Added Enigma game
This commit is contained in:
103
project/jni/application/enigma/src/DOMErrorReporter.cpp
Normal file
103
project/jni/application/enigma/src/DOMErrorReporter.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "DOMErrorReporter.hh"
|
||||
#include "main.hh"
|
||||
#include "XMLtoLocal.hh"
|
||||
#include <iostream>
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/XercesDefs.hpp>
|
||||
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
DOMErrorReporter::DOMErrorReporter(std::ostream *aLogStream) :
|
||||
sawErrors(false), severity(DOMError::DOM_SEVERITY_WARNING),
|
||||
logStream(aLogStream), reportStream(aLogStream) {
|
||||
}
|
||||
|
||||
DOMErrorReporter::~DOMErrorReporter() {
|
||||
}
|
||||
|
||||
// DOMCountHandlers: Overrides of the DOM ErrorHandler interface
|
||||
bool DOMErrorReporter::handleError(const DOMError& domError) {
|
||||
sawErrors = true;
|
||||
if (domError.getSeverity() == DOMError::DOM_SEVERITY_WARNING) {
|
||||
if(reportStream) {*reportStream << "\nWarning ";}
|
||||
}
|
||||
else if (domError.getSeverity() == DOMError::DOM_SEVERITY_ERROR) {
|
||||
if(reportStream) {*reportStream << "\nError ";}
|
||||
if (severity == DOMError::DOM_SEVERITY_WARNING)
|
||||
severity = DOMError::DOM_SEVERITY_ERROR;
|
||||
}
|
||||
else {
|
||||
if(reportStream) {*reportStream << "\nFatal Error ";}
|
||||
severity = DOMError::DOM_SEVERITY_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if(reportStream) {
|
||||
const XMLCh * const fileURI = domError.getLocation()->getURI();
|
||||
if( fileURI && (XMLString::stringLen(fileURI) > 0)) {
|
||||
*reportStream << "at file "
|
||||
<< XMLtoLocal(fileURI)
|
||||
<< ", line " << domError.getLocation()->getLineNumber()
|
||||
<< ", char " << domError.getLocation()->getColumnNumber();
|
||||
}
|
||||
*reportStream << "\n Message: " << XMLtoLocal(domError.getMessage())
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// try to continue
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DOMErrorReporter::getSawErrors() const {
|
||||
return sawErrors;
|
||||
}
|
||||
|
||||
DOMError::ErrorSeverity DOMErrorReporter::getSeverity() const {
|
||||
return severity;
|
||||
}
|
||||
|
||||
void DOMErrorReporter::resetErrors() {
|
||||
sawErrors = false;
|
||||
severity = DOMError::DOM_SEVERITY_WARNING;
|
||||
}
|
||||
|
||||
void DOMErrorReporter::reportToLog() {
|
||||
reportStream = logStream;
|
||||
}
|
||||
|
||||
void DOMErrorReporter::reportToErr() {
|
||||
reportStream = &std::cerr;
|
||||
}
|
||||
|
||||
void DOMErrorReporter::reportToNull() {
|
||||
reportStream = NULL;
|
||||
}
|
||||
|
||||
void DOMErrorReporter::reportToOstream(std::ostream *anOstream) {
|
||||
reportStream = anOstream;
|
||||
}
|
||||
|
||||
} // namespace enigma
|
||||
|
||||
114
project/jni/application/enigma/src/DOMErrorReporter.hh
Normal file
114
project/jni/application/enigma/src/DOMErrorReporter.hh
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ENIGMA_DOMERRORREPORTER_HH
|
||||
#define ENIGMA_DOMERRORREPORTER_HH
|
||||
|
||||
#include <ostream>
|
||||
#include <xercesc/dom/DOMErrorHandler.hpp>
|
||||
#include <xercesc/dom/DOMError.hpp>
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* Error handler for DOM parser and serializer. It reports the error
|
||||
* messages according to there severity as a log note or an alert panel
|
||||
*/
|
||||
class DOMErrorReporter : public XERCES_CPP_NAMESPACE_QUALIFIER DOMErrorHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Main constructor.
|
||||
* @param aLogStream the stream for error reports
|
||||
*/
|
||||
DOMErrorReporter(std::ostream *aLogStream);
|
||||
~DOMErrorReporter();
|
||||
|
||||
/**
|
||||
* Implements the DOM ErrorHandler interface. The error is reported
|
||||
* and the maximum error typ is stored for polling evalutaion.
|
||||
* @param domError the error description
|
||||
* @return true to continue parse or serialization
|
||||
*/
|
||||
bool handleError(const XERCES_CPP_NAMESPACE_QUALIFIER DOMError& domError);
|
||||
|
||||
/**
|
||||
* Returns true if error or warning occured since last reset
|
||||
*/
|
||||
bool getSawErrors() const;
|
||||
|
||||
/**
|
||||
* Returns maximum severity of error since last reset
|
||||
*/
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMError::ErrorSeverity getSeverity() const;
|
||||
|
||||
/**
|
||||
* Resets error flag and severity
|
||||
*/
|
||||
void resetErrors();
|
||||
|
||||
/**
|
||||
* Switch on report output to log stream
|
||||
*/
|
||||
void reportToLog();
|
||||
|
||||
/**
|
||||
* Switch on report output to err stream
|
||||
*/
|
||||
void reportToErr();
|
||||
|
||||
/**
|
||||
* Switch off report output
|
||||
*/
|
||||
void reportToNull();
|
||||
|
||||
/**
|
||||
* Switch on report output to given stream
|
||||
*/
|
||||
void reportToOstream(std::ostream *anOstream);
|
||||
|
||||
private :
|
||||
// Unimplemented constructors and operators
|
||||
DOMErrorReporter(const DOMErrorReporter&);
|
||||
void operator=(const DOMErrorReporter&);
|
||||
|
||||
/**
|
||||
* Flag for warnings or errors that occured since last reset
|
||||
*/
|
||||
bool sawErrors;
|
||||
|
||||
/**
|
||||
* Most significant error type since last reset
|
||||
*/
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMError::ErrorSeverity severity;
|
||||
|
||||
/**
|
||||
* Current output stream for error reports
|
||||
*/
|
||||
std::ostream *reportStream;
|
||||
|
||||
/**
|
||||
* The configured log output stream
|
||||
*/
|
||||
std::ostream *logStream;
|
||||
};
|
||||
|
||||
} // namespace enigma
|
||||
#endif
|
||||
|
||||
127
project/jni/application/enigma/src/DOMSchemaResolver.cpp
Normal file
127
project/jni/application/enigma/src/DOMSchemaResolver.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "DOMSchemaResolver.hh"
|
||||
#include "main.hh"
|
||||
#include "file.hh"
|
||||
#include "XMLtoLocal.hh"
|
||||
#include "LocalToXML.hh"
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#if _XERCES_VERSION >= 30000
|
||||
#include <xercesc/framework/Wrapper4InputSource.hpp>
|
||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||
|
||||
#else
|
||||
#include <xercesc/framework/Wrapper4InputSource.hpp>
|
||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
DOMSchemaResolver::DOMSchemaResolver():resolveStatus(false) {
|
||||
}
|
||||
|
||||
DOMSchemaResolver::~DOMSchemaResolver() {
|
||||
}
|
||||
|
||||
void DOMSchemaResolver::resetResolver() {
|
||||
substitutions.clear();
|
||||
resolveStatus = false;
|
||||
}
|
||||
|
||||
bool DOMSchemaResolver::didResolveSchema() {
|
||||
return resolveStatus;
|
||||
}
|
||||
|
||||
void DOMSchemaResolver::resetResolveStatus() {
|
||||
resolveStatus = false;
|
||||
}
|
||||
|
||||
void DOMSchemaResolver::addSchemaId(const std::string &schemaSystemId,
|
||||
const std::string &schemaFilename) {
|
||||
substitutions.insert(std::make_pair(schemaSystemId, schemaFilename));
|
||||
}
|
||||
|
||||
#if _XERCES_VERSION >= 30000
|
||||
DOMLSInput * DOMSchemaResolver::resolveResource (
|
||||
const XMLCh* const resourceType, const XMLCh* const namespaceUri,
|
||||
const XMLCh *const publicId, const XMLCh *const systemId,
|
||||
const XMLCh *const baseURI) {
|
||||
|
||||
std::string schemaName = XMLtoLocal(systemId).c_str();
|
||||
std::map<std::string, std::string>::iterator i = substitutions.find(schemaName);
|
||||
if (i == substitutions.end()) {
|
||||
Log << "DOMSchemaResolver: no schema substitution found for '"
|
||||
<< schemaName << "'\n";
|
||||
// let the parser try to resolve potential external entities
|
||||
return NULL;
|
||||
} else {
|
||||
std::string schemaPath;
|
||||
bool result = app.systemFS->findFile( std::string("schemas/") +
|
||||
i->second , schemaPath);
|
||||
if (result) {
|
||||
DOMLSInput * inSrc = new Wrapper4InputSource(new LocalFileInputSource(
|
||||
LocalToXML(&schemaPath).x_str()));
|
||||
// W3C implementation:
|
||||
// DOMLSInput * inSrc = app.domImplementationLS->createLSInput();
|
||||
// inSrc->setSystemId(LocalToXML(&schemaPath).x_str()));
|
||||
return inSrc;
|
||||
} else {
|
||||
Log << "DOMSchemaResolver: schema file '"
|
||||
<< i->second << "' not found\n";
|
||||
// let the parser try to resolve the schema
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
DOMInputSource * DOMSchemaResolver::resolveEntity (
|
||||
const XMLCh *const publicId, const XMLCh *const systemId,
|
||||
const XMLCh *const baseURI) {
|
||||
|
||||
std::string schemaName = XMLtoLocal(systemId).c_str();
|
||||
std::map<std::string, std::string>::iterator i = substitutions.find(schemaName);
|
||||
if (i == substitutions.end()) {
|
||||
Log << "DOMSchemaResolver: no schema substitution found for '"
|
||||
<< schemaName << "'\n";
|
||||
// let the parser try to resolve potential external entities
|
||||
return NULL;
|
||||
} else {
|
||||
std::string schemaPath;
|
||||
bool result = app.systemFS->findFile( std::string("schemas/") +
|
||||
i->second , schemaPath);
|
||||
if (result) {
|
||||
DOMInputSource * inSrc = new Wrapper4InputSource(new LocalFileInputSource(
|
||||
LocalToXML(&schemaPath).x_str()));
|
||||
return inSrc;
|
||||
} else {
|
||||
Log << "DOMSchemaResolver: schema file '"
|
||||
<< i->second << "' not found\n";
|
||||
// let the parser try to resolve the schema
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // namespace enigma
|
||||
|
||||
91
project/jni/application/enigma/src/DOMSchemaResolver.hh
Normal file
91
project/jni/application/enigma/src/DOMSchemaResolver.hh
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ENIGMA_DOMSCHEMARESOLVER_HH
|
||||
#define ENIGMA_DOMSCHEMARESOLVER_HH
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <xercesc/util/XercesVersion.hpp>
|
||||
#if _XERCES_VERSION >= 30000
|
||||
#include <xercesc/dom/DOMLSParser.hpp>
|
||||
#include <xercesc/dom/DOMLSResourceResolver.hpp>
|
||||
#include <xercesc/dom/DOMLSInput.hpp>
|
||||
#else
|
||||
#include <xercesc/dom/DOMBuilder.hpp>
|
||||
#include <xercesc/dom/DOMEntityResolver.hpp>
|
||||
#include <xercesc/dom/DOMInputSource.hpp>
|
||||
#endif
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* An XML schema system id to local schema storage path resolver.
|
||||
* The resolver can be configured with several pairs of system id and
|
||||
* paths. This should allow usage of versioned schema system ids like
|
||||
* http://enigma/1.0/levels.xsd . All entities without local substitution
|
||||
* are resolved by the parser using the given system id. A flag allows to
|
||||
* check if the XML file did adhere to a given schema.
|
||||
*/
|
||||
#if _XERCES_VERSION >= 30000
|
||||
class DOMSchemaResolver : public XERCES_CPP_NAMESPACE_QUALIFIER DOMLSResourceResolver {
|
||||
public:
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMLSInput * resolveResource (
|
||||
const XMLCh* const resourceType, const XMLCh* const namespaceUri,
|
||||
const XMLCh *const publicId, const XMLCh *const systemId,
|
||||
const XMLCh *const baseURI);
|
||||
#else
|
||||
class DOMSchemaResolver : public XERCES_CPP_NAMESPACE_QUALIFIER DOMEntityResolver {
|
||||
public:
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMInputSource * resolveEntity (
|
||||
const XMLCh *const publicId, const XMLCh *const systemId,
|
||||
const XMLCh *const baseURI);
|
||||
#endif
|
||||
DOMSchemaResolver();
|
||||
~DOMSchemaResolver();
|
||||
|
||||
/**
|
||||
* clear system id substitution paths and reset result flag.
|
||||
*/
|
||||
void resetResolver();
|
||||
|
||||
/**
|
||||
* add a system id substituion path.
|
||||
* @param schemaSystemId as used in XML files
|
||||
* @param schemaFilename the local substitution filename of the schema.
|
||||
* Just the filename without any path components.
|
||||
*/
|
||||
void addSchemaId(const std::string &schemaSystemId, const std::string &schemaFilename);
|
||||
|
||||
/**
|
||||
* true if at least one local substitution occured since last reset.
|
||||
*/
|
||||
bool didResolveSchema();
|
||||
|
||||
/**
|
||||
* just reset status without deletion of substitution info.
|
||||
*/
|
||||
void resetResolveStatus();
|
||||
private:
|
||||
std::map<std::string, std::string> substitutions;
|
||||
bool resolveStatus;
|
||||
};
|
||||
} // namespace enigma
|
||||
#endif
|
||||
|
||||
169
project/jni/application/enigma/src/Inventory.cpp
Normal file
169
project/jni/application/enigma/src/Inventory.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "Inventory.hh"
|
||||
#include "items.hh"
|
||||
#include "ecl_util.hh"
|
||||
#include <algorithm>
|
||||
|
||||
using enigma::Inventory;
|
||||
using world::Item;
|
||||
|
||||
typedef std::vector<Item*> ItemList;
|
||||
|
||||
/** The maximum number of items that may be stored in an inventory.
|
||||
For compatibility with Oxyd this should be always 12. */
|
||||
unsigned const Inventory::max_items = 12;
|
||||
|
||||
|
||||
Inventory::Inventory() : m_items()
|
||||
{}
|
||||
|
||||
|
||||
Inventory::~Inventory()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
size_t Inventory::size() const
|
||||
{
|
||||
return m_items.size();
|
||||
}
|
||||
|
||||
|
||||
void Inventory::clear()
|
||||
{
|
||||
ecl::delete_sequence(m_items.begin(), m_items.end());
|
||||
m_items.clear();
|
||||
}
|
||||
|
||||
|
||||
Item * Inventory::get_item (size_t idx) const
|
||||
{
|
||||
return idx >= size() ? 0 : m_items[idx];
|
||||
}
|
||||
|
||||
|
||||
Item * Inventory::yield_item (size_t idx)
|
||||
{
|
||||
if (idx < size()) {
|
||||
Item *it = m_items[idx];
|
||||
m_items.erase(m_items.begin()+ idx);
|
||||
return it;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Item * Inventory::yield_first()
|
||||
{
|
||||
return yield_item(0);
|
||||
}
|
||||
|
||||
|
||||
Item * Inventory::remove_item(Item *wanted)
|
||||
{
|
||||
ItemList::iterator e = m_items.end();
|
||||
for (ItemList::iterator i = m_items.begin(); i != e; ++i) {
|
||||
if (*i == wanted) {
|
||||
m_items.erase(i);
|
||||
return wanted;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Inventory::is_full() const
|
||||
{
|
||||
ItemHolder *holder = dynamic_cast<ItemHolder*>(get_item(0));
|
||||
if (holder && !holder->is_full())
|
||||
return false;
|
||||
return m_items.size() >= max_items;
|
||||
}
|
||||
|
||||
bool Inventory::is_empty() const {
|
||||
return m_items.size() == 0;
|
||||
}
|
||||
|
||||
void Inventory::add_item(Item *i)
|
||||
{
|
||||
ItemHolder *firstHolder = dynamic_cast<ItemHolder*>(get_item(0));
|
||||
ItemHolder *addHolder = dynamic_cast<ItemHolder*>(i);
|
||||
if (firstHolder && !firstHolder->is_full() &&
|
||||
(addHolder == NULL || !addHolder->is_empty())) {
|
||||
// first item is a bag and not full and add item is not an empty bag
|
||||
firstHolder->add_item (i);
|
||||
}
|
||||
else {
|
||||
m_items.insert (m_items.begin(), i);
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::takeItemsFrom(ItemHolder *ih) {
|
||||
ItemHolder *holder = dynamic_cast<ItemHolder*>(get_item(0));
|
||||
if (holder && !holder->is_full()) {
|
||||
// first item is a bag and not full - do not refill items form one
|
||||
// itemholder into another
|
||||
return;
|
||||
}
|
||||
else {
|
||||
while (m_items.size() < max_items && !ih->is_empty()) {
|
||||
Item * it = ih->yield_first();
|
||||
m_items.insert (m_items.begin(), it);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::rotate_left ()
|
||||
{
|
||||
if (!m_items.empty())
|
||||
std::rotate(m_items.begin(), m_items.begin()+1, m_items.end());
|
||||
}
|
||||
|
||||
|
||||
void Inventory::rotate_right ()
|
||||
{
|
||||
if (!m_items.empty())
|
||||
std::rotate(m_items.begin(), m_items.end()-1, m_items.end());
|
||||
}
|
||||
|
||||
bool Inventory::willAddItem(Item *it) {
|
||||
ItemHolder *holder = dynamic_cast<ItemHolder*>(it);
|
||||
if (is_full()) {
|
||||
return false;
|
||||
} else if (holder != NULL && holder->is_empty() &&
|
||||
(m_items.size() >= max_items || dynamic_cast<ItemHolder*>(get_item(0)) != NULL)) {
|
||||
// should add a bag that is empty, but first item in Inventory is itself
|
||||
// a bag or Inventory is full -- avoid recursive bags
|
||||
return false;
|
||||
}
|
||||
return true; // we have space and item is not critical
|
||||
}
|
||||
|
||||
|
||||
int Inventory::find(const std::string& kind, size_t start_idx) const
|
||||
{
|
||||
size_t size_ = size();
|
||||
for (size_t i = start_idx; i<size_; ++i) {
|
||||
if (get_item(i)->is_kind(kind))
|
||||
return static_cast<int> (i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
67
project/jni/application/enigma/src/Inventory.hh
Normal file
67
project/jni/application/enigma/src/Inventory.hh
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef INVENTORY_HH_INCLUDED
|
||||
#define INVENTORY_HH_INCLUDED
|
||||
|
||||
#include "ItemHolder.hh"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
using world::Item; // TODO: remove this after moving Item into enigma namespace
|
||||
|
||||
class Inventory : public ItemHolder {
|
||||
public:
|
||||
Inventory();
|
||||
~Inventory();
|
||||
|
||||
// ---------- ItemHolder interface ----------
|
||||
bool is_full() const;
|
||||
virtual bool is_empty() const;
|
||||
void add_item (Item *i);
|
||||
virtual void takeItemsFrom(ItemHolder *ih);
|
||||
virtual Item *yield_first();
|
||||
|
||||
// ---------- Methods ----------
|
||||
|
||||
//! The number of items currently in the inventory
|
||||
size_t size() const;
|
||||
void clear();
|
||||
|
||||
void rotate_left();
|
||||
void rotate_right();
|
||||
Item *get_item (size_t idx) const;
|
||||
Item *yield_item (size_t idx);
|
||||
bool willAddItem(Item *it);
|
||||
|
||||
int find(const std::string& kind, size_t start_idx = 0) const;
|
||||
|
||||
private:
|
||||
// Private methods.
|
||||
Item *remove_item(Item *it);
|
||||
|
||||
// Private variables.
|
||||
static const unsigned max_items;
|
||||
std::vector<Item*> m_items;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
29
project/jni/application/enigma/src/ItemHolder.hh
Normal file
29
project/jni/application/enigma/src/ItemHolder.hh
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef ITEMHOLDER_HH_INCLUDED
|
||||
#define ITEMHOLDER_HH_INCLUDED
|
||||
|
||||
#include "items.hh"
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* A base class for all entities that can hold multiple items
|
||||
* during the game. Currently this is only the inventory that is
|
||||
* displayed at the bottom of the screen (there is one inventory
|
||||
* for every player) and the it-bag item.
|
||||
*/
|
||||
class ItemHolder {
|
||||
public:
|
||||
virtual ~ItemHolder() {}
|
||||
|
||||
//! Return true if not further object can be picked up
|
||||
virtual bool is_full() const = 0;
|
||||
virtual bool is_empty() const = 0;
|
||||
|
||||
//! Add another item
|
||||
virtual void add_item (world::Item *it) = 0;
|
||||
virtual world::Item *yield_first() = 0;
|
||||
virtual void takeItemsFrom(ItemHolder *ih) {return;}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
47
project/jni/application/enigma/src/LocalToXML.cpp
Normal file
47
project/jni/application/enigma/src/LocalToXML.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "LocalToXML.hh"
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
LocalToXML::LocalToXML(const char * const toTranscode) {
|
||||
// Use XML for transcoding -- the returned string is owned by us
|
||||
// but managed by XMLString!
|
||||
xmlString = XMLString::transcode(toTranscode);
|
||||
}
|
||||
|
||||
LocalToXML::LocalToXML(const std::string * const toTranscode) {
|
||||
// Use XML for transcoding -- the returned string is owned by us
|
||||
// but managed by XMLString!
|
||||
xmlString = XMLString::transcode(toTranscode->c_str());
|
||||
}
|
||||
|
||||
LocalToXML::~LocalToXML() {
|
||||
XMLString::release(&xmlString);
|
||||
}
|
||||
|
||||
const XMLCh * LocalToXML::x_str() const {
|
||||
return xmlString;
|
||||
}
|
||||
|
||||
} //namespace enigma
|
||||
|
||||
72
project/jni/application/enigma/src/LocalToXML.hh
Normal file
72
project/jni/application/enigma/src/LocalToXML.hh
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ENIGMA_LOCALTOXML_HH
|
||||
#define ENIGMA_LOCALTOXML_HH
|
||||
|
||||
#include <iostream>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* Transcoding utility for local code page strings to XMLCh strings.
|
||||
* Provides a simple interface for the memory management paradigm shift
|
||||
* even though not terribly efficient. Make sure all LocalToXML objects
|
||||
* exist only temporarily, f.e.
|
||||
* <code>DOMNode::setNodeValue(LocalToXML(char *toTranscode).x_str())</code> or
|
||||
* <code>XMLString::replicate(LocalToXML(char *toTranscode).x_str())</code>
|
||||
* Xerces should be initialized before using this class and all objects
|
||||
* should be deleted before terminating.
|
||||
*/
|
||||
class LocalToXML {
|
||||
public :
|
||||
/**
|
||||
* Makes a transcoding to XML.
|
||||
*
|
||||
* @param toTranscode local code page string
|
||||
*/
|
||||
LocalToXML(const char * const toTranscode);
|
||||
|
||||
/**
|
||||
* Makes a transcoding to XML.
|
||||
*
|
||||
* @param toTranscode local code page string
|
||||
*/
|
||||
LocalToXML(const std::string * const toTranscode);
|
||||
~LocalToXML();
|
||||
|
||||
/**
|
||||
* Returns the string coded in the local page. It remains owner of
|
||||
* the string.
|
||||
*/
|
||||
const XMLCh * x_str() const;
|
||||
|
||||
private :
|
||||
/**
|
||||
* A XML copy. We are the owner.
|
||||
*/
|
||||
XMLCh * xmlString;
|
||||
void init(const char * const toTranscode);
|
||||
};
|
||||
|
||||
} //namespace enigma
|
||||
#endif
|
||||
|
||||
197
project/jni/application/enigma/src/PreferenceManager.cpp
Normal file
197
project/jni/application/enigma/src/PreferenceManager.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PreferenceManager.hh"
|
||||
#include "main.hh"
|
||||
#include "DOMErrorReporter.hh"
|
||||
#include "DOMSchemaResolver.hh"
|
||||
#include "LocalToXML.hh"
|
||||
#include "nls.hh"
|
||||
#include "Utf8ToXML.hh"
|
||||
#include "utilXML.hh"
|
||||
#include "options.hh"
|
||||
#include "XMLtoLocal.hh"
|
||||
#include "XMLtoUtf8.hh"
|
||||
#include "ecl_system.hh"
|
||||
#include "gui/ErrorMenu.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/util/XMLDouble.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/XMLUniDefs.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
#include <xercesc/util/XercesVersion.hpp>
|
||||
#if _XERCES_VERSION < 30000
|
||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace enigma;
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma {
|
||||
PreferenceManager *PreferenceManager::theSingleton = 0;
|
||||
|
||||
PreferenceManager* PreferenceManager::instance() {
|
||||
if (theSingleton == 0) {
|
||||
theSingleton = new PreferenceManager();
|
||||
}
|
||||
return theSingleton;
|
||||
}
|
||||
|
||||
PreferenceManager::PreferenceManager() {
|
||||
std::string prefTemplatePath;
|
||||
bool haveXMLProperties = (ecl::FileExists(app.prefPath)) ? true : false;
|
||||
|
||||
if (!app.systemFS->findFile( std::string("schemas/") + PREFFILENAME , prefTemplatePath)) {
|
||||
cerr << "Preferences: no template found\n";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
try {
|
||||
app.domParserErrorHandler->resetErrors();
|
||||
app.domParserErrorHandler->reportToErr();
|
||||
app.domParserSchemaResolver->resetResolver();
|
||||
app.domParserSchemaResolver->addSchemaId("preferences.xsd","preferences.xsd");
|
||||
|
||||
if (haveXMLProperties) {
|
||||
// update existing XML prefs from possibly newer template:
|
||||
// use user prefs and copy new properties from template
|
||||
doc = app.domParser->parseURI(app.prefPath.c_str());
|
||||
propertiesElem = dynamic_cast<DOMElement *>(doc->getElementsByTagName(
|
||||
Utf8ToXML("properties").x_str())->item(0));
|
||||
// The following algorithm is not optimized - O(n^2)!
|
||||
DOMDocument * prefTemplate = app.domParser->parseURI(prefTemplatePath.c_str());
|
||||
DOMNodeList * tmplPropList = prefTemplate->getElementsByTagName(
|
||||
Utf8ToXML("property").x_str());
|
||||
for (int i = 0, l = tmplPropList-> getLength(); i < l; i++) {
|
||||
DOMElement *tmplProperty = dynamic_cast<DOMElement *>(tmplPropList->item(i));
|
||||
const XMLCh * key = tmplProperty->getAttribute(Utf8ToXML("key").x_str());
|
||||
DOMElement * lastUserProperty;
|
||||
if ((key[0] != chUnderscore) && !hasProperty(key, &lastUserProperty)) {
|
||||
// a new property in the template
|
||||
Log << "Preferences: add new Property \"" << XMLtoLocal(key) << "\"\n";
|
||||
// make a copy
|
||||
DOMNode * newProperty = doc->importNode(tmplProperty, false);
|
||||
if (newProperty == NULL) {
|
||||
Log << "Preferences: copy new Property failed!\n";
|
||||
} else {
|
||||
// insert it at the end of the existing user properties
|
||||
propertiesElem->appendChild(dynamic_cast<DOMElement *>(newProperty));
|
||||
}
|
||||
}
|
||||
}
|
||||
prefTemplate->release();
|
||||
} else {
|
||||
// update from LUA options to XML preferences:
|
||||
// use the template, copy LUA option values and save it later as prefs
|
||||
doc = app.domParser->parseURI(prefTemplatePath.c_str());
|
||||
propertiesElem = dynamic_cast<DOMElement *>(doc->getElementsByTagName(
|
||||
Utf8ToXML("properties").x_str())->item(0));
|
||||
DOMNodeList * propList = propertiesElem->getElementsByTagName(Utf8ToXML("property").x_str());
|
||||
for (int i = 0, l = propList-> getLength(); i < l; i++) {
|
||||
DOMElement * property = dynamic_cast<DOMElement *>(propList->item(i));
|
||||
const XMLCh * key = property->getAttribute(Utf8ToXML("key").x_str());
|
||||
std::string optionValue;
|
||||
if (options::HasOption(XMLtoLocal(key).c_str(), optionValue)) {
|
||||
Log << "Preferences: copy LUA option \"" << XMLtoLocal(key) << "\"\n";
|
||||
property->setAttribute(Utf8ToXML("value").x_str(),
|
||||
LocalToXML(&optionValue).x_str());
|
||||
} else {
|
||||
Log << "Preferences: no LUA option \"" << XMLtoLocal(key) << "\"\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const XMLException& toCatch) {
|
||||
char* message = XMLString::transcode(toCatch.getMessage());
|
||||
cerr << "Exception on load of preferences: "
|
||||
<< message << "\n";
|
||||
XMLString::release(&message);
|
||||
exit (-1);
|
||||
}
|
||||
catch (const DOMException& toCatch) {
|
||||
char* message = XMLString::transcode(toCatch.msg);
|
||||
cerr << "Exception on load of preferences: "
|
||||
<< message << "\n";
|
||||
XMLString::release(&message);
|
||||
exit (-1);
|
||||
}
|
||||
catch (...) {
|
||||
cerr << "Unexpected Exception on load of preferences\n" ;
|
||||
exit (-1);
|
||||
}
|
||||
}
|
||||
|
||||
PreferenceManager::~PreferenceManager() {
|
||||
if (doc != NULL)
|
||||
shutdown();
|
||||
}
|
||||
|
||||
bool PreferenceManager::save() {
|
||||
bool result = true;
|
||||
std::string errMessage;
|
||||
|
||||
if (doc == NULL)
|
||||
return true;
|
||||
|
||||
stripIgnorableWhitespace(doc->getDocumentElement());
|
||||
|
||||
try {
|
||||
#if _XERCES_VERSION >= 30000
|
||||
result = app.domSer->writeToURI(doc, LocalToXML(& app.prefPath).x_str());
|
||||
#else
|
||||
XMLFormatTarget *myFormTarget = new LocalFileFormatTarget(app.prefPath.c_str());
|
||||
result = app.domSer->writeNode(myFormTarget, *doc);
|
||||
delete myFormTarget; // flush
|
||||
#endif
|
||||
} catch (const XMLException& toCatch) {
|
||||
errMessage = std::string("Exception on save of preferences: \n") +
|
||||
XMLtoUtf8(toCatch.getMessage()).c_str() + "\n";
|
||||
result = false;
|
||||
} catch (const DOMException& toCatch) {
|
||||
errMessage = std::string("Exception on save of preferences: \n") +
|
||||
XMLtoUtf8(toCatch.getMessage()).c_str() + "\n";
|
||||
result = false;
|
||||
} catch (...) {
|
||||
errMessage = "Unexpected exception on save of preferences\n" ;
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
cerr << errMessage;
|
||||
gui::ErrorMenu m(errMessage, N_("Continue"));
|
||||
m.manage();
|
||||
} else
|
||||
Log << "Preferences save o.k.\n";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PreferenceManager::shutdown() {
|
||||
save();
|
||||
if (doc != NULL)
|
||||
doc->release();
|
||||
doc = NULL;
|
||||
}
|
||||
|
||||
} // namespace enigma
|
||||
|
||||
55
project/jni/application/enigma/src/PreferenceManager.hh
Normal file
55
project/jni/application/enigma/src/PreferenceManager.hh
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef PREFMGR_HH_INCLUDED
|
||||
#define PREFMGR_HH_INCLUDED
|
||||
|
||||
#include "PropertyManager.hh"
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* A singelton manager for preferences stored in XML format.
|
||||
* <p>The singleton can be accessed via standard static instance() method or
|
||||
* the application public ivar <code>app.prefs</code>.</p>
|
||||
* <p> During initialization old LUA stored options are convereted. New
|
||||
* preferences with given default values are introduced to the user via the
|
||||
* template in the systen data directory (data/enigmarc.xml).</p>
|
||||
* <p>The storage location of the users preferences is determined by the
|
||||
* Application object.</p>
|
||||
* <p>The set and get methods for preferences take utf8 encoded preference
|
||||
* names and operate with utf8 encoded string values. Set methods create new
|
||||
* preference property elements if necessary. Get methods do not modify
|
||||
* reference values and return C++ default values if the named preference
|
||||
* does not exist.</p>
|
||||
*/
|
||||
class PreferenceManager : public PropertyManager {
|
||||
public:
|
||||
static PreferenceManager *instance();
|
||||
~PreferenceManager();
|
||||
virtual bool save();
|
||||
void shutdown();
|
||||
|
||||
protected:
|
||||
PreferenceManager();
|
||||
private:
|
||||
static PreferenceManager *theSingleton;
|
||||
};
|
||||
} // namespace enigma
|
||||
#endif
|
||||
|
||||
186
project/jni/application/enigma/src/PropertyManager.cpp
Normal file
186
project/jni/application/enigma/src/PropertyManager.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PropertyManager.hh"
|
||||
#include "errors.hh"
|
||||
#include "main.hh"
|
||||
#include "DOMErrorReporter.hh"
|
||||
#include "DOMSchemaResolver.hh"
|
||||
#include "LocalToXML.hh"
|
||||
#include "Utf8ToXML.hh"
|
||||
#include "options.hh"
|
||||
#include "XMLtoLocal.hh"
|
||||
#include "XMLtoUtf8.hh"
|
||||
#include "ecl_system.hh"
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/util/XMLDouble.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/XMLUniDefs.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
#include <xercesc/util/XercesVersion.hpp>
|
||||
#if _XERCES_VERSION < 30000
|
||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace enigma;
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma {
|
||||
PropertyManager::PropertyManager() : doc (NULL), propertiesElem (NULL) {
|
||||
}
|
||||
|
||||
PropertyManager::~PropertyManager() {
|
||||
}
|
||||
|
||||
void PropertyManager::setProperty(const char *prefName, const std::string &value) {
|
||||
DOMElement * property = getPropertyElement(prefName);
|
||||
|
||||
property->setAttribute(Utf8ToXML("value").x_str(),
|
||||
Utf8ToXML(&value).x_str());
|
||||
}
|
||||
|
||||
void PropertyManager::setProperty(const char *prefName, const char *value) {
|
||||
setProperty(prefName, std::string(value));
|
||||
}
|
||||
|
||||
void PropertyManager::getProperty(const char *prefName, std::string &value) {
|
||||
DOMElement * property;
|
||||
bool propFound = hasProperty(prefName, &property);
|
||||
if (propFound) {
|
||||
value = XMLtoUtf8(property->getAttribute(Utf8ToXML("value").x_str())).c_str();
|
||||
}
|
||||
}
|
||||
|
||||
std::string PropertyManager::getString(const char *prefName) {
|
||||
std::string value;
|
||||
getProperty(prefName, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void PropertyManager::setProperty(const char *prefName, const double &value) {
|
||||
char printedValue[20];
|
||||
sprintf(printedValue, "%.7g", value);
|
||||
DOMElement * property = getPropertyElement(prefName);
|
||||
property->setAttribute(Utf8ToXML("value").x_str(),
|
||||
Utf8ToXML(printedValue).x_str());
|
||||
}
|
||||
|
||||
void PropertyManager::getProperty(const char *prefName, double &value) {
|
||||
DOMElement * property;
|
||||
bool propFound = hasProperty(prefName, &property);
|
||||
if (propFound) {
|
||||
XMLDouble * result = new XMLDouble(property->getAttribute(Utf8ToXML("value").x_str()));
|
||||
value = result->getValue();
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
|
||||
double PropertyManager::getDouble(const char *prefName) {
|
||||
double value = 0;
|
||||
getProperty (prefName, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void PropertyManager::setProperty(const char *prefName, const int &value) {
|
||||
char printedValue[20];
|
||||
sprintf(printedValue, "%d", value);
|
||||
DOMElement * property = getPropertyElement(prefName);
|
||||
|
||||
property->setAttribute(Utf8ToXML("value").x_str(),
|
||||
Utf8ToXML(printedValue).x_str());
|
||||
}
|
||||
|
||||
void PropertyManager::getProperty(const char *prefName, int &value) {
|
||||
DOMElement * property;
|
||||
bool propFound = hasProperty(prefName, &property);
|
||||
if (propFound) {
|
||||
value = XMLString::parseInt(property->getAttribute(Utf8ToXML("value").x_str()));
|
||||
}
|
||||
}
|
||||
|
||||
int PropertyManager::getInt(const char *prefName) {
|
||||
int value = 0;
|
||||
getProperty (prefName, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void PropertyManager::setProperty(const char *prefName, const bool &value) {
|
||||
int i = (value ? 1: 0);
|
||||
setProperty(prefName, i);
|
||||
}
|
||||
|
||||
void PropertyManager::getProperty(const char *prefName, bool &value) {
|
||||
int result = 0;
|
||||
getProperty(prefName, result);
|
||||
value = ((result == 0) ? false: true);
|
||||
}
|
||||
|
||||
bool PropertyManager::getBool(const char *prefName) {
|
||||
bool value = false;
|
||||
getProperty (prefName, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
DOMElement * PropertyManager::getPropertyElement(const char *prefName) {
|
||||
ASSERT(propertiesElem != NULL, XFrontend, "");
|
||||
ASSERT(doc != NULL, XFrontend, "");
|
||||
XMLCh * key = XMLString::replicate(Utf8ToXML(prefName).x_str());
|
||||
DOMElement * property;
|
||||
bool propFound = hasProperty(prefName, &property);
|
||||
|
||||
if (!propFound) {
|
||||
DOMElement * newProperty = doc->createElement (Utf8ToXML("property").x_str());
|
||||
newProperty->setAttribute(Utf8ToXML("key").x_str(), key);
|
||||
// insert it at the end of the existing properties
|
||||
propertiesElem->appendChild(newProperty);
|
||||
property = newProperty;
|
||||
}
|
||||
XMLString::release(&key);
|
||||
return property;
|
||||
}
|
||||
|
||||
bool PropertyManager::hasProperty(const char *prefName, DOMElement ** element) {
|
||||
return hasProperty(Utf8ToXML(prefName).x_str(), element);
|
||||
}
|
||||
|
||||
bool PropertyManager::hasProperty(const XMLCh * key, DOMElement ** element) {
|
||||
ASSERT(propertiesElem != NULL, XFrontend, "");
|
||||
bool propFound = false;
|
||||
DOMElement * property;
|
||||
|
||||
// Xerces 3.0 has no full XPath support - otherwise the following simple
|
||||
// statement would suffice and not be aborted with NOT_SUPPORTED_ERR.
|
||||
// doc->evaluate(Utf8ToXML("//property[@key='...']").x_str(), doc, NULL, 0, NULL);
|
||||
|
||||
DOMNodeList * propList = propertiesElem->getElementsByTagName(Utf8ToXML("property").x_str());
|
||||
for (int i = 0, l = propList-> getLength(); i < l && !propFound; i++) {
|
||||
property = dynamic_cast<DOMElement *>(propList->item(i));
|
||||
if (XMLString::equals(key,
|
||||
property->getAttribute(Utf8ToXML("key").x_str()))) {
|
||||
propFound = true;
|
||||
}
|
||||
}
|
||||
* element = property;
|
||||
return propFound;
|
||||
}
|
||||
} // namespace enigma
|
||||
81
project/jni/application/enigma/src/PropertyManager.hh
Normal file
81
project/jni/application/enigma/src/PropertyManager.hh
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef PROPERTYMGR_HH_INCLUDED
|
||||
#define PROPERTYMGR_HH_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <xercesc/dom/DOMDocument.hpp>
|
||||
#include <xercesc/dom/DOMElement.hpp>
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* An abstact Superclass for key/value property access.
|
||||
*/
|
||||
class PropertyManager {
|
||||
public:
|
||||
~PropertyManager();
|
||||
virtual bool save() = 0; // mark the class as abstract
|
||||
|
||||
void setProperty(const char *prefName, const std::string &value);
|
||||
void setProperty(const char *prefName, const char *value);
|
||||
void getProperty(const char *prefName, std::string &value);
|
||||
std::string getString(const char *prefName);
|
||||
void setProperty(const char *prefName, const double &value);
|
||||
void getProperty(const char *prefName, double &value);
|
||||
double getDouble(const char *prefName);
|
||||
void setProperty(const char *prefName, const int &value);
|
||||
void getProperty(const char *prefName, int &value);
|
||||
int getInt(const char *prefName);
|
||||
void setProperty(const char *prefName, const bool &value);
|
||||
void getProperty(const char *prefName, bool &value);
|
||||
bool getBool(const char *prefName);
|
||||
|
||||
protected:
|
||||
PropertyManager();
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *propertiesElem;
|
||||
|
||||
/**
|
||||
* force a return of a property element with the given name as key.
|
||||
* @param prefName the name of the searched or new property
|
||||
* @return the property element with the given key name.
|
||||
*/
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement * getPropertyElement(const char *prefName);
|
||||
|
||||
/**
|
||||
* checks if a property exists.
|
||||
* @param prefName the preference name.
|
||||
* @param element the searched property element or the last property
|
||||
* element found in the preference list (for append usage).
|
||||
* @return validity of element.
|
||||
*/
|
||||
bool hasProperty(const char *prefName, XERCES_CPP_NAMESPACE_QUALIFIER DOMElement ** element);
|
||||
/**
|
||||
* checks if a property exists.
|
||||
* @param key the preference name.
|
||||
* @param element the searched property element or the last property
|
||||
* element found in the preference list (for append usage).
|
||||
* @return validity of element.
|
||||
*/
|
||||
bool hasProperty(const XMLCh * key, XERCES_CPP_NAMESPACE_QUALIFIER DOMElement ** element);
|
||||
};
|
||||
} // namespace enigma
|
||||
#endif
|
||||
|
||||
408
project/jni/application/enigma/src/StateManager.cpp
Normal file
408
project/jni/application/enigma/src/StateManager.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StateManager.hh"
|
||||
#include "errors.hh"
|
||||
#include "main.hh"
|
||||
#include "DOMErrorReporter.hh"
|
||||
#include "DOMSchemaResolver.hh"
|
||||
#include "LocalToXML.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "Utf8ToXML.hh"
|
||||
#include "utilXML.hh"
|
||||
#include "XMLtoLocal.hh"
|
||||
#include "XMLtoUtf8.hh"
|
||||
#include "ecl_system.hh"
|
||||
#include "gui/ErrorMenu.hh"
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/util/XMLDouble.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/XMLUniDefs.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
#include <xercesc/util/XercesVersion.hpp>
|
||||
#if _XERCES_VERSION < 30000
|
||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace enigma;
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma {
|
||||
StateManager *StateManager::theSingleton = 0;
|
||||
|
||||
StateManager* StateManager::instance() {
|
||||
if (theSingleton == 0) {
|
||||
theSingleton = new StateManager();
|
||||
}
|
||||
return theSingleton;
|
||||
}
|
||||
|
||||
StateManager::StateManager() {
|
||||
std::string statePath;
|
||||
std::string errMessage;
|
||||
|
||||
if (!app.resourceFS->findFile( "state.xml" , statePath)) {
|
||||
if (!app.systemFS->findFile( "schemas/state.xml" , statePath)) {
|
||||
throw XFrontend("Cannot load application state template!");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
std::ostringstream errStream;
|
||||
app.domParserErrorHandler->resetErrors();
|
||||
app.domParserErrorHandler->reportToOstream(&errStream);
|
||||
app.domParserSchemaResolver->resetResolver();
|
||||
app.domParserSchemaResolver->addSchemaId("state.xsd","state.xsd");
|
||||
|
||||
doc = app.domParser->parseURI(statePath.c_str());
|
||||
if (doc != NULL && !app.domParserErrorHandler->getSawErrors()) {
|
||||
propertiesElem = dynamic_cast<DOMElement *>(doc->getElementsByTagName(
|
||||
Utf8ToXML("properties").x_str())->item(0));
|
||||
groupsElem = dynamic_cast<DOMElement *>(doc->getElementsByTagName(
|
||||
Utf8ToXML("groups").x_str())->item(0));
|
||||
groupList = groupsElem->getElementsByTagName(
|
||||
Utf8ToXML("group").x_str());
|
||||
indicesElem = dynamic_cast<DOMElement *>(doc->getElementsByTagName(
|
||||
Utf8ToXML("indices").x_str())->item(0));
|
||||
indexList = indicesElem->getElementsByTagName(
|
||||
Utf8ToXML("index").x_str());
|
||||
levelsElem = dynamic_cast<DOMElement *>(doc->getElementsByTagName(
|
||||
Utf8ToXML("levels").x_str())->item(0));
|
||||
}
|
||||
if(app.domParserErrorHandler->getSawErrors()) {
|
||||
errMessage = errStream.str();
|
||||
}
|
||||
app.domParserErrorHandler->reportToNull(); // do not report to errStream any more
|
||||
}
|
||||
catch (...) {
|
||||
errMessage = "Unexpected XML Exception on load of state\n";
|
||||
}
|
||||
if (!errMessage.empty()) {
|
||||
throw XFrontend("Cannot load application state file: " + statePath +
|
||||
"\nError: " + errMessage);
|
||||
}
|
||||
}
|
||||
|
||||
StateManager::~StateManager() {
|
||||
if (doc != NULL)
|
||||
shutdown();
|
||||
}
|
||||
|
||||
bool StateManager::save() {
|
||||
bool result = true;
|
||||
std::string errMessage;
|
||||
|
||||
if (doc == NULL)
|
||||
return true;
|
||||
|
||||
int count = getInt("Count");
|
||||
setProperty("Count", ++count);
|
||||
|
||||
stripIgnorableWhitespace(doc->getDocumentElement());
|
||||
std::string path = app.userPath + "/state.xml";
|
||||
std::string pathBackup = app.userPath + "/backup/state.xml";
|
||||
|
||||
// backup state every 10th save
|
||||
if (count%10 == 0) {
|
||||
std::remove((pathBackup + "~2").c_str());
|
||||
std::remove((path + "~2").c_str()); // 1.00 bakups
|
||||
if (ecl::FileExists(path + "~1")) {
|
||||
if (std::difftime(ecl::FileModTime(path + "~1"),
|
||||
ecl::FileModTime(pathBackup + "~1")) > 0) {
|
||||
// backup 1 from 1.00 is newer than backup 1 on backup path
|
||||
if (Copyfile(path + "~1", pathBackup + "~2"))
|
||||
std::remove((path + "~1").c_str()); // 1.00 bakup
|
||||
} else {
|
||||
// just in case off previous copy failure
|
||||
std::rename((pathBackup + "~1").c_str(), (pathBackup + "~2").c_str());
|
||||
std::remove((path + "~1").c_str()); // 1.00 bakup
|
||||
}
|
||||
} else {
|
||||
std::rename((pathBackup + "~1").c_str(), (pathBackup + "~2").c_str());
|
||||
}
|
||||
Copyfile(path, pathBackup + "~1");
|
||||
}
|
||||
|
||||
try {
|
||||
#if _XERCES_VERSION >= 30000
|
||||
result = app.domSer->writeToURI(doc, LocalToXML(& path).x_str());
|
||||
#else
|
||||
XMLFormatTarget *myFormTarget = new LocalFileFormatTarget(path.c_str());
|
||||
result = app.domSer->writeNode(myFormTarget, *doc);
|
||||
delete myFormTarget; // flush
|
||||
#endif
|
||||
} catch (const XMLException& toCatch) {
|
||||
errMessage = std::string("Exception on save of state: \n") +
|
||||
XMLtoUtf8(toCatch.getMessage()).c_str() + "\n";
|
||||
result = false;
|
||||
} catch (const DOMException& toCatch) {
|
||||
errMessage = std::string("Exception on save of state: \n") +
|
||||
XMLtoUtf8(toCatch.getMessage()).c_str() + "\n";
|
||||
result = false;
|
||||
} catch (...) {
|
||||
errMessage = "Unexpected exception on save of state\n" ;
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
if (count%10 == 0) {
|
||||
// restore backup in case of error
|
||||
if (Copyfile(pathBackup + "~1", path)) {
|
||||
std::remove((pathBackup + "~1").c_str());
|
||||
std::rename((pathBackup + "~2").c_str(), (pathBackup + "~1").c_str());
|
||||
}
|
||||
}
|
||||
cerr << XMLtoLocal(Utf8ToXML(errMessage.c_str()).x_str()).c_str();
|
||||
gui::ErrorMenu m(errMessage, N_("Continue"));
|
||||
m.manage();
|
||||
} else
|
||||
Log << "State save o.k.\n";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void StateManager::shutdown() {
|
||||
save();
|
||||
if (doc != NULL)
|
||||
doc->release();
|
||||
doc = NULL;
|
||||
}
|
||||
|
||||
void StateManager::getGroupNames(std::vector<std::string> *names) {
|
||||
for (int i = 0, l = groupList-> getLength(); i < l; i++) {
|
||||
DOMElement * group = dynamic_cast<DOMElement *>(groupList->item(i));
|
||||
names->push_back(XMLtoUtf8(group->getAttribute(Utf8ToXML("title").x_str())).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string StateManager::getGroupSelectedIndex(std::string groupName) {
|
||||
for (int i = 0, l = groupList-> getLength(); i < l; i++) {
|
||||
DOMElement * group = dynamic_cast<DOMElement *>(groupList->item(i));
|
||||
if (groupName == XMLtoUtf8(group->getAttribute(Utf8ToXML("title").x_str())).c_str())
|
||||
return XMLtoUtf8(group->getAttribute(Utf8ToXML("curindex").x_str())).c_str();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string StateManager::getGroupSelectedColumn(std::string groupName) {
|
||||
for (int i = 0, l = groupList-> getLength(); i < l; i++) {
|
||||
DOMElement * group = dynamic_cast<DOMElement *>(groupList->item(i));
|
||||
if (groupName == XMLtoUtf8(group->getAttribute(Utf8ToXML("title").x_str())).c_str())
|
||||
return XMLtoUtf8(group->getAttribute(Utf8ToXML("curcolumn").x_str())).c_str();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StateManager::setGroupSelectedIndex(std::string groupName, std::string indexName) {
|
||||
for (int i = 0, l = groupList-> getLength(); i < l; i++) {
|
||||
DOMElement * group = dynamic_cast<DOMElement *>(groupList->item(i));
|
||||
if (groupName == XMLtoUtf8(group->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
group->setAttribute(Utf8ToXML("curindex").x_str(), Utf8ToXML(indexName).x_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::setGroupSelectedColumn(std::string groupName, std::string column) {
|
||||
for (int i = 0, l = groupList-> getLength(); i < l; i++) {
|
||||
DOMElement * group = dynamic_cast<DOMElement *>(groupList->item(i));
|
||||
if (groupName == XMLtoUtf8(group->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
group->setAttribute(Utf8ToXML("curcolumn").x_str(), Utf8ToXML(column).x_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::addGroup(std::string groupName, std::string indexName, int column) {
|
||||
// check if group exists - update attributes only
|
||||
for (int i = 0, l = groupList->getLength(); i < l; i++) {
|
||||
DOMElement * group = dynamic_cast<DOMElement *>(groupList->item(i));
|
||||
if (groupName == XMLtoUtf8(group->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
group->setAttribute(Utf8ToXML("curcolumn").x_str(),
|
||||
Utf8ToXML(ecl::strf("%d",column)).x_str());
|
||||
group->setAttribute(Utf8ToXML("curindex").x_str(), Utf8ToXML(indexName).x_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if group does not exist add a new element
|
||||
DOMElement * group = doc->createElement (Utf8ToXML("group").x_str());
|
||||
group->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(groupName).x_str());
|
||||
group->setAttribute(Utf8ToXML("curindex").x_str(), Utf8ToXML(indexName).x_str());
|
||||
group->setAttribute(Utf8ToXML("curcolumn").x_str(),
|
||||
Utf8ToXML(ecl::strf("%d",column)).x_str());
|
||||
groupsElem->appendChild(group);
|
||||
}
|
||||
|
||||
void StateManager::insertGroup(int pos, std::string groupName,
|
||||
std::string indexName, std::string column) {
|
||||
DOMElement * group = doc->createElement (Utf8ToXML("group").x_str());
|
||||
group->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(groupName).x_str());
|
||||
group->setAttribute(Utf8ToXML("curindex").x_str(), Utf8ToXML(indexName).x_str());
|
||||
group->setAttribute(Utf8ToXML("curcolumn").x_str(), Utf8ToXML(column).x_str());
|
||||
if (pos < 0 || pos >= groupList->getLength())
|
||||
groupsElem->appendChild(group);
|
||||
else {
|
||||
DOMElement * nextGroup = dynamic_cast<DOMElement *>(groupList->item(pos));
|
||||
groupsElem->insertBefore(group, nextGroup);
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::deleteGroup(std::string groupName) {
|
||||
for (int i = 0, l = groupList->getLength(); i < l; i++) {
|
||||
DOMElement * group = dynamic_cast<DOMElement *>(groupList->item(i));
|
||||
if (groupName == XMLtoUtf8(group->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
groupsElem->removeChild(group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::renameGroup(std::string oldName, std::string newName) {
|
||||
// rename group element
|
||||
for (int i = 0, l = groupList->getLength(); i < l; i++) {
|
||||
DOMElement * group = dynamic_cast<DOMElement *>(groupList->item(i));
|
||||
if (oldName == XMLtoUtf8(group->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
group->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(newName).x_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void StateManager::addIndex(std::string indexName, std::string &groupName,
|
||||
double &location, int &curpos, int &curfirst) {
|
||||
// check if index exists - get user attributes
|
||||
for (int i = 0, l = indexList-> getLength(); i < l; i++) {
|
||||
DOMElement * index = dynamic_cast<DOMElement *>(indexList->item(i));
|
||||
if (indexName == XMLtoUtf8(index->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
groupName = XMLtoUtf8(index->getAttribute(Utf8ToXML("group").x_str())).c_str();
|
||||
XMLDouble * result = new XMLDouble(index->getAttribute(Utf8ToXML("location").x_str()));
|
||||
location = result->getValue();
|
||||
delete result;
|
||||
curpos = XMLString::parseInt(index->getAttribute(Utf8ToXML("curposition").x_str()));
|
||||
curfirst = XMLString::parseInt(index->getAttribute(Utf8ToXML("curfirst").x_str()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if index does not exist add a new element with default values
|
||||
DOMElement * index = doc->createElement (Utf8ToXML("index").x_str());
|
||||
index->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(indexName).x_str());
|
||||
index->setAttribute(Utf8ToXML("group").x_str(), Utf8ToXML(groupName).x_str());
|
||||
index->setAttribute(Utf8ToXML("location").x_str(), Utf8ToXML(ecl::strf("%g",location)).x_str());
|
||||
index->setAttribute(Utf8ToXML("curfirst").x_str(), Utf8ToXML(ecl::strf("%d",0)).x_str());
|
||||
index->setAttribute(Utf8ToXML("curposition").x_str(), Utf8ToXML(ecl::strf("%d",0)).x_str());
|
||||
indicesElem->appendChild(index);
|
||||
}
|
||||
|
||||
void StateManager::setIndexName(std::string oldName, std::string newName) {
|
||||
// search index and set attribute
|
||||
for (int i = 0, l = indexList-> getLength(); i < l; i++) {
|
||||
DOMElement * index = dynamic_cast<DOMElement *>(indexList->item(i));
|
||||
if (oldName == XMLtoUtf8(index->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
index->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(newName).x_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::setIndexLocation(std::string indexName, double location) {
|
||||
// search index and set attribute
|
||||
for (int i = 0, l = indexList-> getLength(); i < l; i++) {
|
||||
DOMElement * index = dynamic_cast<DOMElement *>(indexList->item(i));
|
||||
if (indexName == XMLtoUtf8(index->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
index->setAttribute(Utf8ToXML("location").x_str(), Utf8ToXML(ecl::strf("%.15g",location)).x_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::setIndexCurpos(std::string indexName, int curpos) {
|
||||
// search index and set attribute
|
||||
for (int i = 0, l = indexList-> getLength(); i < l; i++) {
|
||||
DOMElement * index = dynamic_cast<DOMElement *>(indexList->item(i));
|
||||
if (indexName == XMLtoUtf8(index->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
index->setAttribute(Utf8ToXML("curposition").x_str(), Utf8ToXML(ecl::strf("%d",curpos)).x_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::setIndexCurfirst(std::string indexName, int curfirst) {
|
||||
// search index and set attribute
|
||||
for (int i = 0, l = indexList-> getLength(); i < l; i++) {
|
||||
DOMElement * index = dynamic_cast<DOMElement *>(indexList->item(i));
|
||||
if (indexName == XMLtoUtf8(index->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
index->setAttribute(Utf8ToXML("curfirst").x_str(), Utf8ToXML(ecl::strf("%d",curfirst)).x_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StateManager::setIndexGroup(std::string indexName, std::string groupName) {
|
||||
// search index and set attribute
|
||||
for (int i = 0, l = indexList-> getLength(); i < l; i++) {
|
||||
DOMElement * index = dynamic_cast<DOMElement *>(indexList->item(i));
|
||||
if (indexName == XMLtoUtf8(index->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
|
||||
index->setAttribute(Utf8ToXML("group").x_str(), Utf8ToXML(groupName).x_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string StateManager::getAnnotation(std::string id) {
|
||||
DOMElement * level = getLevel(id);
|
||||
if (level != NULL)
|
||||
return XMLtoUtf8(level->getAttribute(Utf8ToXML("annotation").x_str())).c_str();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
void StateManager::setAnnotation(std::string id, std::string annotation) {
|
||||
DOMElement * level = getLevel(id);
|
||||
if (level == NULL) {
|
||||
level = doc->createElement (Utf8ToXML("level").x_str());
|
||||
level->setAttribute(Utf8ToXML("id").x_str(), Utf8ToXML(id).x_str());
|
||||
levelsElem->appendChild(level);
|
||||
}
|
||||
level->setAttribute(Utf8ToXML("annotation").x_str(), Utf8ToXML(annotation).x_str());
|
||||
}
|
||||
|
||||
DOMElement * StateManager::getLevel(std::string id) {
|
||||
XMLCh * xmlId = XMLString::replicate(Utf8ToXML(id).x_str());
|
||||
bool levelFound = false;
|
||||
DOMElement * level;
|
||||
DOMNodeList * levelList = levelsElem->getElementsByTagName(Utf8ToXML("level").x_str());
|
||||
for (int i = 0, l = levelList-> getLength(); i < l && !levelFound; i++) {
|
||||
level = dynamic_cast<DOMElement *>(levelList->item(i));
|
||||
if (XMLString::equals(xmlId,
|
||||
level->getAttribute(Utf8ToXML("id").x_str()))) {
|
||||
levelFound = true;
|
||||
}
|
||||
}
|
||||
XMLString::release(&xmlId);
|
||||
return levelFound ? level : NULL;
|
||||
}
|
||||
} // namespace enigma
|
||||
83
project/jni/application/enigma/src/StateManager.hh
Normal file
83
project/jni/application/enigma/src/StateManager.hh
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef STATEMGR_HH_INCLUDED
|
||||
#define STATEMGR_HH_INCLUDED
|
||||
|
||||
#include "PropertyManager.hh"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <xercesc/dom/DOMElement.hpp>
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* A singelton manager for state info stored in XML format.
|
||||
* <p>The singleton can be accessed via standard static instance() method or
|
||||
* the application public ivar <code>app.state</code>.</p>
|
||||
*
|
||||
* <p>The storage location of the state is determined by the
|
||||
* Application object.</p>
|
||||
* <p>The set and get methods for properties take utf8 encoded property
|
||||
* names and operate with utf8 encoded string values. Set methods create new
|
||||
* state property elements if necessary. Get methods do not modify
|
||||
* reference values and return C++ default values if the named property
|
||||
* does not exist.</p>
|
||||
*/
|
||||
class StateManager : public PropertyManager {
|
||||
public:
|
||||
static StateManager *instance();
|
||||
~StateManager();
|
||||
virtual bool save();
|
||||
void shutdown();
|
||||
|
||||
void getGroupNames(std::vector<std::string> *names);
|
||||
std::string getGroupSelectedIndex(std::string groupName);
|
||||
std::string getGroupSelectedColumn(std::string groupName);
|
||||
void setGroupSelectedIndex(std::string groupName, std::string indexName);
|
||||
void setGroupSelectedColumn(std::string groupName, std::string column);
|
||||
void addGroup(std::string groupName, std::string indexName, int column); // update or append
|
||||
void insertGroup(int pos, std::string groupName, std::string indexName, std::string column); // no duplicate check, pos -1 is append
|
||||
void deleteGroup(std::string groupName);
|
||||
void renameGroup(std::string oldName, std::string newName);
|
||||
|
||||
void addIndex(std::string indexName, std::string &groupName, double &location,
|
||||
int &curpos, int &curfirst);
|
||||
void setIndexName(std::string oldName, std::string newName);
|
||||
void setIndexLocation(std::string indexName, double location);
|
||||
void setIndexCurpos(std::string indexName, int curpos);
|
||||
void setIndexCurfirst(std::string indexName, int curfirst);
|
||||
void setIndexGroup(std::string indexName, std::string groupName);
|
||||
|
||||
std::string getAnnotation(std::string id);
|
||||
void setAnnotation(std::string id, std::string annotation);
|
||||
|
||||
protected:
|
||||
StateManager();
|
||||
private:
|
||||
static StateManager *theSingleton;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *groupsElem;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMNodeList *groupList;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *indicesElem;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMNodeList *indexList;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *levelsElem;
|
||||
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *getLevel(std::string id);
|
||||
};
|
||||
} // namespace enigma
|
||||
#endif
|
||||
80
project/jni/application/enigma/src/Utf8ToXML.cpp
Normal file
80
project/jni/application/enigma/src/Utf8ToXML.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "Utf8ToXML.hh"
|
||||
#include "main.hh"
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/TransService.hpp>
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
Utf8ToXML::Utf8ToXML(const char * const toTranscode) {
|
||||
init(toTranscode);
|
||||
}
|
||||
|
||||
Utf8ToXML::Utf8ToXML(const std::string * const toTranscode) {
|
||||
init(toTranscode->c_str());
|
||||
}
|
||||
|
||||
Utf8ToXML::Utf8ToXML(const std::string toTranscode) {
|
||||
init(toTranscode.c_str());
|
||||
}
|
||||
|
||||
void Utf8ToXML::init(const char * const toTranscode) {
|
||||
#if _XERCES_VERSION >= 30000
|
||||
XMLSize_t srcLength = std::strlen(toTranscode) + 1;
|
||||
// make safe assumptions on utf-16 size
|
||||
XMLSize_t maxDestLength = srcLength;
|
||||
XMLSize_t charsEaten;
|
||||
XMLSize_t destLength;
|
||||
#else
|
||||
unsigned int srcLength = std::strlen(toTranscode) + 1;
|
||||
// make safe assumptions on utf-16 size
|
||||
unsigned int maxDestLength = srcLength;
|
||||
unsigned int charsEaten;
|
||||
unsigned int destLength;
|
||||
#endif
|
||||
unsigned char *charSizes = new unsigned char[maxDestLength]; // just junk
|
||||
// make a buffer - size does not matter - the object is temporary
|
||||
xmlString = new XMLCh[maxDestLength];
|
||||
// transcode to utf-8 -- there are no unrepresentable chars
|
||||
destLength = app.xmlUtf8Transcoder->transcodeFrom((XMLByte *)toTranscode,
|
||||
srcLength,
|
||||
xmlString, maxDestLength,
|
||||
charsEaten, charSizes);
|
||||
delete[] charSizes;
|
||||
if (charsEaten < srcLength)
|
||||
// an assert - should never occur
|
||||
Log << "Utf8toXML: incomplete transcoding - only "<< charsEaten <<
|
||||
" of " << srcLength << "bytes were processed!" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
Utf8ToXML::~Utf8ToXML() {
|
||||
delete [] xmlString;
|
||||
}
|
||||
|
||||
const XMLCh * Utf8ToXML::x_str() const {
|
||||
return xmlString;
|
||||
};
|
||||
} //namespace enigma
|
||||
|
||||
76
project/jni/application/enigma/src/Utf8ToXML.hh
Normal file
76
project/jni/application/enigma/src/Utf8ToXML.hh
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ENIGMA_UTF8TOXML_HH
|
||||
#define ENIGMA_UTF8TOXML_HH
|
||||
|
||||
#include <iostream>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* Transcoding utility for utf-8 strings to XMLCh strings
|
||||
* Provides a simple interface for the memory management paradigm shift
|
||||
* even though not terribly efficient. Make sure all Utf8toXML objects
|
||||
* exist only temporarily, f.e.
|
||||
* <code>DOMNode::setNodeValue(Utf8ToXML(char *toTranscode).x_str())</code> or
|
||||
* <code>XMLString::replicate(Utf8ToXML(char *toTranscode).x_str())</code>
|
||||
* Xerces should be initialized before using this class and all objects
|
||||
* should be deleted before terminating.
|
||||
*/
|
||||
class Utf8ToXML {
|
||||
public :
|
||||
/**
|
||||
* Makes a transcoding to XML.
|
||||
*
|
||||
* @param toTranscode utf-8 coded string
|
||||
*/
|
||||
Utf8ToXML(const char * const toTranscode);
|
||||
/**
|
||||
* Makes a transcoding to the local code page.
|
||||
*
|
||||
* @param toTranscode utf-8 coded string
|
||||
*/
|
||||
Utf8ToXML(const std::string * const toTranscode);
|
||||
/**
|
||||
* Makes a transcoding to the local code page.
|
||||
*
|
||||
* @param toTranscode utf-8 coded string
|
||||
*/
|
||||
Utf8ToXML(const std::string toTranscode);
|
||||
~Utf8ToXML();
|
||||
|
||||
/**
|
||||
* Returns the XML string. It remains owner of
|
||||
* the string.
|
||||
*/
|
||||
const XMLCh * x_str() const;
|
||||
|
||||
private :
|
||||
/**
|
||||
* A XML copy. We are the owner.
|
||||
*/
|
||||
XMLCh * xmlString;
|
||||
void init(const char * const toTranscode);
|
||||
};
|
||||
} //namespace enigma
|
||||
#endif
|
||||
|
||||
40
project/jni/application/enigma/src/XMLtoLocal.cpp
Normal file
40
project/jni/application/enigma/src/XMLtoLocal.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "XMLtoLocal.hh"
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
XMLtoLocal::XMLtoLocal(const XMLCh* const toTranscode) {
|
||||
// Use XML for transcoding -- the returned string is owned by us
|
||||
// but managed by XMLString!
|
||||
localString = XMLString::transcode(toTranscode);
|
||||
}
|
||||
|
||||
XMLtoLocal::~XMLtoLocal() {
|
||||
XMLString::release(&localString);
|
||||
}
|
||||
|
||||
const char* XMLtoLocal::c_str() const {
|
||||
return localString;
|
||||
}
|
||||
|
||||
} //namespace enigma
|
||||
73
project/jni/application/enigma/src/XMLtoLocal.hh
Normal file
73
project/jni/application/enigma/src/XMLtoLocal.hh
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ENIGMA_XMLTOLOCAL_HH
|
||||
#define ENIGMA_XMLTOLOCAL_HH
|
||||
|
||||
#include <iostream>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* Transcoding utility for XMLCh strings to local code page strings.
|
||||
* Provides a simple interface for the memory management paradigm shift
|
||||
* even though not terribly efficient. Make sure all XMLtoLocal objects
|
||||
* exist only temporarily, f.e.
|
||||
* <code>new String(XMLtoLocal(XMLCh *toTranscode).c_str())</code> or
|
||||
* <code>Log << XMLtoLocal(XMLCh *toTranscode)</code>
|
||||
* Xerces should be initialized before using this class and all objects
|
||||
* should be deleted before terminating.
|
||||
*/
|
||||
class XMLtoLocal {
|
||||
public :
|
||||
/**
|
||||
* Makes a transcoding to the local code page.
|
||||
*
|
||||
* @param toTranscode XML managed string
|
||||
*/
|
||||
XMLtoLocal(const XMLCh* const toTranscode);
|
||||
~XMLtoLocal();
|
||||
|
||||
/**
|
||||
* Returns the string coded in the local page. It remains owner of
|
||||
* the string.
|
||||
*/
|
||||
const char* c_str() const;
|
||||
|
||||
private :
|
||||
/**
|
||||
* A copy coded in the local code page.
|
||||
* The string is managed by XMLString - we are the owner.
|
||||
*/
|
||||
char* localString;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enables efficient stream output of XMLCh * strings. Use it as
|
||||
* <code>Log << XML2Local(XMLCh *toTranscode)</code>. All resources
|
||||
* are managed and released.
|
||||
*/
|
||||
inline std::ostream& operator<<(std::ostream& target, const XMLtoLocal& toDump) {
|
||||
target << toDump.c_str();
|
||||
return target;
|
||||
}
|
||||
} //namespace enigma
|
||||
#endif
|
||||
|
||||
63
project/jni/application/enigma/src/XMLtoUtf8.cpp
Normal file
63
project/jni/application/enigma/src/XMLtoUtf8.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2005, 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "XMLtoUtf8.hh"
|
||||
#include "main.hh"
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/TransService.hpp>
|
||||
|
||||
XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
XMLtoUtf8::XMLtoUtf8(const XMLCh* const toTranscode) {
|
||||
#if _XERCES_VERSION >= 30000
|
||||
XMLSize_t srcLength = XMLString::stringLen(toTranscode) + 1;
|
||||
// make safe assumptions on utf-8 size
|
||||
XMLSize_t maxDestLength = 3 * srcLength;
|
||||
XMLSize_t charsEaten;
|
||||
XMLSize_t destLength;
|
||||
#else
|
||||
unsigned int srcLength = XMLString::stringLen(toTranscode) + 1;
|
||||
// make safe assumptions on utf-8 size
|
||||
unsigned int maxDestLength = 3 * srcLength;
|
||||
unsigned int charsEaten;
|
||||
unsigned int destLength;
|
||||
#endif
|
||||
// make a buffer - size does not matter - the object is temporary
|
||||
utf8String = new char[maxDestLength];
|
||||
// transcode to utf-8 -- there are no unrepresentable chars
|
||||
destLength = app.xmlUtf8Transcoder->transcodeTo(toTranscode, srcLength,
|
||||
(XMLByte *)utf8String, maxDestLength,
|
||||
charsEaten, XMLTranscoder::UnRep_RepChar);
|
||||
if (charsEaten < srcLength)
|
||||
// an assert - should never occur
|
||||
Log << "XMLtoUtf8: incomplete transcoding - only "<< charsEaten <<
|
||||
" of " << srcLength << "characters were processed!" << std::endl;
|
||||
}
|
||||
|
||||
XMLtoUtf8::~XMLtoUtf8() {
|
||||
delete [] utf8String;
|
||||
}
|
||||
|
||||
const char* XMLtoUtf8::c_str() const {
|
||||
return utf8String;
|
||||
};
|
||||
} //namespace enigma
|
||||
|
||||
61
project/jni/application/enigma/src/XMLtoUtf8.hh
Normal file
61
project/jni/application/enigma/src/XMLtoUtf8.hh
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ENIGMA_XMLTOUTF8_HH
|
||||
#define ENIGMA_XMLTOUTF8_HH
|
||||
|
||||
#include <iostream>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
/**
|
||||
* Transcoding utility for XMLCh strings to utf-8 strings.
|
||||
* Provides a simple interface for the memory management paradigm shift
|
||||
* even though not terribly efficient. Make sure all XMLtoUtf8 objects
|
||||
* exist only temporarily, f.e.
|
||||
* <code>new string(XMLtoUtf8(XMLCh *toTranscode).c_str())</code>
|
||||
* Xerces should be initialized before using this class and all objects
|
||||
* should be deleted before terminating.
|
||||
*/
|
||||
class XMLtoUtf8 {
|
||||
public :
|
||||
/**
|
||||
* Makes a transcoding to utf-8
|
||||
*
|
||||
* @param toTranscode XML managed string
|
||||
*/
|
||||
XMLtoUtf8(const XMLCh* const toTranscode);
|
||||
~XMLtoUtf8();
|
||||
|
||||
/**
|
||||
* Returns the string coded in utf-8. It remains owner of
|
||||
* the string.
|
||||
*/
|
||||
const char * c_str() const;
|
||||
|
||||
private :
|
||||
/**
|
||||
* A copy coded in utf-8. We are the owner.
|
||||
*/
|
||||
char * utf8String;
|
||||
};
|
||||
} //namespace enigma
|
||||
#endif
|
||||
|
||||
1182
project/jni/application/enigma/src/actors.cpp
Normal file
1182
project/jni/application/enigma/src/actors.cpp
Normal file
File diff suppressed because it is too large
Load Diff
208
project/jni/application/enigma/src/actors.hh
Normal file
208
project/jni/application/enigma/src/actors.hh
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef ACTORS_HH_INCLUDED
|
||||
#define ACTORS_HH_INCLUDED
|
||||
|
||||
#include "objects_decl.hh"
|
||||
|
||||
namespace world
|
||||
{
|
||||
enum ActorID {
|
||||
ac_INVALID = -1,
|
||||
ac_FIRST = 0,
|
||||
ac_blackball = 0,
|
||||
ac_whiteball = 1,
|
||||
ac_meditation = 2,
|
||||
ac_killerball = 3,
|
||||
ac_rotor = 4,
|
||||
ac_top = 5,
|
||||
ac_horse = 6,
|
||||
ac_bug = 7,
|
||||
ac_cannonball = 8,
|
||||
ac_spermbird = 9,
|
||||
ac_LAST = 9,
|
||||
ac_COUNT
|
||||
};
|
||||
|
||||
struct ActorTraits {
|
||||
const char *name;
|
||||
ActorID id;
|
||||
float radius;
|
||||
float default_mass;
|
||||
};
|
||||
|
||||
/* -------------------- ActorInfo -------------------- */
|
||||
|
||||
struct Contact {
|
||||
ecl::V2 pos;
|
||||
ecl::V2 normal;
|
||||
|
||||
// Constructor
|
||||
Contact (const ecl::V2 &pos_, const ecl::V2 &normal_)
|
||||
: pos(pos_), normal (normal_) {}
|
||||
};
|
||||
|
||||
typedef std::vector<Contact> ContactList;
|
||||
|
||||
/*!
|
||||
* This class contains the information the physics engine
|
||||
* maintains about dynamic objects ("actors").
|
||||
*/
|
||||
struct ActorInfo {
|
||||
// ---------- Variables ----------
|
||||
|
||||
ecl::V2 pos; // Absolute position
|
||||
ecl::V2 vel; // Velocity
|
||||
ecl::V2 forceacc; // Force accumulator
|
||||
double charge; // Electric charge
|
||||
double mass; // Mass
|
||||
double radius; // Radius of the ball
|
||||
bool grabbed; // Actor not controlled by the physics engine
|
||||
bool ignore_contacts; // Do not perform collision handling
|
||||
|
||||
// Variables used internally by the physics engine
|
||||
|
||||
ecl::V2 last_pos; // Position before current tick
|
||||
ecl::V2 oldpos; // Backup position for enter/leave notification
|
||||
ecl::V2 force; // Force used during tick
|
||||
ecl::V2 collforce;
|
||||
ContactList contacts;
|
||||
ContactList new_contacts;
|
||||
|
||||
// Constructor
|
||||
ActorInfo();
|
||||
};
|
||||
|
||||
|
||||
class Actor : public Object, public display::ModelCallback {
|
||||
public:
|
||||
// ModelCallback interface
|
||||
void animcb ();
|
||||
|
||||
/* ---------- Object interface ---------- */
|
||||
Actor *clone() = 0;
|
||||
virtual Value message (const string &m, const Value &);
|
||||
void set_attrib (const string& key, const Value &val);
|
||||
|
||||
/* ---------- Actor interface ---------- */
|
||||
virtual const ActorTraits &get_traits() const = 0;
|
||||
|
||||
virtual void think (double dtime);
|
||||
|
||||
virtual void on_collision(Actor *a);
|
||||
virtual void on_creation(const ecl::V2 &pos);
|
||||
virtual void on_respawn (const ecl::V2 &pos);
|
||||
|
||||
virtual bool is_dead() const = 0;
|
||||
virtual bool is_movable() const { return true; }
|
||||
virtual bool is_flying() const { return false; }
|
||||
virtual bool is_on_floor() const { return true; }
|
||||
virtual bool is_drunken() const { return false; }
|
||||
virtual bool is_invisible() const { return false; }
|
||||
|
||||
virtual bool can_drop_items() const { return false; }
|
||||
virtual bool can_move() const;
|
||||
virtual bool can_be_warped() const { return false; }
|
||||
virtual bool has_shield() const { return false; }
|
||||
|
||||
virtual void init();
|
||||
|
||||
/* ---------- Methods ---------- */
|
||||
void move ();
|
||||
virtual void move_screen ();
|
||||
void warp (const ecl::V2 &newpos);
|
||||
bool sound_event (const char *name, double vol = 1.0);
|
||||
|
||||
void respawn();
|
||||
void set_respawnpos(const ecl::V2& p);
|
||||
void remove_respawnpos();
|
||||
void find_respawnpos();
|
||||
const ecl::V2 &get_respawnpos() const;
|
||||
const ecl::V2 &get_startpos() const;
|
||||
|
||||
virtual void hide();
|
||||
void show();
|
||||
|
||||
void add_force (const ecl::V2 &f);
|
||||
|
||||
/* ---------- Accessors ---------- */
|
||||
ActorInfo *get_actorinfo();
|
||||
const ActorInfo &get_actorinfo() const;
|
||||
const ecl::V2 &get_pos() const;
|
||||
|
||||
const ecl::V2 &get_vel() const {
|
||||
return m_actorinfo.vel;
|
||||
}
|
||||
|
||||
bool has_spikes() const { return spikes; }
|
||||
void set_spikes(bool has) { spikes = has; }
|
||||
|
||||
static double get_max_radius(); // max. radius of all actors
|
||||
|
||||
int get_controllers () const { return controllers; }
|
||||
double get_mouseforce () const { return mouseforce; }
|
||||
|
||||
bool controlled_by(int player) const {
|
||||
return (get_controllers() & (1+player)) != 0;
|
||||
}
|
||||
|
||||
const GridPos &get_gridpos() const { return gridpos; }
|
||||
|
||||
protected:
|
||||
Actor(const ActorTraits &tr);
|
||||
void set_model (const string &modelname);
|
||||
void set_anim (const string &modelname);
|
||||
|
||||
display::SpriteHandle &get_sprite() { return m_sprite; }
|
||||
|
||||
private:
|
||||
/* ---------- Variables ---------- */
|
||||
ActorInfo m_actorinfo;
|
||||
display::SpriteHandle m_sprite;
|
||||
ecl::V2 startingpos;
|
||||
ecl::V2 respawnpos;
|
||||
bool use_respawnpos;
|
||||
bool spikes; // set by "it-pin"
|
||||
int controllers;
|
||||
double mouseforce;
|
||||
GridPos gridpos;
|
||||
};
|
||||
|
||||
inline ActorID get_id (Actor *a) {
|
||||
return a->get_traits().id;
|
||||
}
|
||||
|
||||
inline double get_radius (const Actor *a) {
|
||||
return a->get_actorinfo().radius;
|
||||
}
|
||||
|
||||
inline double get_mass (const Actor *a) {
|
||||
return a->get_actorinfo().mass;
|
||||
}
|
||||
|
||||
inline double get_charge (const Actor *a) {
|
||||
return a->get_actorinfo().charge;
|
||||
}
|
||||
|
||||
/* -------------------- Global Functions -------------------- */
|
||||
|
||||
void InitActors();
|
||||
}
|
||||
|
||||
#endif
|
||||
216
project/jni/application/enigma/src/actors_internal.hh
Normal file
216
project/jni/application/enigma/src/actors_internal.hh
Normal file
@@ -0,0 +1,216 @@
|
||||
namespace
|
||||
{
|
||||
// helper class to find good respawn positions
|
||||
|
||||
struct ExaminedLocation : public GridPos {
|
||||
public:
|
||||
ExaminedLocation(GridPos p) : GridPos(p) {}
|
||||
|
||||
bool operator<(const ExaminedLocation& other) const {
|
||||
return (x == other.x) ? y<other.y : x<other.x;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::set<ExaminedLocation> ExaminedLocations;
|
||||
|
||||
class FreeRespawnLocationFinder
|
||||
{
|
||||
ExaminedLocations checked;
|
||||
ExaminedLocations blocked;
|
||||
ExaminedLocations candidates;
|
||||
|
||||
const Actor &actor_to_set;
|
||||
bool actor_is_marble;
|
||||
V2 preferred_position;
|
||||
|
||||
double max_enemy_gap;
|
||||
V2 max_gap_pos;
|
||||
|
||||
static const double MAX_DISTANCE_WANTED;
|
||||
|
||||
static bool is_marble(const string& k) {
|
||||
// true if kind 'k' is a marble
|
||||
return k == "ac-blackball" || k == "ac-whiteball" || k == "ac-whiteball-small";
|
||||
}
|
||||
|
||||
static bool is_respawn_floor(const string& k) {
|
||||
// true if marble may appear on floors of kind 'k'
|
||||
return
|
||||
k != "fl-abyss" &&
|
||||
k != "fl-water" &&
|
||||
k != "fl-space"; // player cannot be moved on fl-space
|
||||
}
|
||||
|
||||
static bool is_respawn_item(const string& k) {
|
||||
// true if marble may appear on items of kind 'k'
|
||||
return
|
||||
k != "it-laserbeam" &&
|
||||
k != "it-burnable-ignited";
|
||||
}
|
||||
|
||||
static bool search_through_stone(const Stone& st) {
|
||||
if (st.is_movable() || st.is_floating()) return true;
|
||||
|
||||
const string& k = st.get_kind();
|
||||
return k == "st-puzzle";
|
||||
}
|
||||
|
||||
static double wanted_distance_to(const string& k) {
|
||||
// returns the size of the gap wanted between a marble and an actor of kind 'k'
|
||||
|
||||
if (k == "ac-rotor") return MAX_DISTANCE_WANTED;
|
||||
if (k == "ac-top") return 3.0;
|
||||
if (k == "ac-killerball" || k == "ac-bug") return 1.5;
|
||||
return 0.3;
|
||||
}
|
||||
|
||||
double distance_wanted_to(const Actor& a) {
|
||||
double dist = 0.3;
|
||||
|
||||
if (actor_is_marble) dist = wanted_distance_to(a.get_kind());
|
||||
else if (is_marble(a.get_kind())) dist = wanted_distance_to(actor_to_set.get_kind());
|
||||
|
||||
ASSERT(dist <= MAX_DISTANCE_WANTED, XLevelRuntime, "FreeRespawnLocationFinder: distance_wanted_to too large ");
|
||||
return dist;
|
||||
}
|
||||
|
||||
bool enemyActorAt(const V2& p) {
|
||||
vector<Actor*> found_actors;
|
||||
double range = get_radius (&actor_to_set) + MAX_DISTANCE_WANTED + Actor::get_max_radius();
|
||||
|
||||
if (GetActorsInRange(p, range, found_actors)) {
|
||||
bool found_near_enemy = false;
|
||||
double min_enemy_gap = 1000.0;
|
||||
|
||||
for (vector<Actor*>::const_iterator ai = found_actors.begin();
|
||||
ai != found_actors.end();
|
||||
++ai)
|
||||
{
|
||||
Actor *a = *ai;
|
||||
|
||||
if (a != &actor_to_set) {
|
||||
double distance = length(p - a->get_pos());
|
||||
double gap_between = distance - get_radius (&actor_to_set) - get_radius(a);
|
||||
double wanted_gap = distance_wanted_to(*a);
|
||||
|
||||
if (gap_between < wanted_gap)
|
||||
found_near_enemy = true;
|
||||
|
||||
if (gap_between < min_enemy_gap)
|
||||
min_enemy_gap = gap_between;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_near_enemy) {
|
||||
if (min_enemy_gap<999.0) {
|
||||
if (min_enemy_gap > max_enemy_gap) {
|
||||
max_enemy_gap = min_enemy_gap;
|
||||
max_gap_pos = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_near_enemy;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void examine(GridPos p) {
|
||||
if (checked.find(p) != checked.end()) return; // already examined
|
||||
checked.insert(p); // never check again
|
||||
|
||||
Floor *fl = GetFloor(p);
|
||||
if (!fl || !is_respawn_floor(fl->get_kind())) return; // bad floor
|
||||
|
||||
bool may_respawn = true;
|
||||
bool continue_search = true;
|
||||
|
||||
Item *it = GetItem(p);
|
||||
if (it && !is_respawn_item(it->get_kind())) may_respawn = false; // bad item
|
||||
|
||||
Stone *st = GetStone(p);
|
||||
if (st) {
|
||||
if (!search_through_stone(*st)) continue_search = false;
|
||||
may_respawn = false;
|
||||
}
|
||||
|
||||
if (may_respawn) { // may be a candidate -> check for enemy actors
|
||||
if (enemyActorAt(p.center())) may_respawn = false;
|
||||
}
|
||||
|
||||
if (continue_search) blocked.insert(p);
|
||||
if (may_respawn) candidates.insert(p);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
FreeRespawnLocationFinder(V2 p, const Actor& actor)
|
||||
: actor_to_set(actor)
|
||||
, preferred_position(p)
|
||||
, max_enemy_gap(-1000.0)
|
||||
{
|
||||
actor_is_marble = is_marble(actor_to_set.get_kind());
|
||||
ExaminedLocations affected; // all locations affected by current respawn position
|
||||
{
|
||||
double radius = get_radius (&actor_to_set);
|
||||
int xmin = int(p[0]-radius);
|
||||
int xmax = int(p[0]+radius);
|
||||
int ymin = int(p[1]-radius);
|
||||
int ymax = int(p[1]+radius);
|
||||
|
||||
for (int x = xmin; x <= xmax; ++x) {
|
||||
for (int y = ymin; y <= ymax; ++y) {
|
||||
affected.insert(GridPos(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ExaminedLocations::const_iterator ai = affected.begin(); ai != affected.end(); ++ai) {
|
||||
examine(*ai);
|
||||
}
|
||||
|
||||
if (candidates.size() != affected.size()) { // if any affected location may not be used for respawning
|
||||
// choose alternate respawn location
|
||||
|
||||
blocked = affected; // start with all affected positions
|
||||
|
||||
while (candidates.empty()) {
|
||||
ExaminedLocations curr_blocked;
|
||||
swap(curr_blocked, blocked);
|
||||
|
||||
if (curr_blocked.empty()) {
|
||||
break; // no chance to find a candidate
|
||||
}
|
||||
|
||||
for (ExaminedLocations::const_iterator bl = curr_blocked.begin(); bl != curr_blocked.end(); ++bl) {
|
||||
examine(move(*bl, NORTH));
|
||||
examine(move(*bl, SOUTH));
|
||||
examine(move(*bl, EAST));
|
||||
examine(move(*bl, WEST));
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.empty()) { // no better location -> take least worse tested location
|
||||
if (max_enemy_gap > 0.0) {
|
||||
preferred_position = max_gap_pos;
|
||||
}
|
||||
}
|
||||
else { // a better location has been found
|
||||
ExaminedLocations::const_iterator c = candidates.begin();
|
||||
advance(c, IntegerRand(0, int (candidates.size()-1)));
|
||||
|
||||
ASSERT(c != candidates.end(), XLevelRuntime, "FreeRespawnLocationFinder: list of candidates corrupt");
|
||||
preferred_position = c->center();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
V2 get_position() const { return preferred_position; }
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const double FreeRespawnLocationFinder::MAX_DISTANCE_WANTED = 5.0;
|
||||
}
|
||||
970
project/jni/application/enigma/src/client.cpp
Normal file
970
project/jni/application/enigma/src/client.cpp
Normal file
@@ -0,0 +1,970 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Daniel Heck
|
||||
* Copyright (C) 2006, 2007 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "client.hh"
|
||||
#include "game.hh"
|
||||
#include "display.hh"
|
||||
#include "options.hh"
|
||||
#include "server.hh"
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "main.hh"
|
||||
#include "gui/GameMenu.hh"
|
||||
#include "sound.hh"
|
||||
#include "player.hh"
|
||||
#include "world.hh"
|
||||
#include "nls.hh"
|
||||
#include "StateManager.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/PersistentIndex.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include "lev/RatingManager.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
|
||||
#include "ecl_sdl.hh"
|
||||
|
||||
#include "enet/enet.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
using namespace enigma::client;
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
#include "client_internal.hh"
|
||||
|
||||
/* -------------------- Auxiliary functions -------------------- */
|
||||
|
||||
namespace
|
||||
{
|
||||
/*! Display a message and change the current mouse speed. */
|
||||
void set_mousespeed (double speed)
|
||||
{
|
||||
int s = round_nearest<int>(speed);
|
||||
options::SetMouseSpeed (s);
|
||||
s = round_nearest<int> (options::GetMouseSpeed ());
|
||||
Msg_ShowText(strf(_("Mouse speed: %d"), s), false, 2.0);
|
||||
}
|
||||
|
||||
/*! Generate the message that is displayed when the level starts. */
|
||||
string displayedLevelInfo (lev::Proxy *level)
|
||||
{
|
||||
std::string text;
|
||||
std::string tmp;
|
||||
|
||||
tmp = level->getLocalizedString("title");
|
||||
if (tmp.empty())
|
||||
tmp = _("Another nameless level");
|
||||
text = string("\"")+ tmp +"\"";
|
||||
tmp = level->getAuthor();
|
||||
if (!tmp.empty())
|
||||
text += _(" by ") + tmp;
|
||||
tmp = level->getLocalizedString("subtitle");
|
||||
if (!tmp.empty() && tmp != "subtitle")
|
||||
text += string(" - \"")+ tmp + "\"";
|
||||
tmp = level->getCredits(false);
|
||||
if (!tmp.empty())
|
||||
text += string(" - Credits: ")+ tmp;
|
||||
tmp = level->getDedication(false);
|
||||
if (!tmp.empty())
|
||||
text += string(" - Dedication: ")+ tmp;
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Variables -------------------- */
|
||||
|
||||
namespace
|
||||
{
|
||||
Client client_instance;
|
||||
const char HSEP = '^'; // history separator (use character that user cannot use)
|
||||
}
|
||||
|
||||
#define CLIENT client_instance
|
||||
|
||||
|
||||
/* -------------------- Client class -------------------- */
|
||||
|
||||
Client::Client()
|
||||
: m_state (cls_idle),
|
||||
m_levelname(),
|
||||
m_hunt_against_time(0),
|
||||
m_cheater(false),
|
||||
m_user_input()
|
||||
{
|
||||
m_network_host = 0;
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
network_stop();
|
||||
}
|
||||
|
||||
bool Client::network_start()
|
||||
{
|
||||
if (m_network_host)
|
||||
return true;
|
||||
|
||||
m_network_host = enet_host_create (NULL,
|
||||
1 /* only allow 1 outgoing connection */,
|
||||
57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */,
|
||||
14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */);
|
||||
|
||||
if (m_network_host == NULL) {
|
||||
fprintf (stderr,
|
||||
"An error occurred while trying to create an ENet client host.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ----- Connect to server
|
||||
|
||||
ENetAddress sv_address;
|
||||
ENetPeer *m_server;
|
||||
|
||||
/* Connect to some.server.net:1234. */
|
||||
enet_address_set_host (&sv_address, "localhost");
|
||||
sv_address.port = 12345;
|
||||
|
||||
/* Initiate the connection, allocating the two channels 0 and 1. */
|
||||
m_server = enet_host_connect (m_network_host, &sv_address, 2);
|
||||
|
||||
if (m_server == NULL) {
|
||||
fprintf (stderr,
|
||||
"No available peers for initiating an ENet connection.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait up to 5 seconds for the connection attempt to succeed.
|
||||
ENetEvent event;
|
||||
if (enet_host_service (m_network_host, &event, 5000) > 0 &&
|
||||
event.type == ENET_EVENT_TYPE_CONNECT)
|
||||
{
|
||||
fprintf (stderr, "Connection to some.server.net:1234 succeeded.");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Either the 5 seconds are up or a disconnect event was */
|
||||
/* received. Reset the peer in the event the 5 seconds */
|
||||
/* had run out without any significant event. */
|
||||
enet_peer_reset (m_server);
|
||||
m_server = 0;
|
||||
|
||||
fprintf (stderr, "Connection to localhost:12345 failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::network_stop ()
|
||||
{
|
||||
if (m_network_host)
|
||||
enet_host_destroy (m_network_host);
|
||||
if (m_server)
|
||||
enet_peer_reset (m_server);
|
||||
}
|
||||
|
||||
|
||||
/* ---------- Event handling ---------- */
|
||||
|
||||
void Client::handle_events()
|
||||
{
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
on_keydown(e);
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (abs(e.motion.xrel) > 300 || abs(e.motion.yrel) > 300) {
|
||||
fprintf(stderr, "mouse event with %i, %i\n", e.motion.xrel, e.motion.yrel);
|
||||
}
|
||||
else
|
||||
server::Msg_MouseForce (options::GetDouble("MouseSpeed") *
|
||||
V2 (e.motion.xrel, e.motion.yrel));
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
on_mousebutton(e);
|
||||
break;
|
||||
case SDL_ACTIVEEVENT: {
|
||||
update_mouse_button_state();
|
||||
if (e.active.gain == 0 && !video::IsFullScreen())
|
||||
show_menu();
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_VIDEOEXPOSE: {
|
||||
display::RedrawAll(video::GetScreen());
|
||||
break;
|
||||
}
|
||||
|
||||
case SDL_QUIT:
|
||||
client::Msg_Command("abort");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::update_mouse_button_state()
|
||||
{
|
||||
int b = SDL_GetMouseState(0, 0);
|
||||
player::InhibitPickup((b & SDL_BUTTON(1)) || (b & SDL_BUTTON(3)));
|
||||
}
|
||||
|
||||
void Client::on_mousebutton(SDL_Event &e)
|
||||
{
|
||||
if (e.button.state == SDL_PRESSED) {
|
||||
if (e.button.button == 1) {
|
||||
// left mousebutton -> activate first item in inventory
|
||||
server::Msg_ActivateItem ();
|
||||
}
|
||||
else if (e.button.button == 3|| e.button.button == 4) {
|
||||
// right mousebutton, wheel down -> rotate inventory
|
||||
rotate_inventory(+1);
|
||||
}
|
||||
else if (e.button.button == 5) {
|
||||
// wheel down -> inverse rotate inventory
|
||||
rotate_inventory(-1);
|
||||
}
|
||||
}
|
||||
update_mouse_button_state();
|
||||
}
|
||||
|
||||
void Client::rotate_inventory (int direction)
|
||||
{
|
||||
m_user_input = "";
|
||||
STATUSBAR->hide_text();
|
||||
player::RotateInventory(direction);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Console related -------------------- */
|
||||
|
||||
class HistoryProxy {
|
||||
static int instances;
|
||||
public:
|
||||
static string content;
|
||||
|
||||
HistoryProxy();
|
||||
~HistoryProxy() {
|
||||
if (!--instances) app.state->setProperty("CommandHistory", content);
|
||||
}
|
||||
};
|
||||
|
||||
string HistoryProxy::content;
|
||||
int HistoryProxy::instances = 0;
|
||||
|
||||
HistoryProxy::HistoryProxy() {
|
||||
if (!instances++) {
|
||||
content = app.state->getString("CommandHistory");
|
||||
if (content.find(HSEP) == string::npos) content = string(1, HSEP);
|
||||
}
|
||||
}
|
||||
|
||||
static void user_input_history_append(const string& text, bool at_end = true) {
|
||||
HistoryProxy history;
|
||||
size_t old_pos = history.content.find(string(1, HSEP)+text+HSEP);
|
||||
|
||||
if (old_pos != string::npos)
|
||||
history.content.erase(old_pos, text.length()+1);
|
||||
|
||||
if (at_end)
|
||||
history.content += text+HSEP;
|
||||
else
|
||||
history.content = string(1, HSEP)+text+history.content;
|
||||
}
|
||||
|
||||
void Client::process_userinput()
|
||||
{
|
||||
if (m_user_input != "") {
|
||||
STATUSBAR->hide_text();
|
||||
string commands = m_user_input;
|
||||
|
||||
user_input_history_append(m_user_input);
|
||||
m_user_input = "";
|
||||
|
||||
size_t sep_pos;
|
||||
while ((sep_pos = commands.find_first_of(';')) != string::npos) {
|
||||
string first_command = commands.substr(0, sep_pos);
|
||||
commands.erase(0, sep_pos+1);
|
||||
server::Msg_Command (first_command);
|
||||
}
|
||||
server::Msg_Command (commands); // last command
|
||||
}
|
||||
}
|
||||
|
||||
void Client::user_input_append (char c) {
|
||||
m_user_input += c;
|
||||
Msg_ShowText (m_user_input, false);
|
||||
}
|
||||
|
||||
void Client::user_input_backspace ()
|
||||
{
|
||||
if (!m_user_input.empty()) {
|
||||
m_user_input.erase (m_user_input.size()-1, 1);
|
||||
if (!m_user_input.empty()) {
|
||||
// still not empty
|
||||
Msg_ShowText (m_user_input, false);
|
||||
} else {
|
||||
// empty
|
||||
STATUSBAR->hide_text();
|
||||
}
|
||||
}
|
||||
}
|
||||
void Client::user_input_previous ()
|
||||
{
|
||||
HistoryProxy history;
|
||||
size_t last_start = history.content.find_last_of(HSEP, history.content.length()-2);
|
||||
|
||||
if (last_start != string::npos) {
|
||||
string prev_input = history.content.substr(last_start+1, history.content.length()-last_start-2);
|
||||
history.content.erase(last_start+1);
|
||||
user_input_history_append(m_user_input, false);
|
||||
m_user_input = prev_input;
|
||||
|
||||
if (m_user_input.empty())
|
||||
STATUSBAR->hide_text();
|
||||
else
|
||||
Msg_ShowText (m_user_input, false);
|
||||
}
|
||||
}
|
||||
void Client::user_input_next ()
|
||||
{
|
||||
HistoryProxy history;
|
||||
size_t first_end = history.content.find_first_of(HSEP, 1);
|
||||
|
||||
if (first_end != string::npos) {
|
||||
string next_input = history.content.substr(1, first_end-1);
|
||||
history.content.erase(0, first_end);
|
||||
user_input_history_append(m_user_input);
|
||||
m_user_input = next_input;
|
||||
|
||||
if (m_user_input.empty())
|
||||
STATUSBAR->hide_text();
|
||||
else
|
||||
Msg_ShowText (m_user_input, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::on_keydown(SDL_Event &e)
|
||||
{
|
||||
SDLKey keysym = e.key.keysym.sym;
|
||||
SDLMod keymod = e.key.keysym.mod;
|
||||
|
||||
if (keymod & KMOD_CTRL) {
|
||||
switch (keysym) {
|
||||
case SDLK_a:
|
||||
server::Msg_Command ("restart");
|
||||
break;
|
||||
case SDLK_F3:
|
||||
if (keymod & KMOD_SHIFT) {
|
||||
// force a reload from file
|
||||
lev::Proxy * curProxy = lev::Proxy::loadedLevel();
|
||||
if (curProxy != NULL)
|
||||
curProxy->release();
|
||||
server::Msg_Command ("restart");
|
||||
}
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
else if (keymod & KMOD_ALT) {
|
||||
switch (keysym) {
|
||||
case SDLK_x: abort(); break;
|
||||
case SDLK_t:
|
||||
if (enigma::WizardMode) {
|
||||
Screen *scr = video::GetScreen();
|
||||
ecl::TintRect(scr->get_surface (), display::GetGameArea(),
|
||||
100, 100, 100, 0);
|
||||
scr->update_all();
|
||||
}
|
||||
break;
|
||||
case SDLK_s:
|
||||
if (enigma::WizardMode) {
|
||||
server::Msg_Command ("god");
|
||||
}
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
{
|
||||
video::TempInputGrab (false);
|
||||
video::ToggleFullscreen ();
|
||||
sdl::FlushEvents();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
else {
|
||||
switch (keysym) {
|
||||
case SDLK_ESCAPE: show_menu(); break;
|
||||
case SDLK_LEFT: set_mousespeed(options::GetMouseSpeed() - 1); break;
|
||||
case SDLK_RIGHT: set_mousespeed(options::GetMouseSpeed() + 1); break;
|
||||
case SDLK_TAB: rotate_inventory(+1); break;
|
||||
case SDLK_F1: show_help(); break;
|
||||
case SDLK_F2:
|
||||
// display hint
|
||||
break;
|
||||
case SDLK_F3:
|
||||
if (keymod & KMOD_SHIFT)
|
||||
server::Msg_Command ("restart");
|
||||
else
|
||||
server::Msg_Command ("suicide");
|
||||
break;
|
||||
|
||||
case SDLK_F4: Msg_AdvanceLevel(lev::ADVANCE_STRICTLY); break;
|
||||
case SDLK_F5: Msg_AdvanceLevel(lev::ADVANCE_UNSOLVED); break;
|
||||
case SDLK_F6: Msg_JumpBack(); break;
|
||||
|
||||
case SDLK_F10: {
|
||||
lev::Proxy *level = lev::Proxy::loadedLevel();
|
||||
std::string basename = std::string("screenshots/") +
|
||||
level->getLocalSubstitutionLevelPath();
|
||||
std::string fname = basename + ".png";
|
||||
std::string fullPath;
|
||||
int i = 1;
|
||||
while (app.resourceFS->findFile(fname, fullPath)) {
|
||||
fname = basename + ecl::strf("#%d", i++) + ".png";
|
||||
}
|
||||
std::string savePath = app.userImagePath + "/" + fname;
|
||||
video::Screenshot(savePath);
|
||||
break;
|
||||
}
|
||||
case SDLK_RETURN: process_userinput(); break;
|
||||
case SDLK_BACKSPACE: user_input_backspace(); break;
|
||||
case SDLK_UP: user_input_previous(); break;
|
||||
case SDLK_DOWN: user_input_next(); break;
|
||||
default:
|
||||
if (e.key.keysym.unicode && (e.key.keysym.unicode & 0xff80) == 0) {
|
||||
char ascii = static_cast<char>(e.key.keysym.unicode & 0x7f);
|
||||
if (isalnum (ascii) ||
|
||||
strchr(" .-!\"$%&/()=?{[]}\\#'+*~_,;.:<>|", ascii)) // don't add '^' or change history code
|
||||
{
|
||||
user_input_append(ascii);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *helptext_ingame[] = {
|
||||
N_("Left mouse button:"), N_("Activate/drop leftmost inventory item"),
|
||||
N_("Right mouse button:"), N_("Rotate inventory items"),
|
||||
N_("Escape:"), N_("Show game menu"),
|
||||
N_("F1:"), N_("Show this help"),
|
||||
N_("F3:"), N_("Kill current marble"),
|
||||
N_("Shift+F3:"), N_("Restart the current level"),
|
||||
N_("F4:"), N_("Skip to next level"),
|
||||
N_("F5:"), 0, // see below
|
||||
N_("F6:"), N_("Jump back to last level"),
|
||||
N_("F10:"), N_("Make screenshot"),
|
||||
N_("Left/right arrow:"), N_("Change mouse speed"),
|
||||
N_("Alt+x:"), N_("Return to level menu"),
|
||||
// N_("Alt+Return:"), N_("Switch between fullscreen and window"),
|
||||
0
|
||||
};
|
||||
|
||||
void Client::show_help()
|
||||
{
|
||||
server::Msg_Pause (true);
|
||||
video::TempInputGrab grab(false);
|
||||
|
||||
helptext_ingame[15] = app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST
|
||||
? _("Skip to next level for best score hunt")
|
||||
: _("Skip to next unsolved level");
|
||||
|
||||
video::ShowMouse();
|
||||
gui::displayHelp(helptext_ingame, 200);
|
||||
video::HideMouse();
|
||||
|
||||
update_mouse_button_state();
|
||||
if (m_state == cls_game)
|
||||
display::RedrawAll(video::GetScreen());
|
||||
|
||||
server::Msg_Pause (false);
|
||||
game::ResetGameTimer();
|
||||
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST)
|
||||
server::Msg_Command ("restart"); // inhibit cheating
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Client::show_menu()
|
||||
{
|
||||
server::Msg_Pause (true);
|
||||
|
||||
ecl::Screen *screen = video::GetScreen();
|
||||
|
||||
video::TempInputGrab grab (false);
|
||||
|
||||
video::ShowMouse();
|
||||
{
|
||||
int x, y;
|
||||
display::GetReferencePointCoordinates(&x, &y);
|
||||
enigma::gui::GameMenu(x, y).manage();
|
||||
}
|
||||
video::HideMouse();
|
||||
update_mouse_button_state();
|
||||
if (m_state == cls_game)
|
||||
display::RedrawAll(screen);
|
||||
|
||||
server::Msg_Pause (false);
|
||||
game::ResetGameTimer();
|
||||
|
||||
}
|
||||
|
||||
void Client::draw_screen()
|
||||
{
|
||||
switch (m_state) {
|
||||
case cls_error: {
|
||||
Screen *scr = video::GetScreen();
|
||||
GC gc (scr->get_surface());
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
Font *f = enigma::GetFont("menufont");
|
||||
|
||||
vector<string> lines;
|
||||
|
||||
ecl::split_copy (m_error_message, '\n', back_inserter(lines));
|
||||
int x = 60;
|
||||
int y = 60;
|
||||
int yskip = 25;
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
int width = vminfo->width - 120;
|
||||
for (unsigned i=0; i<lines.size(); ) {
|
||||
std::string::size_type breakPos = ecl::breakString (f, lines[i],
|
||||
" ", width);
|
||||
f->render(gc, x, y, lines[i].substr(0,breakPos).c_str());
|
||||
y += yskip;
|
||||
if (breakPos != lines[i].size()) {
|
||||
// process rest of line
|
||||
lines[i] = lines[i].substr(breakPos);
|
||||
} else {
|
||||
// process next line
|
||||
i++;
|
||||
}
|
||||
}
|
||||
scr->update_all();
|
||||
scr->flush_updates();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Client::init_hunted_time()
|
||||
{
|
||||
std::string hunted;
|
||||
m_hunt_against_time = 0;
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST) {
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
lev::ScoreManager *scm = lev::ScoreManager::instance();
|
||||
lev::Proxy *curProxy = ind->getCurrent();
|
||||
lev::RatingManager *ratingMgr = lev::RatingManager::instance();
|
||||
|
||||
int difficulty = app.state->getInt("Difficulty");
|
||||
int wr_time = ratingMgr->getBestScore(curProxy, difficulty);
|
||||
int best_user_time = scm->getBestUserScore(curProxy, difficulty);
|
||||
|
||||
if (best_user_time>0 && (wr_time == -1 || best_user_time<wr_time)) {
|
||||
m_hunt_against_time = best_user_time;
|
||||
hunted = "you";
|
||||
}
|
||||
else if (wr_time>0) {
|
||||
m_hunt_against_time = wr_time;
|
||||
hunted = ratingMgr->getBestScoreHolder(curProxy, difficulty);
|
||||
}
|
||||
|
||||
// STATUSBAR->set_timerstart(-m_hunt_against_time);
|
||||
}
|
||||
return hunted;
|
||||
}
|
||||
|
||||
void Client::tick (double dtime)
|
||||
{
|
||||
const double timestep = 0.01; // 10ms
|
||||
|
||||
switch (m_state) {
|
||||
case cls_idle:
|
||||
break;
|
||||
|
||||
case cls_preparing_game: {
|
||||
video::TransitionEffect *fx = m_effect.get();
|
||||
if (fx && !fx->finished()) {
|
||||
fx->tick (dtime);
|
||||
}
|
||||
else {
|
||||
m_effect.reset();
|
||||
server::Msg_StartGame();
|
||||
|
||||
m_state = cls_game;
|
||||
m_timeaccu = 0;
|
||||
m_total_game_time = 0;
|
||||
sdl::FlushEvents();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case cls_game:
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST) {
|
||||
int old_second = round_nearest<int> (m_total_game_time);
|
||||
int second = round_nearest<int> (m_total_game_time + dtime);
|
||||
|
||||
if (m_hunt_against_time && old_second <= m_hunt_against_time) {
|
||||
if (second > m_hunt_against_time) { // happens exactly once when par has passed by
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
lev::ScoreManager *scm = lev::ScoreManager::instance();
|
||||
lev::Proxy *curProxy = ind->getCurrent();
|
||||
lev::RatingManager *ratingMgr = lev::RatingManager::instance();
|
||||
int difficulty = app.state->getInt("Difficulty");
|
||||
int wr_time = ratingMgr->getBestScore(curProxy, difficulty);
|
||||
int best_user_time = scm->getBestUserScore(curProxy, difficulty);
|
||||
string message;
|
||||
|
||||
if (wr_time>0 && (best_user_time<0 || best_user_time>wr_time)) {
|
||||
message = string(_("Too slow for ")) +
|
||||
ratingMgr->getBestScoreHolder(curProxy, difficulty) +
|
||||
".. [Ctrl-A]";
|
||||
}
|
||||
else {
|
||||
message = string(_("You are slow today.. [Ctrl-A]"));
|
||||
}
|
||||
|
||||
client::Msg_PlaySound("shatter", 1.0);
|
||||
Msg_ShowText(message, true, 2.0);
|
||||
}
|
||||
else {
|
||||
if (old_second<second && // tick every second
|
||||
(second >= (m_hunt_against_time-5) || // at least 5 seconds
|
||||
second >= round_nearest<int> (m_hunt_against_time*.8))) // or the last 20% before par
|
||||
{
|
||||
client::Msg_PlaySound("pickup", 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_total_game_time += dtime;
|
||||
STATUSBAR->set_time (m_total_game_time);
|
||||
// fall through
|
||||
case cls_finished: {
|
||||
m_timeaccu += dtime;
|
||||
for (;m_timeaccu >= timestep; m_timeaccu -= timestep) {
|
||||
display::Tick (timestep);
|
||||
}
|
||||
display::Redraw(video::GetScreen());
|
||||
handle_events();
|
||||
break;
|
||||
}
|
||||
|
||||
case cls_gamemenu:
|
||||
break;
|
||||
case cls_gamehelp:
|
||||
break;
|
||||
case cls_abort:
|
||||
break;
|
||||
case cls_error:
|
||||
{
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_QUIT:
|
||||
client::Msg_Command("abort");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::level_finished()
|
||||
{
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
lev::ScoreManager *scm = lev::ScoreManager::instance();
|
||||
lev::Proxy *curProxy = ind->getCurrent();
|
||||
lev::RatingManager *ratingMgr = lev::RatingManager::instance();
|
||||
int difficulty = app.state->getInt("Difficulty");
|
||||
int wr_time = ratingMgr->getBestScore(curProxy, difficulty);
|
||||
int best_user_time = scm->getBestUserScore(curProxy, difficulty);
|
||||
string par_name = ratingMgr->getBestScoreHolder(curProxy, difficulty);
|
||||
int par_time = ratingMgr->getParScore(curProxy, difficulty);
|
||||
|
||||
int level_time = round_nearest<int> (m_total_game_time);
|
||||
|
||||
string text;
|
||||
bool timehunt_restart = false;
|
||||
|
||||
if (wr_time > 0) {
|
||||
if (best_user_time<0 || best_user_time>wr_time) {
|
||||
if (level_time == wr_time)
|
||||
text = string(_("Exactly the world record of "))+par_name+"!";
|
||||
else if (level_time<wr_time)
|
||||
text = _("Great! A new world record!");
|
||||
}
|
||||
}
|
||||
if (text.length() == 0 && best_user_time>0) {
|
||||
if (level_time == best_user_time) {
|
||||
text = _("Again your personal record...");
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST)
|
||||
timehunt_restart = true; // when hunting yourself: Equal is too slow
|
||||
}
|
||||
else if (level_time<best_user_time)
|
||||
if (par_time >= 0 && level_time <= par_time)
|
||||
text = _("New personal record - better than par!");
|
||||
else if (par_time >= 0)
|
||||
text = _("New personal record, but over par!");
|
||||
else
|
||||
text = _("New personal record!");
|
||||
}
|
||||
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST &&
|
||||
(wr_time>0 || best_user_time>0))
|
||||
{
|
||||
bool with_par = best_user_time == -1 || (wr_time >0 && wr_time<best_user_time);
|
||||
int behind = level_time - (with_par ? wr_time : best_user_time);
|
||||
|
||||
if (behind>0) {
|
||||
if (best_user_time>0 && level_time<best_user_time && with_par) {
|
||||
text = _("Your record, ");
|
||||
}
|
||||
else {
|
||||
text = "";
|
||||
}
|
||||
text += strf("%d:%02d ", static_cast<int> (behind/60)%100, behind%60);
|
||||
if (with_par)
|
||||
text += _("behind world record.");
|
||||
else
|
||||
text += _("behind your record.");
|
||||
|
||||
timehunt_restart = true; // time hunt failed -> repeat level
|
||||
}
|
||||
}
|
||||
|
||||
if (text.length() == 0) {
|
||||
if (par_time >= 0 && level_time <= par_time)
|
||||
text = _("Level finished - better than par!");
|
||||
else if (par_time >= 0)
|
||||
text = _("Level finished, but over par!");
|
||||
else
|
||||
text = _("Level finished!");
|
||||
}
|
||||
if (m_cheater)
|
||||
text += _(" Cheater!");
|
||||
|
||||
Msg_ShowText (text, false);
|
||||
|
||||
if (!m_cheater) {
|
||||
scm->updateUserScore(curProxy, difficulty, level_time);
|
||||
|
||||
// save score (just in case Enigma crashes when loading next level)
|
||||
lev::ScoreManager::instance()->save();
|
||||
|
||||
}
|
||||
|
||||
if (timehunt_restart)
|
||||
server::Msg_Command("restart");
|
||||
else
|
||||
m_state = cls_finished;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
void Client::level_loaded(bool isRestart)
|
||||
{
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
lev::ScoreManager *scm = lev::ScoreManager::instance();
|
||||
lev::Proxy *curProxy = ind->getCurrent();
|
||||
|
||||
// update window title
|
||||
video::SetCaption(ecl::strf(_("Enigma pack %s - level #%d: %s"), ind->getName().c_str(),
|
||||
ind->getCurrentLevel(), curProxy->getTitle().c_str()).c_str());
|
||||
|
||||
string hunted = init_hunted_time(); // sets m_hunt_against_time (used below)
|
||||
|
||||
// show level information (name, author, etc.)
|
||||
{
|
||||
string displayed_info = "";
|
||||
if (m_hunt_against_time>0) {
|
||||
if (hunted == "you")
|
||||
displayed_info = _("Your record: ");
|
||||
else
|
||||
displayed_info = _("World record to beat: ");
|
||||
displayed_info += ecl::strf("%d:%02d", (m_hunt_against_time/60)%100,
|
||||
m_hunt_against_time%60);
|
||||
//+ _(" by ") +hunted;
|
||||
// makes the string too long in many levels
|
||||
Msg_ShowText (displayed_info, true, 4.0);
|
||||
}
|
||||
else {
|
||||
displayed_info = displayedLevelInfo(curProxy);
|
||||
Msg_ShowText (displayed_info, true, 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
sound::FadeoutMusic();
|
||||
if (options::GetBool("InGameMusic")) {
|
||||
sound::PlayMusic (options::GetString("LevelMusicFile"));
|
||||
} else {
|
||||
sound::StopMusic();
|
||||
}
|
||||
|
||||
// start screen transition
|
||||
GC gc(video::BackBuffer());
|
||||
display::DrawAll(gc);
|
||||
|
||||
m_effect.reset (video::MakeEffect ((isRestart ? video::TM_SQUARES :
|
||||
video::TM_PUSH_RANDOM), video::BackBuffer()));
|
||||
m_cheater = false;
|
||||
m_state = cls_preparing_game;
|
||||
}
|
||||
|
||||
|
||||
void Client::handle_message (Message *m) { // @@@ unused
|
||||
switch (m->type) {
|
||||
case CLMSG_LEVEL_LOADED:
|
||||
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "Unhandled client event: %d\n", m->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::error (const string &text)
|
||||
{
|
||||
m_error_message = text;
|
||||
m_state = cls_error;
|
||||
draw_screen();
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
|
||||
bool client::NetworkStart()
|
||||
{
|
||||
return CLIENT.network_start();
|
||||
}
|
||||
|
||||
void client::Msg_LevelLoaded(bool isRestart)
|
||||
{
|
||||
CLIENT.level_loaded(isRestart);
|
||||
}
|
||||
|
||||
void client::Tick (double dtime) {
|
||||
CLIENT.tick (dtime);
|
||||
sound::Tick (dtime);
|
||||
}
|
||||
|
||||
void client::Stop() {
|
||||
CLIENT.stop ();
|
||||
}
|
||||
|
||||
void client::Msg_AdvanceLevel (lev::LevelAdvanceMode mode) {
|
||||
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
// log last played level
|
||||
lev::PersistentIndex::addCurrentToHistory();
|
||||
|
||||
if (ind->advanceLevel(mode)) {
|
||||
// now we may advance
|
||||
server::Msg_LoadLevel(ind->getCurrent(), false);
|
||||
}
|
||||
else
|
||||
client::Msg_Command("abort");
|
||||
}
|
||||
|
||||
void client::Msg_JumpBack() {
|
||||
// log last played level
|
||||
lev::PersistentIndex::addCurrentToHistory();
|
||||
server::Msg_JumpBack();
|
||||
}
|
||||
|
||||
bool client::AbortGameP() {
|
||||
return CLIENT.abort_p();
|
||||
}
|
||||
|
||||
void client::Msg_Command(const string& cmd) {
|
||||
if (cmd == "abort") {
|
||||
CLIENT.abort();
|
||||
}
|
||||
else if (cmd == "level_finished") {
|
||||
client::Msg_PlaySound("finished", 1.0);
|
||||
CLIENT.level_finished();
|
||||
}
|
||||
else if (cmd == "cheater") {
|
||||
CLIENT.mark_cheater();
|
||||
}
|
||||
else if (cmd == "easy_going") {
|
||||
CLIENT.easy_going();
|
||||
}
|
||||
else {
|
||||
enigma::Log << "Warning: Client received unknown command '" << cmd << "'\n";
|
||||
}
|
||||
}
|
||||
|
||||
void client::Msg_PlayerPosition (unsigned iplayer, const V2 &pos)
|
||||
{
|
||||
if (iplayer == (unsigned)player::CurrentPlayer()) {
|
||||
sound::SetListenerPosition (pos);
|
||||
display::SetReferencePoint (pos);
|
||||
}
|
||||
}
|
||||
|
||||
void client::Msg_PlaySound (const std::string &wavfile,
|
||||
const ecl::V2 &pos,
|
||||
double relative_volume)
|
||||
{
|
||||
sound::EmitSoundEvent (wavfile.c_str(), pos, relative_volume);
|
||||
}
|
||||
|
||||
void client::Msg_PlaySound (const std::string &wavfile, double relative_volume)
|
||||
{
|
||||
sound::EmitSoundEvent (wavfile.c_str(), V2(), relative_volume);
|
||||
}
|
||||
|
||||
void client::Msg_Sparkle (const ecl::V2 &pos) {
|
||||
display::AddEffect (pos, "ring-anim");
|
||||
}
|
||||
|
||||
|
||||
void client::Msg_ShowText
|
||||
(const std::string &text, bool scrolling, double duration)
|
||||
{
|
||||
STATUSBAR->show_text (text, scrolling, duration);
|
||||
}
|
||||
|
||||
void client::Msg_Error (const std::string &text)
|
||||
{
|
||||
CLIENT.error (text);
|
||||
}
|
||||
71
project/jni/application/enigma/src/client.hh
Normal file
71
project/jni/application/enigma/src/client.hh
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2003,2004,2005 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef CLIENT_HH_INCLUDED
|
||||
#define CLIENT_HH_INCLUDED
|
||||
|
||||
#include "lev/Index.hh"
|
||||
|
||||
namespace enigma_client
|
||||
{
|
||||
using namespace enigma;
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
bool NetworkStart();
|
||||
|
||||
|
||||
void Tick (double dtime);
|
||||
|
||||
bool AbortGameP();
|
||||
|
||||
void Stop();
|
||||
|
||||
/* -------------------- Server->Client messages -------------------- */
|
||||
|
||||
void Msg_Command(const std::string& cmd);
|
||||
|
||||
void Msg_AdvanceLevel (lev::LevelAdvanceMode mode);
|
||||
void Msg_JumpBack();
|
||||
|
||||
void Msg_LevelLoaded(bool isRestart);
|
||||
|
||||
void Msg_PlayerPosition (unsigned iplayer, const ecl::V2 &pos);
|
||||
|
||||
void Msg_Sparkle (const ecl::V2 &pos);
|
||||
|
||||
void Msg_ShowText (const std::string &text, bool scrolling, double duration=-1);
|
||||
|
||||
//! Play sound emanating from an absolute position in the world
|
||||
void Msg_PlaySound (const std::string &soundname,
|
||||
const ecl::V2 &pos,
|
||||
double relative_volume);
|
||||
|
||||
//! Play a sound emanating from the player's current position
|
||||
void Msg_PlaySound (const std::string &soundname, double relative_volume);
|
||||
|
||||
//! Stop the game and display an error message instead
|
||||
void Msg_Error (const std::string &text);
|
||||
}
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
namespace client = enigma_client;
|
||||
}
|
||||
|
||||
#endif
|
||||
172
project/jni/application/enigma/src/client_internal.hh
Normal file
172
project/jni/application/enigma/src/client_internal.hh
Normal file
@@ -0,0 +1,172 @@
|
||||
#include "gui/Menu.hh"
|
||||
#include "video.hh"
|
||||
#include "ecl_buffer.hh"
|
||||
|
||||
namespace
|
||||
{
|
||||
using ecl::Buffer;
|
||||
using std::string;
|
||||
|
||||
/* -------------------- Server -> Client messages -------------------- */
|
||||
|
||||
enum ClientCommand {
|
||||
CLMSG_NOOP,
|
||||
CLMSG_NEW_WORLD,
|
||||
CLMSG_LEVEL_LOADED,
|
||||
CLMSG_CHANGE_FIELD,
|
||||
CLMSG_ADD_ACTOR,
|
||||
CLMSG_MOVE_ACTOR,
|
||||
CLMSG_FOCUS_ACTOR,
|
||||
CLMSG_CHANGE_LINE,
|
||||
CLMSG_PLAY_SOUND,
|
||||
CLMSG_SHOW_TEXT,
|
||||
CLMSG_ERROR // error occurred
|
||||
};
|
||||
|
||||
struct Message {
|
||||
Message (ClientCommand type_ = CLMSG_NOOP) : type (type_) {
|
||||
}
|
||||
|
||||
ClientCommand type;
|
||||
};
|
||||
|
||||
struct Cl_NewWorld {
|
||||
std::string levelname;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct Cl_LevelLoaded : public Message {
|
||||
Cl_LevelLoaded() : Message (CLMSG_LEVEL_LOADED) {
|
||||
}
|
||||
};
|
||||
Buffer &operator << (Buffer &b, const Cl_LevelLoaded &m) {
|
||||
return b << Uint8 (CLMSG_LEVEL_LOADED);
|
||||
}
|
||||
|
||||
struct Cl_ChangeField {
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct Cl_AddActor {
|
||||
|
||||
};
|
||||
|
||||
struct Cl_MoveActor {
|
||||
|
||||
};
|
||||
|
||||
struct Cl_FocusActor {
|
||||
|
||||
};
|
||||
|
||||
struct Cl_ShowText : public Message {
|
||||
Cl_ShowText() : Message(CLMSG_SHOW_TEXT) {
|
||||
}
|
||||
|
||||
string text;
|
||||
float duration;
|
||||
bool scrolling;
|
||||
bool interruptible;
|
||||
};
|
||||
|
||||
struct Cl_AddEffect {
|
||||
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct Cl_PlaySound {
|
||||
string soundname;
|
||||
float x, y;
|
||||
int priority;
|
||||
};
|
||||
|
||||
/* -------------------- Client class -------------------- */
|
||||
|
||||
enum ClientState {
|
||||
cls_idle,
|
||||
cls_preparing_game, // level loaded, currently updating the screen
|
||||
cls_game,
|
||||
cls_finished, // level finished, waiting for next one
|
||||
cls_gamehelp,
|
||||
cls_gamemenu,
|
||||
cls_abort,
|
||||
cls_error
|
||||
};
|
||||
|
||||
|
||||
class Client {
|
||||
public:
|
||||
Client();
|
||||
~Client();
|
||||
|
||||
void tick (double dtime);
|
||||
void stop() { m_state = cls_idle; }
|
||||
bool network_start();
|
||||
void network_stop();
|
||||
|
||||
|
||||
void handle_message(Message *msg);
|
||||
|
||||
void level_loaded(bool isRestart);
|
||||
void level_finished();
|
||||
|
||||
void error (const std::string &text);
|
||||
|
||||
void abort() { m_state = cls_abort; }
|
||||
bool abort_p() const { return m_state == cls_abort; }
|
||||
|
||||
void mark_cheater() { m_cheater = true; }
|
||||
void easy_going() { m_hunt_against_time = false; }
|
||||
private:
|
||||
|
||||
std::string init_hunted_time();
|
||||
|
||||
|
||||
/* ---------- Private methods ---------- */
|
||||
|
||||
void show_menu();
|
||||
void show_help();
|
||||
|
||||
// Screen update (state dependant)
|
||||
void draw_screen();
|
||||
|
||||
// Event handling
|
||||
void handle_events();
|
||||
void on_keydown(SDL_Event &e);
|
||||
void on_mousebutton(SDL_Event &e);
|
||||
void update_mouse_button_state();
|
||||
|
||||
// Inventory & command line
|
||||
void rotate_inventory(int direction);
|
||||
|
||||
void process_userinput();
|
||||
void user_input_append (char c);
|
||||
void user_input_backspace ();
|
||||
void user_input_previous ();
|
||||
void user_input_next ();
|
||||
|
||||
|
||||
// Variables
|
||||
ClientState m_state;
|
||||
string m_levelname;
|
||||
double m_timeaccu;
|
||||
|
||||
double m_total_game_time;
|
||||
int m_hunt_against_time;
|
||||
bool m_cheater;
|
||||
|
||||
string m_user_input;
|
||||
string m_error_message;
|
||||
|
||||
std::auto_ptr<video::TransitionEffect> m_effect;
|
||||
ENetHost *m_network_host;
|
||||
ENetPeer *m_server;
|
||||
|
||||
private:
|
||||
Client (const Client&);
|
||||
Client &operator = (const Client &);
|
||||
};
|
||||
}
|
||||
|
||||
323
project/jni/application/enigma/src/config.h
Normal file
323
project/jni/application/enigma/src/config.h
Normal file
@@ -0,0 +1,323 @@
|
||||
/* src/config.h. Generated from config.h.in by configure. */
|
||||
/* src/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* android paths */
|
||||
#define SYSTEM_DATA_DIR "."
|
||||
#define LOCALEDIR "."
|
||||
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
/* #undef CRAY_STACKSEG_END */
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
/* #undef C_ALLOCA */
|
||||
|
||||
/* Include experimental features */
|
||||
/* #undef ENABLE_EXPERIMENTAL */
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#define ENABLE_NLS 1
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#define HAVE_ALLOCA 1
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#define HAVE_ALLOCA_H 1
|
||||
|
||||
/* Define to 1 if you have the <argz.h> header file. */
|
||||
/* #undef HAVE_ARGZ_H */
|
||||
|
||||
/* Define to 1 if you have the `asprintf' function. */
|
||||
#define HAVE_ASPRINTF 1
|
||||
|
||||
/* Define if the GNU dcgettext() function is already present or preinstalled.
|
||||
*/
|
||||
/* #undef HAVE_DCGETTEXT */
|
||||
|
||||
/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_FEOF_UNLOCKED 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
|
||||
you don't. */
|
||||
#define HAVE_DECL_FGETS_UNLOCKED 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_GETC_UNLOCKED 1
|
||||
|
||||
/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL__SNPRINTF 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `_snwprintf', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL__SNWPRINTF 0
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#define HAVE_DIRENT_H 1
|
||||
|
||||
/* Define to 1 if you have the `fwprintf' function. */
|
||||
#define HAVE_FWPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the `getcwd' function. */
|
||||
#define HAVE_GETCWD 1
|
||||
|
||||
/* Define to 1 if you have the `getegid' function. */
|
||||
#define HAVE_GETEGID 1
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#define HAVE_GETEUID 1
|
||||
|
||||
/* Define to 1 if you have the `getgid' function. */
|
||||
#define HAVE_GETGID 1
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
/* #undef HAVE_GETPAGESIZE */
|
||||
|
||||
/* Define if the GNU gettext() function is already present or preinstalled. */
|
||||
/* #undef HAVE_GETTEXT */
|
||||
|
||||
/* Define to 1 if you have the `getuid' function. */
|
||||
#define HAVE_GETUID 1
|
||||
|
||||
/* Define if you have the iconv() function. */
|
||||
#define HAVE_ICONV 1
|
||||
|
||||
/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
|
||||
#define HAVE_INTMAX_T 1
|
||||
|
||||
/* Define if <inttypes.h> exists and doesn't clash with <sys/types.h>. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
|
||||
declares uintmax_t. */
|
||||
#define HAVE_INTTYPES_H_WITH_UINTMAX 1
|
||||
|
||||
/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
|
||||
/* #undef HAVE_LANGINFO_CODESET */
|
||||
|
||||
/* Define if your <locale.h> file defines LC_MESSAGES. */
|
||||
#define HAVE_LC_MESSAGES 1
|
||||
|
||||
/* Define to 1 if you have the `png' library (-lpng). */
|
||||
#define HAVE_LIBPNG 1
|
||||
|
||||
/* Define to 1 if you have the `png12' library (-lpng12). */
|
||||
/* #undef HAVE_LIBPNG12 */
|
||||
|
||||
/* Define to 1 if you have the `SDL_image' library (-lSDL_image). */
|
||||
#define HAVE_LIBSDL_IMAGE 1
|
||||
|
||||
/* Define to 1 if you have the `SDL_mixer' library (-lSDL_mixer). */
|
||||
#define HAVE_LIBSDL_MIXER 1
|
||||
|
||||
/* Define to 1 if you have the `SDL_ttf' library (-lSDL_ttf). */
|
||||
#define HAVE_LIBSDL_TTF 1
|
||||
|
||||
/* Define to 1 if you have the `winmm' library (-lwinmm). */
|
||||
/* #undef HAVE_LIBWINMM */
|
||||
|
||||
/* Define to 1 if you have the `xerces-c' library (-lxerces-c). */
|
||||
#define HAVE_LIBXERCES_C 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#define HAVE_LOCALE_H 1
|
||||
|
||||
/* Define if you have the 'long double' type. */
|
||||
#define HAVE_LONG_DOUBLE 1
|
||||
|
||||
/* Define if you have the 'long long' type. */
|
||||
#define HAVE_LONG_LONG 1
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#define HAVE_MALLOC_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `mempcpy' function. */
|
||||
/* #undef HAVE_MEMPCPY */
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
/* #undef HAVE_MMAP */
|
||||
|
||||
/* Define to 1 if you have the `munmap' function. */
|
||||
#define HAVE_MUNMAP 1
|
||||
|
||||
/* Define to 1 if you have the <nl_types.h> header file. */
|
||||
/* #undef HAVE_NL_TYPES_H */
|
||||
|
||||
/* Define if your printf() function supports format strings with positions. */
|
||||
#define HAVE_POSIX_PRINTF 1
|
||||
|
||||
/* Define to 1 if you have the `putenv' function. */
|
||||
#define HAVE_PUTENV 1
|
||||
|
||||
/* Define to 1 if you have the `setenv' function. */
|
||||
#define HAVE_SETENV 1
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#define HAVE_SETLOCALE 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#define HAVE_SNPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#define HAVE_STDDEF_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
|
||||
uintmax_t. */
|
||||
#define HAVE_STDINT_H_WITH_UINTMAX 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `stpcpy' function. */
|
||||
/* #undef HAVE_STPCPY */
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#define HAVE_STRCASECMP 1
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#define HAVE_STRTOUL 1
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#define HAVE_SYS_PARAM_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `tsearch' function. */
|
||||
/* #undef HAVE_TSEARCH */
|
||||
|
||||
/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
|
||||
#define HAVE_UINTMAX_T 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define if you have the 'unsigned long long' type. */
|
||||
#define HAVE_UNSIGNED_LONG_LONG 1
|
||||
|
||||
/* Define if you have the 'wchar_t' type. */
|
||||
#define HAVE_WCHAR_T 1
|
||||
|
||||
/* Define to 1 if you have the `wcslen' function. */
|
||||
#define HAVE_WCSLEN 1
|
||||
|
||||
/* Define if you have the 'wint_t' type. */
|
||||
#define HAVE_WINT_T 1
|
||||
|
||||
/* Define to 1 if you have the `__argz_count' function. */
|
||||
/* #undef HAVE___ARGZ_COUNT */
|
||||
|
||||
/* Define to 1 if you have the `__argz_next' function. */
|
||||
/* #undef HAVE___ARGZ_NEXT */
|
||||
|
||||
/* Define to 1 if you have the `__argz_stringify' function. */
|
||||
/* #undef HAVE___ARGZ_STRINGIFY */
|
||||
|
||||
/* Define to 1 if you have the `__fsetlocking' function. */
|
||||
/* #undef HAVE___FSETLOCKING */
|
||||
|
||||
/* Define as const if the declaration of iconv() needs const. */
|
||||
#define ICONV_CONST const
|
||||
|
||||
/* Define if integer division by zero raises signal SIGFPE. */
|
||||
#define INTDIV0_RAISES_SIGFPE 0
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
/* #undef NO_MINUS_C_MINUS_O */
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT ""
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "enigma"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "enigma 1.01"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "enigma"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.01"
|
||||
|
||||
/* Define if <inttypes.h> exists and defines unusable PRI* macros. */
|
||||
/* #undef PRI_MACROS_BROKEN */
|
||||
|
||||
/* Whether SDL_image library provides init */
|
||||
#define SDL_IMG_INIT
|
||||
|
||||
/* Whether SDL_mixer library provides init */
|
||||
#define SDL_MIX_INIT
|
||||
|
||||
/* Define as the maximum value of type 'size_t', if the system doesn't define
|
||||
it. */
|
||||
/* #undef SIZE_MAX */
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
/* #undef STACK_DIRECTION */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
/* #undef off_t */
|
||||
|
||||
/* Define as the type of the result of subtracting two pointers, if the system
|
||||
doesn't define it. */
|
||||
/* #undef ptrdiff_t */
|
||||
|
||||
/* Define to empty if the C compiler doesn't support this keyword. */
|
||||
/* #undef signed */
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* Define to unsigned long or unsigned long long if <stdint.h> and
|
||||
<inttypes.h> don't define. */
|
||||
/* #undef uintmax_t */
|
||||
317
project/jni/application/enigma/src/config.h.in
Normal file
317
project/jni/application/enigma/src/config.h.in
Normal file
@@ -0,0 +1,317 @@
|
||||
/* src/config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Include experimental features */
|
||||
#undef ENABLE_EXPERIMENTAL
|
||||
|
||||
/* Define to 1 if translation of program messages to the user's native
|
||||
language is requested. */
|
||||
#undef ENABLE_NLS
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define to 1 if you have the <argz.h> header file. */
|
||||
#undef HAVE_ARGZ_H
|
||||
|
||||
/* Define to 1 if you have the `asprintf' function. */
|
||||
#undef HAVE_ASPRINTF
|
||||
|
||||
/* Define if the GNU dcgettext() function is already present or preinstalled.
|
||||
*/
|
||||
#undef HAVE_DCGETTEXT
|
||||
|
||||
/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_FEOF_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
|
||||
you don't. */
|
||||
#undef HAVE_DECL_FGETS_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL_GETC_UNLOCKED
|
||||
|
||||
/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL__SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the declaration of `_snwprintf', and to 0 if you
|
||||
don't. */
|
||||
#undef HAVE_DECL__SNWPRINTF
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file. */
|
||||
#undef HAVE_DIRENT_H
|
||||
|
||||
/* Define to 1 if you have the `fwprintf' function. */
|
||||
#undef HAVE_FWPRINTF
|
||||
|
||||
/* Define to 1 if you have the `getcwd' function. */
|
||||
#undef HAVE_GETCWD
|
||||
|
||||
/* Define to 1 if you have the `getegid' function. */
|
||||
#undef HAVE_GETEGID
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
#undef HAVE_GETEUID
|
||||
|
||||
/* Define to 1 if you have the `getgid' function. */
|
||||
#undef HAVE_GETGID
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#undef HAVE_GETPAGESIZE
|
||||
|
||||
/* Define if the GNU gettext() function is already present or preinstalled. */
|
||||
#undef HAVE_GETTEXT
|
||||
|
||||
/* Define to 1 if you have the `getuid' function. */
|
||||
#undef HAVE_GETUID
|
||||
|
||||
/* Define if you have the iconv() function. */
|
||||
#undef HAVE_ICONV
|
||||
|
||||
/* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
|
||||
#undef HAVE_INTMAX_T
|
||||
|
||||
/* Define if <inttypes.h> exists and doesn't clash with <sys/types.h>. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
|
||||
declares uintmax_t. */
|
||||
#undef HAVE_INTTYPES_H_WITH_UINTMAX
|
||||
|
||||
/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
|
||||
#undef HAVE_LANGINFO_CODESET
|
||||
|
||||
/* Define if your <locale.h> file defines LC_MESSAGES. */
|
||||
#undef HAVE_LC_MESSAGES
|
||||
|
||||
/* Define to 1 if you have the `png' library (-lpng). */
|
||||
#undef HAVE_LIBPNG
|
||||
|
||||
/* Define to 1 if you have the `png12' library (-lpng12). */
|
||||
#undef HAVE_LIBPNG12
|
||||
|
||||
/* Define to 1 if you have the `SDL_image' library (-lSDL_image). */
|
||||
#undef HAVE_LIBSDL_IMAGE
|
||||
|
||||
/* Define to 1 if you have the `SDL_mixer' library (-lSDL_mixer). */
|
||||
#undef HAVE_LIBSDL_MIXER
|
||||
|
||||
/* Define to 1 if you have the `SDL_ttf' library (-lSDL_ttf). */
|
||||
#undef HAVE_LIBSDL_TTF
|
||||
|
||||
/* Define to 1 if you have the `winmm' library (-lwinmm). */
|
||||
#undef HAVE_LIBWINMM
|
||||
|
||||
/* Define to 1 if you have the `xerces-c' library (-lxerces-c). */
|
||||
#undef HAVE_LIBXERCES_C
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#undef HAVE_LIMITS_H
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#undef HAVE_LOCALE_H
|
||||
|
||||
/* Define if you have the 'long double' type. */
|
||||
#undef HAVE_LONG_DOUBLE
|
||||
|
||||
/* Define if you have the 'long long' type. */
|
||||
#undef HAVE_LONG_LONG
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `mempcpy' function. */
|
||||
#undef HAVE_MEMPCPY
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#undef HAVE_MMAP
|
||||
|
||||
/* Define to 1 if you have the `munmap' function. */
|
||||
#undef HAVE_MUNMAP
|
||||
|
||||
/* Define to 1 if you have the <nl_types.h> header file. */
|
||||
#undef HAVE_NL_TYPES_H
|
||||
|
||||
/* Define if your printf() function supports format strings with positions. */
|
||||
#undef HAVE_POSIX_PRINTF
|
||||
|
||||
/* Define to 1 if you have the `putenv' function. */
|
||||
#undef HAVE_PUTENV
|
||||
|
||||
/* Define to 1 if you have the `setenv' function. */
|
||||
#undef HAVE_SETENV
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
|
||||
uintmax_t. */
|
||||
#undef HAVE_STDINT_H_WITH_UINTMAX
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `stpcpy' function. */
|
||||
#undef HAVE_STPCPY
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#undef HAVE_STRDUP
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#undef HAVE_STRTOUL
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the `tsearch' function. */
|
||||
#undef HAVE_TSEARCH
|
||||
|
||||
/* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
|
||||
#undef HAVE_UINTMAX_T
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define if you have the 'unsigned long long' type. */
|
||||
#undef HAVE_UNSIGNED_LONG_LONG
|
||||
|
||||
/* Define if you have the 'wchar_t' type. */
|
||||
#undef HAVE_WCHAR_T
|
||||
|
||||
/* Define to 1 if you have the `wcslen' function. */
|
||||
#undef HAVE_WCSLEN
|
||||
|
||||
/* Define if you have the 'wint_t' type. */
|
||||
#undef HAVE_WINT_T
|
||||
|
||||
/* Define to 1 if you have the `__argz_count' function. */
|
||||
#undef HAVE___ARGZ_COUNT
|
||||
|
||||
/* Define to 1 if you have the `__argz_next' function. */
|
||||
#undef HAVE___ARGZ_NEXT
|
||||
|
||||
/* Define to 1 if you have the `__argz_stringify' function. */
|
||||
#undef HAVE___ARGZ_STRINGIFY
|
||||
|
||||
/* Define to 1 if you have the `__fsetlocking' function. */
|
||||
#undef HAVE___FSETLOCKING
|
||||
|
||||
/* Define as const if the declaration of iconv() needs const. */
|
||||
#undef ICONV_CONST
|
||||
|
||||
/* Define if integer division by zero raises signal SIGFPE. */
|
||||
#undef INTDIV0_RAISES_SIGFPE
|
||||
|
||||
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
|
||||
#undef NO_MINUS_C_MINUS_O
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define if <inttypes.h> exists and defines unusable PRI* macros. */
|
||||
#undef PRI_MACROS_BROKEN
|
||||
|
||||
/* Whether SDL_image library provides init */
|
||||
#undef SDL_IMG_INIT
|
||||
|
||||
/* Whether SDL_mixer library provides init */
|
||||
#undef SDL_MIX_INIT
|
||||
|
||||
/* Define as the maximum value of type 'size_t', if the system doesn't define
|
||||
it. */
|
||||
#undef SIZE_MAX
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
#undef STACK_DIRECTION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# undef _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
#undef off_t
|
||||
|
||||
/* Define as the type of the result of subtracting two pointers, if the system
|
||||
doesn't define it. */
|
||||
#undef ptrdiff_t
|
||||
|
||||
/* Define to empty if the C compiler doesn't support this keyword. */
|
||||
#undef signed
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to unsigned long or unsigned long long if <stdint.h> and
|
||||
<inttypes.h> don't define. */
|
||||
#undef uintmax_t
|
||||
480
project/jni/application/enigma/src/d_engine.hh
Normal file
480
project/jni/application/enigma/src/d_engine.hh
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef D_ENGINE_HH
|
||||
#define D_ENGINE_HH
|
||||
|
||||
#include "ecl_geom.hh"
|
||||
#include "ecl_array2.hh"
|
||||
#include "ecl_alist.hh"
|
||||
#include "ecl_fwd.hh"
|
||||
|
||||
namespace display
|
||||
{
|
||||
|
||||
/* -------------------- DisplayEngine -------------------- */
|
||||
|
||||
class DisplayEngine {
|
||||
public:
|
||||
DisplayEngine (int tilew=32, int tileh=32);
|
||||
~DisplayEngine();
|
||||
|
||||
/* ---------- Class configuration ---------- */
|
||||
void add_layer (DisplayLayer *l);
|
||||
void set_screen_area (const ecl::Rect & r);
|
||||
void set_tilesize (int w, int h);
|
||||
|
||||
int get_tilew () const { return m_tilew; }
|
||||
int get_tileh () const { return m_tileh; }
|
||||
int get_width() const { return m_width; }
|
||||
int get_height() const { return m_height; }
|
||||
const ecl::Rect &get_area() const { return m_area; }
|
||||
|
||||
/* ---------- Scrolling / page flipping ---------- */
|
||||
void set_offset (const ecl::V2 &off);
|
||||
void move_offset (const ecl::V2 &off);
|
||||
ecl::V2 get_offset () const { return m_offset; }
|
||||
|
||||
/* ---------- Game-related stuff ---------- */
|
||||
void new_world (int w, int h);
|
||||
void tick (double dtime);
|
||||
|
||||
/* ---------- Coordinate conversion ---------- */
|
||||
void world_to_screen (const ecl::V2 & pos, int *x, int *y);
|
||||
WorldArea screen_to_world (const ScreenArea &a);
|
||||
ScreenArea world_to_screen (const WorldArea &a);
|
||||
|
||||
/* "Video" coordinates are like screen coordinates, except the
|
||||
origin coincides with the world origin, not the current
|
||||
scrolling position. */
|
||||
void world_to_video (const ecl::V2 &pos, int *x, int *y);
|
||||
void video_to_screen (int x, int y, int *xx, int *yy);
|
||||
void video_to_world (const ecl::Rect &r, ecl::Rect &s);
|
||||
|
||||
V2 to_world (const V2 &pos);
|
||||
|
||||
/* ---------- Screen upates ---------- */
|
||||
|
||||
void mark_redraw_screen();
|
||||
void mark_redraw_area (const WorldArea &wa, int delay=0);
|
||||
|
||||
void redraw_screen_area (const ScreenArea &a);
|
||||
void redraw_world_area (const WorldArea &a);
|
||||
|
||||
void update_screen();
|
||||
void draw_all (ecl::GC &gc);
|
||||
void update_offset();
|
||||
|
||||
private:
|
||||
void update_layer (DisplayLayer *l, WorldArea wa);
|
||||
|
||||
/* ---------- Variables ---------- */
|
||||
|
||||
std::vector<DisplayLayer *> m_layers;
|
||||
int m_tilew, m_tileh;
|
||||
|
||||
// Offset of screen
|
||||
ecl::V2 m_offset; // Offset in world units
|
||||
ecl::V2 m_new_offset; // New offset in world units
|
||||
int m_screenoffset[2]; // Offset in screen units
|
||||
|
||||
|
||||
// Screen area occupied by level display
|
||||
ecl::Rect m_area;
|
||||
|
||||
// Width and height of the world in tiles
|
||||
int m_width, m_height;
|
||||
|
||||
ecl::Array2<char> m_redrawp;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- DisplayLayer -------------------- */
|
||||
|
||||
class DisplayLayer {
|
||||
public:
|
||||
DisplayLayer() {}
|
||||
virtual ~DisplayLayer() {}
|
||||
|
||||
/* ---------- Class configuration ---------- */
|
||||
void set_engine (DisplayEngine *e) { m_engine = e; }
|
||||
DisplayEngine *get_engine() const { return m_engine; }
|
||||
|
||||
/* ---------- DisplayLayer interface ---------- */
|
||||
virtual void prepare_draw (const WorldArea &) {}
|
||||
virtual void draw (ecl::GC &gc, const WorldArea &a, int x, int y) = 0;
|
||||
virtual void draw_onepass (ecl::GC &/*gc*/) {}
|
||||
virtual void tick (double /*dtime*/) {}
|
||||
virtual void new_world (int /*w*/, int /*h*/) {}
|
||||
|
||||
// Functions.
|
||||
void mark_redraw_area (const ecl::Rect &r)
|
||||
{
|
||||
get_engine()->mark_redraw_area(r);
|
||||
}
|
||||
private:
|
||||
DisplayEngine *m_engine;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- ModelLayer -------------------- */
|
||||
|
||||
/*! The base class for all layers that contains Models. */
|
||||
class ModelLayer : public DisplayLayer {
|
||||
public:
|
||||
ModelLayer() {}
|
||||
|
||||
// DisplayLayer interface
|
||||
void tick (double dtime);
|
||||
void new_world (int, int);
|
||||
|
||||
// Member functions
|
||||
void activate (Model *m);
|
||||
void deactivate (Model *m);
|
||||
void maybe_redraw_model(Model *m, bool immediately=false);
|
||||
|
||||
virtual int redraw_size () const { return 2; }
|
||||
private:
|
||||
|
||||
// Variables
|
||||
ModelList m_active_models;
|
||||
ModelList m_active_models_new;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- DL_Grid -------------------- */
|
||||
|
||||
/*! Layer for grid-aligned models (stones, floor tiles, items). */
|
||||
|
||||
class DL_Grid : public ModelLayer {
|
||||
public:
|
||||
DL_Grid(int redrawsize = 1);
|
||||
~DL_Grid();
|
||||
|
||||
void set_model (int x, int y, Model *m);
|
||||
Model *get_model (int x, int y);
|
||||
Model *yield_model (int x, int y);
|
||||
|
||||
private:
|
||||
// DL_Grid interface.
|
||||
void mark_redraw (int x, int y);
|
||||
|
||||
// DisplayLayer interface.
|
||||
void new_world (int w, int h);
|
||||
void draw (ecl::GC &gc, const WorldArea &a, int x, int y);
|
||||
|
||||
// ModelLayer interface
|
||||
virtual int redraw_size () const { return m_redrawsize; }
|
||||
|
||||
// Variables.
|
||||
typedef ecl::Array2<Model*> ModelArray;
|
||||
ModelArray m_models;
|
||||
int m_redrawsize;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- Sprites -------------------- */
|
||||
|
||||
class Sprite : public ecl::Nocopy {
|
||||
public:
|
||||
Model *model;
|
||||
V2 pos;
|
||||
int screenpos[2];
|
||||
SpriteLayer layer;
|
||||
bool visible;
|
||||
bool mayNeedRedraw;
|
||||
|
||||
Sprite (const V2 & p, SpriteLayer l, Model *m)
|
||||
: model(m), pos(p), layer(l), visible(true), mayNeedRedraw(false)
|
||||
{
|
||||
screenpos[0] = screenpos[1] = 0;
|
||||
}
|
||||
~Sprite() { delete model; }
|
||||
};
|
||||
|
||||
typedef std::vector<Sprite*> SpriteList;
|
||||
|
||||
class DL_Sprites : public ModelLayer {
|
||||
public:
|
||||
DL_Sprites();
|
||||
~DL_Sprites();
|
||||
|
||||
/* ---------- DisplayLayer interface ---------- */
|
||||
void draw (ecl::GC &gc, const WorldArea &a, int x, int y);
|
||||
void draw_onepass (ecl::GC &gc);
|
||||
void new_world (int, int);
|
||||
|
||||
/* ---------- Member functions ---------- */
|
||||
SpriteId add_sprite (Sprite *sprite);
|
||||
void kill_sprite (SpriteId id);
|
||||
void move_sprite (SpriteId, const ecl::V2& newpos);
|
||||
void replace_sprite (SpriteId id, Model *m);
|
||||
|
||||
void redraw_sprite_region (SpriteId id);
|
||||
void draw_sprites (bool shades, ecl::GC &gc);
|
||||
|
||||
Model *get_model (SpriteId id) { return sprites[id]->model; }
|
||||
|
||||
void set_maxsprites (unsigned m) { maxsprites = m; }
|
||||
|
||||
Sprite *get_sprite(SpriteId id);
|
||||
|
||||
static const SpriteId MAGIC_SPRITEID = 1000000;
|
||||
SpriteList sprites;
|
||||
|
||||
private:
|
||||
// ModelLayer interface
|
||||
virtual void tick (double /*dtime*/);
|
||||
|
||||
// Variables.
|
||||
unsigned numsprites; // Current number of sprites
|
||||
unsigned maxsprites; // Maximum number of sprites
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- Shadows -------------------- */
|
||||
|
||||
struct StoneShadowCache;
|
||||
|
||||
class DL_Shadows : public DisplayLayer {
|
||||
public:
|
||||
DL_Shadows(DL_Grid *grid, DL_Sprites *sprites);
|
||||
~DL_Shadows();
|
||||
|
||||
void new_world(int w, int h);
|
||||
void draw (ecl::GC &gc, int xpos, int ypos, int x, int y);
|
||||
|
||||
void draw (ecl::GC &gc, const WorldArea &a, int x, int y);
|
||||
private:
|
||||
/* ---------- Private functions ---------- */
|
||||
void shadow_blit (ecl::Surface *scr, int x, int y,
|
||||
ecl::Surface *shadows, ecl::Rect r);
|
||||
|
||||
bool has_actor (int x, int y);
|
||||
virtual void prepare_draw (const WorldArea &);
|
||||
|
||||
Model * get_shadow_model(int x, int y);
|
||||
|
||||
/* ---------- Variables ---------- */
|
||||
DL_Grid *m_grid; // Stone models
|
||||
DL_Sprites *m_sprites; // Sprite models
|
||||
|
||||
StoneShadowCache *m_cache;
|
||||
|
||||
Uint32 shadow_ckey; // Color key
|
||||
ecl::Surface *buffer;
|
||||
|
||||
ecl::Array2<bool> m_hasactor;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- Lines -------------------- */
|
||||
|
||||
struct Line {
|
||||
V2 start,end;
|
||||
V2 oldstart, oldend;
|
||||
|
||||
Line(const V2 &s, const V2 &e) :start(s), end(e) {}
|
||||
Line() {}
|
||||
};
|
||||
|
||||
|
||||
typedef ecl::AssocList<unsigned, Line> LineMap;
|
||||
|
||||
class DL_Lines : public DisplayLayer {
|
||||
public:
|
||||
DL_Lines() : m_id(1)
|
||||
{
|
||||
}
|
||||
|
||||
void draw (ecl::GC &/*gc*/, const WorldArea &/*a*/, int /*x*/, int /*y*/)
|
||||
{}
|
||||
void draw_onepass (ecl::GC &gc);
|
||||
|
||||
RubberHandle add_line (const V2 &p1, const V2 &p2);
|
||||
void set_startpoint (unsigned id, const V2 &p1);
|
||||
void set_endpoint (unsigned id, const V2 &p2);
|
||||
void kill_line (unsigned id);
|
||||
|
||||
private:
|
||||
// Private methods.
|
||||
void mark_redraw_line (const Line &r);
|
||||
|
||||
// Variables.
|
||||
unsigned m_id;
|
||||
LineMap m_rubbers;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- CommonDisplay -------------------- */
|
||||
|
||||
/*! Parts of the display engine that are common to the game and
|
||||
the editor. */
|
||||
class CommonDisplay {
|
||||
public:
|
||||
CommonDisplay (const ScreenArea &a = ScreenArea (0, 0, 10, 10));
|
||||
~CommonDisplay();
|
||||
|
||||
Model *set_model (const GridLoc &l, Model *m);
|
||||
Model *get_model (const GridLoc &l);
|
||||
Model *yield_model (const GridLoc &l);
|
||||
|
||||
void set_floor (int x, int y, Model *m);
|
||||
void set_item (int x, int y, Model *m);
|
||||
void set_stone (int x, int y, Model *m);
|
||||
|
||||
DisplayEngine *get_engine() const { return m_engine; }
|
||||
|
||||
SpriteHandle add_effect (const V2& pos, Model *m);
|
||||
SpriteHandle add_sprite (const V2 &pos, Model *m);
|
||||
|
||||
RubberHandle add_line (V2 p1, V2 p2);
|
||||
|
||||
void new_world (int w, int h);
|
||||
void redraw();
|
||||
|
||||
protected:
|
||||
DL_Grid *floor_layer;
|
||||
DL_Grid *item_layer;
|
||||
DL_Grid *stone_layer;
|
||||
|
||||
DL_Sprites *effects_layer;
|
||||
|
||||
DL_Lines *line_layer;
|
||||
DL_Sprites *sprite_layer;
|
||||
DL_Shadows *shadow_layer;
|
||||
|
||||
private:
|
||||
|
||||
DisplayEngine *m_engine;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- Scrolling -------------------- */
|
||||
|
||||
|
||||
class Follower {
|
||||
public:
|
||||
Follower (DisplayEngine *e);
|
||||
virtual ~Follower() {}
|
||||
virtual void tick(double dtime, const ecl::V2 &point) = 0;
|
||||
virtual void center(const ecl::V2 &point);
|
||||
|
||||
void set_boundary (double b) { m_boundary = b; }
|
||||
|
||||
protected:
|
||||
DisplayEngine *get_engine() const { return m_engine; }
|
||||
bool set_offset (V2 offs);
|
||||
double get_hoff() const;
|
||||
double get_voff() const;
|
||||
ecl::V2 get_scrollpos(const ecl::V2 &point);
|
||||
|
||||
double m_boundary;
|
||||
|
||||
private:
|
||||
DisplayEngine *m_engine;
|
||||
};
|
||||
|
||||
/*! Follows a sprite by flipping to the next screen as soon as the
|
||||
sprite reaches the border of the current screen. */
|
||||
class Follower_Screen : public Follower {
|
||||
public:
|
||||
Follower_Screen(DisplayEngine *e);
|
||||
void tick(double dtime, const ecl::V2 &point);
|
||||
};
|
||||
|
||||
/*! Follows a sprite by softly scrolling the visible area of the
|
||||
screen as soon as the sprite reaches the border of the current
|
||||
screen. */
|
||||
class Follower_Scrolling : public Follower {
|
||||
public:
|
||||
Follower_Scrolling (DisplayEngine *e, bool screenwise_);
|
||||
void tick(double dtime, const ecl::V2 &point);
|
||||
void center(const ecl::V2 &point);
|
||||
private:
|
||||
bool currently_scrolling;
|
||||
V2 curpos, destpos;
|
||||
V2 dir;
|
||||
double scrollspeed;
|
||||
double resttime;
|
||||
bool screenwise;
|
||||
};
|
||||
|
||||
class Follower_Smooth : public Follower {
|
||||
public:
|
||||
Follower_Smooth (DisplayEngine *e);
|
||||
void tick (double time, const ecl::V2 &point);
|
||||
void center (const ecl::V2 &point);
|
||||
virtual void set_boundary (double b) {}
|
||||
|
||||
ecl::V2 calc_offset (const ecl::V2 &point);
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- GameDisplay -------------------- */
|
||||
|
||||
class GameDisplay : public CommonDisplay {
|
||||
public:
|
||||
GameDisplay (const ScreenArea &gamearea,
|
||||
const ScreenArea &inventoryarea);
|
||||
~GameDisplay();
|
||||
|
||||
StatusBar * get_status_bar() const;
|
||||
|
||||
void tick(double dtime);
|
||||
void new_world (int w, int h);
|
||||
|
||||
void resize_game_area (int w, int h);
|
||||
|
||||
/* ---------- Scrolling ---------- */
|
||||
void set_follow_mode (FollowMode m);
|
||||
void follow_center();
|
||||
void set_follow_sprite(SpriteId id);
|
||||
void set_reference_point (const ecl::V2 &point);
|
||||
void set_scroll_boundary (double d);
|
||||
|
||||
// current screen coordinates of reference point
|
||||
void get_reference_point_coordinates(int *x, int *y);
|
||||
|
||||
/* ---------- Screen updates ---------- */
|
||||
void redraw (ecl::Screen *scr);
|
||||
void redraw_all (ecl::Screen *scr);
|
||||
void draw_all (ecl::GC &gc);
|
||||
|
||||
private:
|
||||
void set_follower (Follower *f);
|
||||
void draw_borders (ecl::GC &gc);
|
||||
|
||||
/* ---------- Variables ---------- */
|
||||
Uint32 last_frame_time;
|
||||
bool redraw_everything;
|
||||
StatusBarImpl *status_bar;
|
||||
|
||||
V2 m_reference_point;
|
||||
Follower *m_follower;
|
||||
|
||||
ScreenArea inventoryarea;
|
||||
};
|
||||
|
||||
class ModelHandle {
|
||||
public:
|
||||
ModelHandle ();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
623
project/jni/application/enigma/src/d_models.cpp
Normal file
623
project/jni/application/enigma/src/d_models.cpp
Normal file
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2005 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "display_internal.hh"
|
||||
#include "d_models.hh"
|
||||
|
||||
#include "lua.hh"
|
||||
#include "options.hh"
|
||||
#include "d_engine.hh"
|
||||
#include "video.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "gui/ErrorMenu.hh"
|
||||
|
||||
#include "SDL_image.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
using namespace enigma;
|
||||
using namespace display;
|
||||
using namespace std;
|
||||
using namespace ecl;
|
||||
|
||||
#ifndef CXXLUA
|
||||
extern "C" {
|
||||
#include "lualib.h"
|
||||
#include "tolua++.h"
|
||||
}
|
||||
#else
|
||||
#include "lualib.h"
|
||||
#include "tolua++.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "lua-global.hh"
|
||||
#include "lua-display.hh"
|
||||
#include "lua-enigma.hh"
|
||||
#include "lua-ecl.hh"
|
||||
|
||||
/* -------------------- Types -------------------- */
|
||||
|
||||
namespace
|
||||
{
|
||||
class SurfaceCache_Alpha : public PtrCache<Surface>{
|
||||
public:
|
||||
Surface *acquire(const std::string &name);
|
||||
};
|
||||
|
||||
class SurfaceCache : public PtrCache<Surface>{
|
||||
public:
|
||||
Surface *acquire(const std::string &name);
|
||||
};
|
||||
|
||||
class ModelManager {
|
||||
public:
|
||||
ModelManager();
|
||||
~ModelManager();
|
||||
|
||||
void define (const std::string name, Model *m);
|
||||
|
||||
/* Create new model of type `name'. Returns 0 if no such
|
||||
model exists. */
|
||||
Model *create (const std::string &name);
|
||||
|
||||
/* Remove model definition for `name'. */
|
||||
void remove (const std::string &name);
|
||||
|
||||
bool has_model (const std::string &name) const;
|
||||
|
||||
size_t num_templates() const;
|
||||
|
||||
private:
|
||||
// Variables
|
||||
typedef ecl::Dict<Model*> ModelMap;
|
||||
ModelMap m_templates;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- SurfaceCache -------------------- */
|
||||
|
||||
Surface *SurfaceCache_Alpha::acquire(const std::string &name)
|
||||
{
|
||||
string filename;
|
||||
if (app.resourceFS->findImageFile (name + ".png", filename))
|
||||
return ecl::LoadImage(filename.c_str());
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Surface *SurfaceCache::acquire(const std::string &name)
|
||||
{
|
||||
string filename;
|
||||
if (app.resourceFS->findImageFile (name + ".png", filename)) {
|
||||
SDL_Surface *s = IMG_Load(filename.c_str());
|
||||
if (s) {
|
||||
SDL_Surface *img = 0;
|
||||
if (s->flags & SDL_SRCALPHA) {
|
||||
img = SDL_DisplayFormatAlpha(s);
|
||||
} else {
|
||||
SDL_SetColorKey(s, SDL_SRCCOLORKEY, //|SDL_RLEACCEL,
|
||||
SDL_MapRGB(s->format, 255,0,255));
|
||||
img = SDL_DisplayFormat(s);
|
||||
}
|
||||
if (img) {
|
||||
SDL_FreeSurface(s);
|
||||
return Surface::make_surface(img);
|
||||
}
|
||||
return Surface::make_surface(s);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- ModelManager -------------------- */
|
||||
|
||||
ModelManager::ModelManager()
|
||||
: m_templates (1069)
|
||||
{}
|
||||
|
||||
ModelManager::~ModelManager() {
|
||||
delete_map (m_templates.begin(), m_templates.end());
|
||||
}
|
||||
|
||||
void ModelManager::define (const std::string name, Model *m) {
|
||||
m_templates.insert (name, m);
|
||||
}
|
||||
|
||||
Model * ModelManager::create (const std::string &name) {
|
||||
ModelMap::iterator i = m_templates.find(name);
|
||||
|
||||
if (i != m_templates.end())
|
||||
return i->second->clone();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ModelManager::remove (const std::string &name)
|
||||
{
|
||||
ModelMap::iterator i = m_templates.find(name);
|
||||
if (i != m_templates.end()) {
|
||||
delete i->second;
|
||||
m_templates.remove (name);
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelManager::has_model (const std::string &name) const {
|
||||
return m_templates.has_key (name);
|
||||
}
|
||||
|
||||
size_t ModelManager::num_templates() const {
|
||||
return m_templates.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Variables -------------------- */
|
||||
|
||||
namespace
|
||||
{
|
||||
SurfaceCache surface_cache;
|
||||
SurfaceCache_Alpha surface_cache_alpha;
|
||||
ModelManager *modelmgr = 0;
|
||||
vector<Surface *> image_pile;
|
||||
string anim_templ_name;
|
||||
Anim2d *anim_templ = 0;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void display::InitModels()
|
||||
{
|
||||
modelmgr = new ModelManager;
|
||||
|
||||
lua_State *L = lua_open();
|
||||
luaL_openlibs(L);
|
||||
lua_register (L, "FindDataFile", lua::FindDataFile);
|
||||
tolua_open(L);
|
||||
tolua_global_open(L);
|
||||
tolua_enigma_open(L);
|
||||
tolua_display_open(L);
|
||||
tolua_px_open(L);
|
||||
|
||||
if (lua::DoSysFile(L, "compat.lua") != lua::NO_LUAERROR) {
|
||||
std::string message = ecl::strf("Error loading 'compat.lua'\nError: '%s'\n",
|
||||
lua::LastError(L).c_str());
|
||||
fprintf(stderr, message.c_str());
|
||||
gui::ErrorMenu m(message +
|
||||
_("\n\nThis error may cause the application to behave strange!")
|
||||
, N_("Continue"));
|
||||
m.manage();
|
||||
}
|
||||
|
||||
string fname;
|
||||
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
fname = app.systemFS->findFile (vminfo->initscript);
|
||||
if (lua::DoSysFile(L, vminfo->initscript) != lua::NO_LUAERROR) {
|
||||
std::string message = ecl::strf("Error loading '%s'\nError: '%s'\n",
|
||||
fname.c_str(), lua::LastError(L).c_str());
|
||||
fprintf(stderr, message.c_str());
|
||||
gui::ErrorMenu m(message +
|
||||
_("\n\nThis error may cause the application to behave strange!")
|
||||
, N_("Continue"));
|
||||
m.manage();
|
||||
}
|
||||
enigma::Log << "# models: " << modelmgr->num_templates() << endl;
|
||||
|
||||
surface_cache_alpha.clear();
|
||||
lua_close(L);
|
||||
}
|
||||
|
||||
void display::ShutdownModels()
|
||||
{
|
||||
delete modelmgr;
|
||||
surface_cache.clear();
|
||||
delete_sequence (image_pile.begin(), image_pile.end());
|
||||
image_pile.clear();
|
||||
anim_templ_name = "";
|
||||
anim_templ = 0;
|
||||
}
|
||||
|
||||
Surface *display::CropSurface (const Surface *s, Rect r) {
|
||||
return ecl::Grab(s, r);
|
||||
}
|
||||
|
||||
/* Register a new model template `m' under the name `name'. */
|
||||
void display::DefineModel (const char *name, Model *m)
|
||||
{
|
||||
if (modelmgr->has_model (name)) {
|
||||
enigma::Log << "Redefining model '" << name << "'\n";
|
||||
modelmgr->remove (name);
|
||||
}
|
||||
modelmgr->define (name, m);
|
||||
}
|
||||
|
||||
Model * display::MakeModel (const string &name)
|
||||
{
|
||||
if (Model *m = modelmgr->create (name))
|
||||
return m;
|
||||
else {
|
||||
enigma::Log << "Unknown model " << name << endl;
|
||||
return modelmgr->create ("dummy");
|
||||
}
|
||||
}
|
||||
|
||||
int display::DefineImage(const char *name, const char *fname,
|
||||
int xoff, int yoff, int padding)
|
||||
{
|
||||
ecl::Surface *sfc = surface_cache.get(fname);
|
||||
if (!sfc)
|
||||
return 1;
|
||||
|
||||
ecl::Rect r = sfc->size();
|
||||
r.x += padding; r.y += padding;
|
||||
r.w -= 2*padding; r.h -= 2*padding;
|
||||
DefineModel(name, new ImageModel(sfc, r, xoff+padding, yoff+padding));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void display::DefineImageModel (const char *name, ecl::Surface *s)
|
||||
{
|
||||
DefineModel (name, new ImageModel(s, 0, 0));
|
||||
}
|
||||
|
||||
int display::DefineSubImage(const char *name, const char *fname,
|
||||
int xoff, int yoff, ecl::Rect subrect)
|
||||
{
|
||||
ecl::Surface *sfc = surface_cache.get(fname);
|
||||
if (!sfc)
|
||||
return 1;
|
||||
|
||||
DefineModel(name, new ImageModel(sfc, subrect, xoff, yoff));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void display::DefineRandModel(const char *name, int n, char **names)
|
||||
{
|
||||
RandomModel *m = new RandomModel();
|
||||
for (int i=0; i<n; i++)
|
||||
m->add_model(names[i]);
|
||||
DefineModel(name, m);
|
||||
}
|
||||
|
||||
void display::DefineShadedModel (const char *name, const char *model, const char *shadow)
|
||||
{
|
||||
DefineModel(name, new ShadowModel(MakeModel(model), MakeModel(shadow)));
|
||||
}
|
||||
|
||||
|
||||
/* Create an image by overlaying several other images. The first entry in
|
||||
`images' is the name of the background image, the following images are
|
||||
drawn on top of it. */
|
||||
void display::DefineOverlayImage (const char *name, int n,
|
||||
char **images)
|
||||
{
|
||||
Surface *sfc = Duplicate(surface_cache.get(images[0]));
|
||||
if (sfc) {
|
||||
GC gc(sfc);
|
||||
for (int i=1; i<n; i++)
|
||||
blit (gc, 0,0, surface_cache_alpha.get(images[i]));
|
||||
DefineModel(name, new ImageModel(sfc, 0,0));
|
||||
image_pile.push_back(sfc); // make sure it gets destructed
|
||||
}
|
||||
}
|
||||
|
||||
void display::DefineComposite (const char *name, const char *bgname, const char *fgname)
|
||||
{
|
||||
DefineModel(name, new CompositeModel(MakeModel(bgname), MakeModel(fgname)));
|
||||
}
|
||||
|
||||
void display::DefineAnim (const char *name, bool loop_p) {
|
||||
anim_templ = new Anim2d(loop_p);
|
||||
DefineModel(name, anim_templ);
|
||||
anim_templ_name = name;
|
||||
}
|
||||
|
||||
void display::AddFrame (const char *name, const char *model, double time)
|
||||
{
|
||||
if (anim_templ_name != name)
|
||||
fprintf(stderr, "AddFrame: Cannot add frames to completed animations.");
|
||||
else
|
||||
anim_templ->add_frame(MakeModel(model), time / 1000.0);
|
||||
}
|
||||
|
||||
void display::DefineAlias (const char *name, const char *othername)
|
||||
{
|
||||
DefineModel(name, new AliasModel(othername));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Model -------------------- */
|
||||
void Model::get_extension (ecl::Rect &r)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Image -------------------- */
|
||||
|
||||
Image::Image(ecl::Surface *sfc)
|
||||
: surface(sfc), rect(surface->size()), refcount(1)
|
||||
{}
|
||||
|
||||
Image::Image(ecl::Surface *sfc, const ecl::Rect &r)
|
||||
: surface(sfc), rect(r), refcount(1)
|
||||
{}
|
||||
|
||||
|
||||
void display::incref(Image *i) {
|
||||
++i->refcount;
|
||||
}
|
||||
|
||||
void display::decref (Image *i) {
|
||||
if (-- i->refcount == 0) {
|
||||
delete i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void display::draw_image (Image *i, ecl::GC &gc, int x, int y)
|
||||
{
|
||||
blit(gc, x, y, i->surface, i->rect);
|
||||
}
|
||||
|
||||
/* -------------------- ImageModel -------------------- */
|
||||
|
||||
ImageModel::ImageModel (Image *i, int xo, int yo)
|
||||
: image(i), xoff(xo), yoff(yo)
|
||||
{
|
||||
assert(image);
|
||||
incref(image);
|
||||
}
|
||||
|
||||
ImageModel::ImageModel(Surface *s, int xo, int yo)
|
||||
: image(new Image(s)), xoff(xo), yoff(yo)
|
||||
{}
|
||||
|
||||
ImageModel::ImageModel(Surface *s, const ecl::Rect &r, int xo, int yo)
|
||||
: image(new Image(s, r)), xoff(xo), yoff(yo)
|
||||
{}
|
||||
|
||||
ImageModel::~ImageModel() {
|
||||
decref(image);
|
||||
}
|
||||
|
||||
void ImageModel::draw(ecl::GC &gc, int x, int y) {
|
||||
draw_image (image, gc, x+xoff, y+yoff);
|
||||
}
|
||||
|
||||
Model *ImageModel::clone() {
|
||||
return new ImageModel(image, xoff, yoff);
|
||||
}
|
||||
|
||||
void ImageModel::get_extension (ecl::Rect &r) {
|
||||
r.x = xoff;
|
||||
r.y = yoff;
|
||||
r.w = image->rect.w;
|
||||
r.h = image->rect.h;
|
||||
}
|
||||
|
||||
/* -------------------- ShadowModel -------------------- */
|
||||
|
||||
ShadowModel::ShadowModel (Model *m, Model *sh) {
|
||||
model=m; shade=sh;
|
||||
}
|
||||
|
||||
ShadowModel::~ShadowModel() {
|
||||
delete model; delete shade;
|
||||
}
|
||||
|
||||
void ShadowModel::expose (ModelLayer *ml, int vx, int vy) {
|
||||
model->expose(ml, vx, vy);
|
||||
shade->expose(ml, vx, vy);
|
||||
}
|
||||
void ShadowModel::remove (ModelLayer *ml) {
|
||||
shade->remove(ml);
|
||||
model->remove(ml);
|
||||
}
|
||||
|
||||
void ShadowModel::set_callback(ModelCallback *cb) {
|
||||
model->set_callback(cb);
|
||||
}
|
||||
|
||||
void ShadowModel::reverse() {
|
||||
model->reverse();
|
||||
shade->reverse();
|
||||
}
|
||||
|
||||
void ShadowModel::restart() {
|
||||
model->restart();
|
||||
shade->restart();
|
||||
}
|
||||
|
||||
void ShadowModel::draw(ecl::GC &gc, int x, int y) {
|
||||
model->draw(gc,x,y);
|
||||
}
|
||||
|
||||
void ShadowModel::draw_shadow(ecl::GC &gc, int x, int y) {
|
||||
shade->draw(gc,x,y);
|
||||
}
|
||||
|
||||
Model *ShadowModel::get_shadow() const {
|
||||
return shade;
|
||||
}
|
||||
|
||||
Model *ShadowModel::clone() {
|
||||
return new ShadowModel(model->clone(), shade->clone());
|
||||
}
|
||||
|
||||
void ShadowModel::get_extension (ecl::Rect &r) {
|
||||
ecl::Rect r1, r2;
|
||||
model->get_extension (r1);
|
||||
shade->get_extension (r2);
|
||||
r = boundingbox (r1, r2);
|
||||
}
|
||||
|
||||
/* -------------------- RandomModel -------------------- */
|
||||
|
||||
Model * RandomModel::clone() {
|
||||
if (!modelnames.empty()) {
|
||||
int r = enigma::IntegerRand(0, modelnames.size()-1);
|
||||
return MakeModel(modelnames[r]);
|
||||
} else {
|
||||
fprintf(stderr, "display_2d.cc: empty RandomModel\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------- AliasModel -------------------- */
|
||||
|
||||
Model * AliasModel::clone() {
|
||||
return MakeModel(name);
|
||||
}
|
||||
|
||||
/* -------------------- Anim2d -------------------- */
|
||||
|
||||
Anim2d::Anim2d(bool loop)
|
||||
: rep(new AnimRep(loop))
|
||||
{}
|
||||
|
||||
Anim2d::Anim2d (AnimRep *r)
|
||||
: rep(r), curframe(0), frametime(0),
|
||||
finishedp (false),
|
||||
changedp (false),
|
||||
reversep (false),
|
||||
videox (0), videoy (0),
|
||||
callback(0)
|
||||
{
|
||||
rep->refcount++;
|
||||
frametime = 0; // enigma::DoubleRand (0, 0.02);
|
||||
}
|
||||
|
||||
Anim2d::~Anim2d() {
|
||||
if (--rep->refcount == 0)
|
||||
delete rep;
|
||||
}
|
||||
|
||||
void Anim2d::restart () {
|
||||
finishedp = false; frametime = 0; curframe = 0; changedp = true;
|
||||
}
|
||||
|
||||
void Anim2d::add_frame(Model *m, double duration) {
|
||||
rep->frames.push_back(new AnimFrame(m, duration));
|
||||
}
|
||||
|
||||
void Anim2d::draw(ecl::GC &gc, int x, int y)
|
||||
{
|
||||
if (!finishedp) {
|
||||
AnimFrame *f =rep->frames[curframe];
|
||||
f->model->draw(gc,x,y);
|
||||
changedp = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Anim2d::draw_shadow (ecl::GC &gc, int x, int y)
|
||||
{
|
||||
if (!finishedp) {
|
||||
AnimFrame *f =rep->frames[curframe];
|
||||
f->model->draw_shadow(gc,x,y);
|
||||
}
|
||||
}
|
||||
|
||||
void Anim2d::expose (ModelLayer *ml, int vx, int vy) {
|
||||
ml->activate (this);
|
||||
videox = vx;
|
||||
videoy = vy;
|
||||
}
|
||||
|
||||
void Anim2d::remove (ModelLayer *ml) {
|
||||
ml->deactivate (this);
|
||||
}
|
||||
|
||||
bool Anim2d::has_changed (Rect &r) {
|
||||
bool retval = changedp;
|
||||
if (changedp) {
|
||||
get_extension (r);
|
||||
r.x += videox;
|
||||
r.y += videoy;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Anim2d::move (int newx, int newy) {
|
||||
videox = newx;
|
||||
videoy = newy;
|
||||
}
|
||||
|
||||
void Anim2d::get_extension (ecl::Rect &r) {
|
||||
AnimFrame *f =rep->frames[curframe];
|
||||
f->model->get_extension (r);
|
||||
}
|
||||
|
||||
void Anim2d::tick (double dtime)
|
||||
{
|
||||
assert(curframe < rep->frames.size());
|
||||
frametime += dtime;
|
||||
double framedur = rep->frames[curframe]->duration;
|
||||
|
||||
if (frametime >= framedur) {
|
||||
frametime -= framedur;
|
||||
changedp = true;
|
||||
|
||||
if (reversep) {
|
||||
if (curframe >= 1)
|
||||
curframe--;
|
||||
else if (rep->loop)
|
||||
curframe = rep->frames.size()-1;
|
||||
else
|
||||
finishedp = true;
|
||||
}
|
||||
else {
|
||||
if (curframe+1 < rep->frames.size())
|
||||
curframe++;
|
||||
else if (rep->loop)
|
||||
curframe = 0;
|
||||
else
|
||||
finishedp = true;
|
||||
}
|
||||
if (finishedp && callback!=0)
|
||||
callback->animcb();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
namespace display
|
||||
{
|
||||
Surface *GetSurface (const std::string &filename)
|
||||
{
|
||||
return surface_cache.get(filename);
|
||||
}
|
||||
|
||||
void RegisterImage (const std::string &name, Image *img)
|
||||
{
|
||||
}
|
||||
|
||||
Image *LookupImage (const std::string &name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
241
project/jni/application/enigma/src/d_models.hh
Normal file
241
project/jni/application/enigma/src/d_models.hh
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef D_MODELS_HH
|
||||
#define D_MODELS_HH
|
||||
|
||||
#include "ecl_fwd.hh"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
namespace display
|
||||
{
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using ecl::Surface;
|
||||
|
||||
/* -------------------- Image -------------------- */
|
||||
|
||||
struct Image {
|
||||
// Variables.
|
||||
ecl::Surface *surface;
|
||||
ecl::Rect rect; // location of image inside surface
|
||||
int refcount; // reference count, initialized to 1
|
||||
|
||||
// Constructors.
|
||||
Image(ecl::Surface *sfc);
|
||||
Image(ecl::Surface *sfc, const ecl::Rect &r);
|
||||
};
|
||||
|
||||
void incref (Image *i);
|
||||
void decref (Image *i);
|
||||
void draw_image (Image *i, ecl::GC &gc, int x, int y);
|
||||
|
||||
/* -------------------- ImageModel -------------------- */
|
||||
|
||||
class ImageModel : public Model {
|
||||
Image* image;
|
||||
int xoff, yoff; // relative origin of the image
|
||||
public:
|
||||
// Constructors
|
||||
ImageModel (Image *i, int xo, int yo);
|
||||
ImageModel (Surface *s, int xo, int yo);
|
||||
ImageModel (Surface *s, const ecl::Rect &r, int xo, int yo);
|
||||
~ImageModel();
|
||||
|
||||
// Model interface
|
||||
void draw(ecl::GC &gc, int x, int y);
|
||||
Model *clone();
|
||||
void get_extension (ecl::Rect &r);
|
||||
Image *get_image() { return image; }
|
||||
};
|
||||
|
||||
/* -------------------- ShadowModel -------------------- */
|
||||
|
||||
class ShadowModel : public Model {
|
||||
public:
|
||||
ShadowModel(Model *m, Model *sh);
|
||||
~ShadowModel();
|
||||
|
||||
// Model interface
|
||||
void expose (ModelLayer *ml, int vx, int vy);
|
||||
void remove (ModelLayer *ml);
|
||||
|
||||
void set_callback(ModelCallback *cb);
|
||||
void reverse();
|
||||
void restart();
|
||||
void draw (ecl::GC &gc, int x, int y);
|
||||
void draw_shadow (ecl::GC &gc, int x, int y);
|
||||
Model *get_shadow() const;
|
||||
Model *clone();
|
||||
|
||||
void get_extension (ecl::Rect &r);
|
||||
|
||||
private:
|
||||
Model *model, *shade;
|
||||
};
|
||||
|
||||
/* -------------------- CompositeModel -------------------- */
|
||||
|
||||
class CompositeModel : public Model {
|
||||
Model *bg, *fg;
|
||||
public:
|
||||
CompositeModel(Model *b, Model *f) : bg(b), fg(f) {}
|
||||
~CompositeModel() {
|
||||
delete bg; delete fg;
|
||||
}
|
||||
|
||||
// Animation interface
|
||||
void set_callback(ModelCallback *cb) {
|
||||
// bg->set_callback(cb);
|
||||
fg->set_callback(cb);
|
||||
}
|
||||
void reverse() {
|
||||
// bg->reverse();
|
||||
fg->reverse();
|
||||
}
|
||||
void restart() {
|
||||
fg->restart();
|
||||
}
|
||||
|
||||
// Model interface
|
||||
Model *get_shadow() const { return bg->get_shadow(); }
|
||||
virtual void expose (ModelLayer *ml, int vx, int vy) {
|
||||
fg->expose (ml, vx, vy);
|
||||
// bg->expose (ml, vx, vy);
|
||||
}
|
||||
virtual void remove (ModelLayer *ml) {
|
||||
fg->remove (ml);
|
||||
// bg->remove (ml);
|
||||
}
|
||||
void draw(ecl::GC &gc, int x, int y) {
|
||||
bg->draw(gc,x,y);
|
||||
fg->draw(gc,x,y);
|
||||
}
|
||||
void draw_shadow(ecl::GC &gc, int x, int y) {
|
||||
bg->draw_shadow(gc,x,y);
|
||||
}
|
||||
Model *clone() {
|
||||
return new CompositeModel(bg->clone(), fg->clone());
|
||||
}
|
||||
|
||||
void get_extension (ecl::Rect &r) {
|
||||
fg->get_extension (r);
|
||||
// ecl::Rect r1, r2;
|
||||
// bg->get_extension (r1);
|
||||
// fg->get_extension (r2);
|
||||
// r = boundingbox (r1, r2);
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------- RandomModel -------------------- */
|
||||
|
||||
/* Creates new models randomly from a set of template models. */
|
||||
class RandomModel : public Model {
|
||||
std::vector<std::string> modelnames;
|
||||
public:
|
||||
void add_model(const std::string &name) {modelnames.push_back(name);}
|
||||
Model *clone();
|
||||
};
|
||||
|
||||
/* -------------------- AliasModel -------------------- */
|
||||
|
||||
class AliasModel : public Model {
|
||||
string name;
|
||||
public:
|
||||
AliasModel(const string &modelname) : name(modelname) {}
|
||||
Model *clone();
|
||||
};
|
||||
|
||||
/* -------------------- Animations -------------------- */
|
||||
|
||||
struct AnimFrame : public ecl::Nocopy {
|
||||
// Variables
|
||||
Model *model;
|
||||
double duration;
|
||||
|
||||
// Constructor and Destructor
|
||||
AnimFrame(Model *m, double dur)
|
||||
: model(m), duration(dur)
|
||||
{}
|
||||
|
||||
~AnimFrame() { delete model; }
|
||||
};
|
||||
|
||||
struct AnimRep {
|
||||
// Variables
|
||||
vector<AnimFrame*> frames;
|
||||
bool loop;
|
||||
int refcount;
|
||||
|
||||
// Constructor and Destructor
|
||||
AnimRep(bool l) : loop(l), refcount(1) {}
|
||||
|
||||
~AnimRep() {
|
||||
delete_sequence(frames.begin(), frames.end());
|
||||
}
|
||||
};
|
||||
|
||||
class Anim2d : public Model, public ecl::Nocopy {
|
||||
public:
|
||||
Anim2d (bool loop);
|
||||
~Anim2d();
|
||||
void set_callback(ModelCallback *cb) { callback = cb; }
|
||||
|
||||
void add_frame(Model *m, double duration);
|
||||
|
||||
/* ---------- Model interface ---------- */
|
||||
void draw(ecl::GC &gc, int x, int y);
|
||||
void draw_shadow(ecl::GC &gc, int x, int y);
|
||||
Model *clone() { return new Anim2d(rep); }
|
||||
void reverse() { reversep = !reversep; }
|
||||
void restart ();
|
||||
|
||||
void expose (ModelLayer *ml, int vx, int vy);
|
||||
void remove (ModelLayer *ml);
|
||||
|
||||
void tick(double dtime);
|
||||
bool has_changed(ecl::Rect &changed_region);
|
||||
bool is_garbage() const { return finishedp; }
|
||||
|
||||
void move (int newx, int newy);
|
||||
void get_extension (ecl::Rect &r);
|
||||
|
||||
private:
|
||||
Anim2d(AnimRep *r);
|
||||
|
||||
/* ---------- Variables ---------- */
|
||||
AnimRep *rep;
|
||||
unsigned curframe; // Current frame number
|
||||
double frametime; // Elapsed time since frame was activated
|
||||
bool finishedp; // Animation has finished
|
||||
bool changedp; // Model state has changed since last redraw
|
||||
bool reversep; // Play the animation in reverse direction
|
||||
|
||||
int videox, videoy; // Video coordinates of sprite
|
||||
ModelCallback *callback;
|
||||
};
|
||||
|
||||
ecl::Surface *GetSurface (const std::string &filename);
|
||||
ecl::Surface *CropSurface (const ecl::Surface *s, ecl::Rect r);
|
||||
void DefineModel (const char *name, Model *m);
|
||||
void DefineImageModel (const char *name, ecl::Surface *s);
|
||||
}
|
||||
|
||||
#endif
|
||||
2132
project/jni/application/enigma/src/display.cpp
Normal file
2132
project/jni/application/enigma/src/display.cpp
Normal file
File diff suppressed because it is too large
Load Diff
246
project/jni/application/enigma/src/display.hh
Normal file
246
project/jni/application/enigma/src/display.hh
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef DISPLAY_HH_INCLUDED
|
||||
#define DISPLAY_HH_INCLUDED
|
||||
|
||||
#include "enigma.hh"
|
||||
#include "ecl.hh"
|
||||
|
||||
//----------------------------------------
|
||||
// Definition of models
|
||||
//----------------------------------------
|
||||
namespace display
|
||||
{
|
||||
class DisplayLayer;
|
||||
class ModelLayer;
|
||||
|
||||
/*! Animations can invoke a callback of this type on completion.
|
||||
Note that you may not delete or replace models other than the
|
||||
one that induced the callback from inside the callback--use a
|
||||
timer or a flag to do this. */
|
||||
class ModelCallback {
|
||||
public:
|
||||
virtual ~ModelCallback() {}
|
||||
virtual void animcb() = 0;
|
||||
};
|
||||
|
||||
class Animation {
|
||||
public:
|
||||
virtual ~Animation() {}
|
||||
virtual void set_callback (ModelCallback *) {}
|
||||
virtual void reverse() {}
|
||||
virtual void restart() {}
|
||||
|
||||
virtual bool is_garbage() const { return false; }
|
||||
virtual void tick(double /*dtime*/) {}
|
||||
virtual bool has_changed(ecl::Rect &/*changed_region*/) { return false; }
|
||||
};
|
||||
|
||||
class Model : public Animation {
|
||||
public:
|
||||
|
||||
virtual void draw(ecl::GC &/*gc*/, int /*x*/, int /*y*/) {}
|
||||
virtual void draw_shadow(ecl::GC &/*gc*/, int /*x*/, int /*y*/) {}
|
||||
|
||||
virtual Model *get_shadow() const { return 0; }
|
||||
|
||||
virtual void expose (ModelLayer * /*ml*/, int videox, int videoy) {}
|
||||
virtual void remove (ModelLayer * /*ml*/) {}
|
||||
|
||||
virtual Model *clone() = 0;
|
||||
virtual void get_extension (ecl::Rect &r);
|
||||
};
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void InitModels();
|
||||
void ShutdownModels();
|
||||
|
||||
Model * MakeModel (const std::string &name);
|
||||
|
||||
|
||||
int DefineImage (const char *name, const char *fname,
|
||||
int xoff, int yoff, int padding);
|
||||
int DefineSubImage (const char *name, const char *fname,
|
||||
int xoff, int yoff, ecl::Rect r);
|
||||
void DefineRandModel (const char *name, int n, char **names);
|
||||
void DefineShadedModel (const char *name, const char *model, const char *shade);
|
||||
void DefineOverlayImage (const char *name, int n, char **images);
|
||||
void DefineComposite (const char *name, const char *bgname, const char *fgname);
|
||||
void DefineAnim (const char *name, bool loop_p);
|
||||
void AddFrame (const char *name, const char *model, double time);
|
||||
void DefineAlias (const char *name, const char *othername);
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Models on the grid
|
||||
//----------------------------------------
|
||||
namespace display
|
||||
{
|
||||
using enigma::GridPos;
|
||||
using enigma::GridLayer;
|
||||
using enigma::GridLoc;
|
||||
|
||||
Model* SetModel (const GridLoc & l, const std::string &modelname);
|
||||
Model* SetModel (const GridLoc & l, Model *m);
|
||||
void KillModel (const GridLoc & l);
|
||||
Model* GetModel (const GridLoc & l);
|
||||
Model* YieldModel (const GridLoc & l);
|
||||
}
|
||||
|
||||
/* -------------------- Scrolling -------------------- */
|
||||
namespace display
|
||||
{
|
||||
enum FollowMode {
|
||||
FOLLOW_NONE = 0, // Don't follow any sprite
|
||||
FOLLOW_SCROLLING = 1, // Scroll the screen
|
||||
FOLLOW_SCREEN = 2, // Flip the screen region
|
||||
FOLLOW_SCREENSCROLLING = 3, // Scroll to the next screen
|
||||
FOLLOW_SMOOTH = 4, // Follow pixel by pixel
|
||||
};
|
||||
|
||||
|
||||
void SetFollowMode (FollowMode m);
|
||||
void SetScrollBoundary (double boundary);
|
||||
|
||||
void SetReferencePoint (const ecl::V2 &point);
|
||||
void GetReferencePointCoordinates(int *x, int *y);
|
||||
void FocusReferencePoint();
|
||||
}
|
||||
|
||||
/* -------------------- Sprites -------------------- */
|
||||
namespace display
|
||||
{
|
||||
enum SpriteLayer {
|
||||
SPRITE_ACTOR, SPRITE_EFFECT, SPRITE_DEBRIS
|
||||
};
|
||||
|
||||
typedef unsigned int SpriteId;
|
||||
|
||||
class DL_Sprites;
|
||||
|
||||
class SpriteHandle {
|
||||
DL_Sprites *layer;
|
||||
unsigned id;
|
||||
public:
|
||||
SpriteHandle (DL_Sprites *l, unsigned spriteid);
|
||||
SpriteHandle();
|
||||
|
||||
void kill();
|
||||
void move (const ecl::V2 &newpos) const;
|
||||
void replace_model (Model *m) const;
|
||||
Model *get_model () const;
|
||||
void set_callback (ModelCallback *cb) const;
|
||||
void hide() const;
|
||||
void show() const;
|
||||
};
|
||||
|
||||
/*! Add a new effect sprite. Sprites of this type are
|
||||
automatically deleted once the animation has finished. */
|
||||
SpriteHandle AddEffect (const ecl::V2 &pos, const char *modelname);
|
||||
|
||||
/*! Create a new sprite. If modelname==0, the sprite is
|
||||
considered invisible. Sprites of this type are _never_
|
||||
automatically deleted. */
|
||||
SpriteHandle AddSprite (const ecl::V2 &pos, const char *modelname=0);
|
||||
|
||||
}
|
||||
|
||||
/* -------------------- Rubber bands -------------------- */
|
||||
namespace display
|
||||
{
|
||||
class DL_Lines;
|
||||
|
||||
class RubberHandle {
|
||||
public:
|
||||
RubberHandle (DL_Lines *layer=0, unsigned id=0);
|
||||
operator unsigned() { return id; }
|
||||
|
||||
void update_first (const ecl::V2 &p1);
|
||||
void update_second (const ecl::V2 &p2);
|
||||
void kill();
|
||||
|
||||
DL_Lines *line_layer;
|
||||
unsigned id;
|
||||
};
|
||||
|
||||
RubberHandle AddRubber (const ecl::V2 &p1, const ecl::V2 &p2);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Status bar -------------------- */
|
||||
namespace display
|
||||
{
|
||||
using enigma_player::Inventory;
|
||||
|
||||
class StatusBar {
|
||||
public:
|
||||
virtual ~StatusBar() {}
|
||||
virtual void set_inventory (const std::vector<std::string> &modelnames) = 0;
|
||||
|
||||
virtual void show_text (const std::string &str,
|
||||
bool scrolling,
|
||||
double duration = -1) = 0;
|
||||
virtual void hide_text() = 0;
|
||||
|
||||
virtual void show_move_counter (bool active) = 0;
|
||||
virtual void show_odometer (bool active) = 0;
|
||||
|
||||
virtual void set_time (double time) = 0;
|
||||
virtual void set_speed (double speed) = 0;
|
||||
virtual void set_travelled_distance (double distance) = 0;
|
||||
virtual void set_counter (int nummoves) = 0;
|
||||
};
|
||||
|
||||
StatusBar *GetStatusBar();
|
||||
|
||||
#define STATUSBAR display::GetStatusBar()
|
||||
|
||||
|
||||
/* -------------------- Interface to display engine -------------------- */
|
||||
|
||||
enum DisplayFlags
|
||||
{
|
||||
SHOW_FLOOR = 0x01,
|
||||
SHOW_STONES = 0x02,
|
||||
SHOW_ITEMS = 0x04,
|
||||
SHOW_SHADES = 0x08,
|
||||
SHOW_SPRITES = 0x10,
|
||||
SHOW_TIME = 0x20,
|
||||
SHOW_INVENTORY = 0x40,
|
||||
SHOW_ALL = 0x7f
|
||||
};
|
||||
|
||||
void ToggleFlag(DisplayFlags flag);
|
||||
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void NewWorld (int w, int h);
|
||||
void ResizeGameArea (int w, int h);
|
||||
const ecl::Rect& GetGameArea ();
|
||||
|
||||
void DrawAll (ecl::GC &gc);
|
||||
void RedrawAll (ecl::Screen *sfc);
|
||||
void Redraw (ecl::Screen *sfc);
|
||||
void Tick (double dtime);
|
||||
}
|
||||
|
||||
#endif
|
||||
96
project/jni/application/enigma/src/display_internal.hh
Normal file
96
project/jni/application/enigma/src/display_internal.hh
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef DISPLAY_INTERNAL_HH
|
||||
#define DISPLAY_INTERNAL_HH
|
||||
|
||||
#include "display.hh"
|
||||
|
||||
namespace display
|
||||
{
|
||||
using ecl::V2;
|
||||
|
||||
class DisplayLayer;
|
||||
class StatusBarImpl;
|
||||
class Model;
|
||||
|
||||
typedef ecl::Rect ScreenArea;
|
||||
typedef ecl::Rect WorldArea;
|
||||
typedef std::list<Model*> ModelList;
|
||||
|
||||
|
||||
class Window {
|
||||
public:
|
||||
Window() {}
|
||||
Window (const ScreenArea &area) : m_area(area)
|
||||
{}
|
||||
|
||||
const ScreenArea &get_area() const { return m_area; }
|
||||
private:
|
||||
ScreenArea m_area;
|
||||
};
|
||||
|
||||
|
||||
class TextDisplay {
|
||||
public:
|
||||
TextDisplay(ecl::Font &f);
|
||||
|
||||
void set_text(const std::string &t, bool scrolling, double duration = -1);
|
||||
|
||||
void tick(double dtime);
|
||||
bool has_changed() const { return changedp; }
|
||||
bool has_finished() const { return finishedp; }
|
||||
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
ecl::Rect area;
|
||||
std::string text;
|
||||
bool changedp, finishedp;
|
||||
bool pingpong;
|
||||
bool showscroll;
|
||||
double xoff;
|
||||
double scrollspeed; // pixels per second
|
||||
std::auto_ptr<ecl::Surface> textsurface;
|
||||
ecl::Font &font;
|
||||
double time, maxtime;
|
||||
};
|
||||
|
||||
class StatusBarImpl : public StatusBar, public Window {
|
||||
public:
|
||||
StatusBarImpl (const ScreenArea &area);
|
||||
~StatusBarImpl();
|
||||
|
||||
bool has_changed() const { return m_changedp; }
|
||||
void redraw (ecl::GC &gc, const ScreenArea &r);
|
||||
void tick (double dtime);
|
||||
void new_world();
|
||||
|
||||
// StatusBar interface.
|
||||
void set_time (double time);
|
||||
void set_inventory (const std::vector<std::string> &modelnames);
|
||||
void show_text (const std::string &str, bool scrolling, double duration);
|
||||
void hide_text();
|
||||
|
||||
void show_move_counter (bool active);
|
||||
void show_odometer (bool active);
|
||||
|
||||
void set_speed (double speed);
|
||||
void set_travelled_distance (double distance);
|
||||
void set_counter (int new_counter);
|
||||
|
||||
private:
|
||||
ScreenArea m_itemarea;
|
||||
std::vector<Model*> m_models;
|
||||
bool m_changedp;
|
||||
TextDisplay m_textview;
|
||||
|
||||
double m_leveltime;
|
||||
bool m_showtime_p;
|
||||
int m_counter;
|
||||
bool m_showcounter_p;
|
||||
bool m_showodometer_p;
|
||||
bool m_interruptible; // Current text message may be interrupted
|
||||
bool m_text_active;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
469
project/jni/application/enigma/src/editor.cpp
Normal file
469
project/jni/application/enigma/src/editor.cpp
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#include "editor.hh"
|
||||
|
||||
#include "ecl_sdl.hh"
|
||||
#include "ecl_video.hh" // set_color, line
|
||||
#include "ecl_util.hh" // set_flags
|
||||
|
||||
#include "main.hh"
|
||||
#include "world.hh"
|
||||
#include "lua.hh"
|
||||
#include "video.hh"
|
||||
#include "gui/widgets.hh"
|
||||
#include "display_internal.hh" // WorldArea
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#include "display_internal.hh"
|
||||
#include "d_engine.hh"
|
||||
|
||||
#ifndef CXXLUA
|
||||
extern "C" {
|
||||
#include "lualib.h"
|
||||
#include "tolua++.h"
|
||||
}
|
||||
#else
|
||||
#include "lualib.h"
|
||||
#include "tolua++.h"
|
||||
#endif
|
||||
|
||||
#include "lua-editor.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace enigma;
|
||||
using namespace editor;
|
||||
using namespace ecl;
|
||||
|
||||
using display::ScreenArea;
|
||||
using display::DisplayEngine;
|
||||
using display::Model;
|
||||
//using world::ObjectTraits;
|
||||
|
||||
using world::ItemID;
|
||||
|
||||
#include "editor_impl.hh"
|
||||
|
||||
|
||||
/* -------------------- Editor state -------------------- */
|
||||
|
||||
EditorState::EditorState()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
EditorState::~EditorState()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void EditorState::save( std::ostream & /*os*/ )
|
||||
{
|
||||
}
|
||||
|
||||
void EditorState::load( std::istream & /*is*/ )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Editor display engine -------------------- */
|
||||
|
||||
EditorDisplay::EditorDisplay()
|
||||
{
|
||||
DisplayEngine *engine = get_engine();
|
||||
engine->set_screen_area( video::GetInfo()->gamearea );
|
||||
engine->add_layer( new DL_Editor );
|
||||
}
|
||||
|
||||
void
|
||||
EditorDisplay::redraw()
|
||||
{
|
||||
display::CommonDisplay::redraw();
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Editor tools -------------------- */
|
||||
|
||||
void
|
||||
GridObjectTool::advance_in_group( int offset )
|
||||
{
|
||||
int newidx = m_objectidx + offset;
|
||||
if( newidx >= 0 && newidx < (int)m_groups[ m_groupidx ].entries.size() ) {
|
||||
m_objectidx = newidx;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GridObjectTool::advance_group( int offset )
|
||||
{
|
||||
int newidx = m_groupidx + offset;
|
||||
if( newidx >= 0 && newidx < (int)m_groups.size() ) {
|
||||
m_groupidx = newidx;
|
||||
m_objectidx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GridObjectTool::on_mousebutton( const SDL_Event &e, V2 worldpos )
|
||||
{
|
||||
Editor *ed = Editor::get_instance();
|
||||
string obj = current_object();
|
||||
|
||||
round_coordinates( &worldpos );
|
||||
int x = (int)worldpos[ 0 ];
|
||||
int y = (int)worldpos[ 1 ];
|
||||
|
||||
if( e.button.type == SDL_MOUSEBUTTONDOWN ) {
|
||||
if( e.button.button == 1 ) {
|
||||
// left mb -> set object
|
||||
switch( m_layer ) {
|
||||
case GRID_FLOOR: ed->set_floor( x, y, obj ); break;
|
||||
case GRID_ITEMS: ed->set_item( x, y, obj ); break;
|
||||
case GRID_STONES: ed->set_stone( x, y, obj ); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if( e.button.button == 3 ) {
|
||||
// right mb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GridObjectTool::object_menu()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ActorTool::on_mousebutton( const SDL_Event &e, V2 worldpos )
|
||||
{
|
||||
Editor *ed = Editor::get_instance();
|
||||
string obj = current_object();
|
||||
|
||||
if( e.button.type == SDL_MOUSEBUTTONDOWN ) {
|
||||
if( e.button.button == 1 ) {
|
||||
// left mb -> set object
|
||||
ed->set_actor( worldpos[0], worldpos[1], obj );
|
||||
}
|
||||
else if( e.button.button == 3 ) {
|
||||
// right mb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- The Editor -------------------- */
|
||||
|
||||
Editor *Editor::m_instance = 0;
|
||||
|
||||
Editor::Editor()
|
||||
: m_editarea( 0,0,640,13*32 )
|
||||
, m_iconarea( 0,13*32,640,64 )
|
||||
, m_display()
|
||||
, m_iconbar( m_iconarea, 2, 640/32 )
|
||||
, m_quit_editor( false )
|
||||
, m_cursor()
|
||||
, m_lua( luaL_newstate() )
|
||||
, m_editmode( MODE_FLOOR )
|
||||
, m_tools()
|
||||
{
|
||||
luaL_openlibs(m_lua);
|
||||
tolua_open( m_lua );
|
||||
tolua_editor_open( m_lua );
|
||||
}
|
||||
|
||||
Editor::~Editor()
|
||||
{
|
||||
lua_close( m_lua );
|
||||
}
|
||||
|
||||
void
|
||||
Editor::init()
|
||||
{
|
||||
delete_sequence( m_tools.begin(), m_tools.end() );
|
||||
m_tools.clear();
|
||||
m_tools.resize( MODE_COUNT, NULL );
|
||||
m_tools[ MODE_FLOOR ] = m_floortool = new FloorTool;
|
||||
m_tools[ MODE_ITEMS ] = m_itemtool = new ItemTool;
|
||||
m_tools[ MODE_STONES ] = m_stonetool = new StoneTool;
|
||||
m_tools[ MODE_ACTORS ] = m_actortool = new ActorTool;
|
||||
|
||||
new_world( 20, 13 );
|
||||
|
||||
// TODO - just printing a message is not enough - the app will crash on missing editor.lua
|
||||
if (lua::DoSysFile(m_lua, "compat.lua") != lua::NO_LUAERROR) {
|
||||
std::string message = "While processing 'compat.lua':\n" +lua::LastError(m_lua);
|
||||
fprintf( stderr, message.c_str() );
|
||||
}
|
||||
if (lua::DoSysFile(m_lua, "editor.lua") != lua::NO_LUAERROR) {
|
||||
std::string message = "Error loading 'editor.lua'\n" +lua::LastError(m_lua);
|
||||
fprintf( stderr, message.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Editor::run()
|
||||
{
|
||||
m_quit_editor = false;
|
||||
while( !m_quit_editor ) {
|
||||
video::HideMouse();
|
||||
m_display.redraw();
|
||||
video::ShowMouse();
|
||||
video::GetScreen()->flush_updates();
|
||||
|
||||
SDL_Event e;
|
||||
if( SDL_PollEvent( &e ) ) {
|
||||
dispatch_event (e);
|
||||
}
|
||||
|
||||
SDL_Delay( 10 );
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::set_mode( EditMode m )
|
||||
{
|
||||
m_editmode = m;
|
||||
update_cursor();
|
||||
}
|
||||
|
||||
void Editor::update_cursor()
|
||||
{
|
||||
// set proper position
|
||||
int mx;
|
||||
int my;
|
||||
SDL_GetMouseState( &mx, &my );
|
||||
DisplayEngine *engine = m_display.get_engine();
|
||||
V2 worldpos = engine->to_world( V2( mx, my ) );
|
||||
current_tool()->round_coordinates( &worldpos );
|
||||
m_cursor.move( worldpos );
|
||||
|
||||
// set proper face
|
||||
set_cursor( current_tool()->current_object() );
|
||||
}
|
||||
|
||||
Tool *Editor::current_tool()
|
||||
{
|
||||
if( Tool *tool = m_tools[ m_editmode ] ) {
|
||||
return tool;
|
||||
}
|
||||
else {
|
||||
fprintf( stderr, "undefined tool\n" );
|
||||
assert( m_stonetool != NULL );
|
||||
return m_stonetool;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Editor::set_floor( int x, int y, std::string const& name )
|
||||
{
|
||||
m_display.set_floor( x, y, display::MakeModel( name ) );
|
||||
}
|
||||
|
||||
void
|
||||
Editor::set_item( int x, int y, std::string const& name )
|
||||
{
|
||||
m_display.set_item( x, y, display::MakeModel( name ) );
|
||||
}
|
||||
|
||||
void
|
||||
Editor::set_stone( int x, int y, std::string const& name )
|
||||
{
|
||||
m_display.set_stone( x, y, display::MakeModel( name ) );
|
||||
}
|
||||
|
||||
void
|
||||
Editor::set_actor( double x, double y, std::string const& name )
|
||||
{
|
||||
m_display.add_sprite( V2( x, y ), display::MakeModel( name ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Editor::new_world( int w, int h )
|
||||
{
|
||||
m_display.new_world( w, h );
|
||||
for( int x=0; x<w; ++x ) {
|
||||
for( int y=0; y<h; ++y ) {
|
||||
set_floor (x, y, "fl-normal");
|
||||
}
|
||||
}
|
||||
m_cursor = m_display.add_effect( V2(), display::MakeModel( "it-hammer" ) );
|
||||
}
|
||||
|
||||
void
|
||||
Editor::set_cursor( const string &name )
|
||||
{
|
||||
m_cursor.replace_model( display::MakeModel( name ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Editor::scroll( double xoff, double yoff )
|
||||
{
|
||||
DisplayEngine *engine = m_display.get_engine();
|
||||
V2 newoffset = engine->get_offset() + V2( xoff, yoff );
|
||||
video::HideMouse();
|
||||
engine->move_offset( newoffset );
|
||||
video::ShowMouse();
|
||||
}
|
||||
|
||||
void
|
||||
Editor::scroll_abs( double x, double y )
|
||||
{
|
||||
DisplayEngine *engine = m_display.get_engine();
|
||||
video::HideMouse();
|
||||
engine->move_offset( V2( x, y ) );
|
||||
video::ShowMouse();
|
||||
}
|
||||
|
||||
bool
|
||||
Editor::on_mousemotion( SDL_Event &e )
|
||||
{
|
||||
DisplayEngine *engine = m_display.get_engine();
|
||||
V2 worldpos = engine->to_world( V2( e.motion.x, e.motion.y ) );
|
||||
current_tool()->round_coordinates( &worldpos );
|
||||
m_cursor.move( worldpos );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Editor::on_mousebutton( SDL_Event &e )
|
||||
{
|
||||
DisplayEngine *engine = m_display.get_engine();
|
||||
V2 worldpos = engine->to_world( V2( e.motion.x, e.motion.y ) );
|
||||
|
||||
if( Tool *tool = current_tool() ) {
|
||||
tool->on_mousebutton( e, worldpos );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Editor::on_keydown( SDL_Event &e )
|
||||
{
|
||||
bool ctrl_pressed = e.key.keysym.mod & KMOD_CTRL;
|
||||
bool shift_pressed = e.key.keysym.mod & KMOD_SHIFT;
|
||||
int hoff = 19;
|
||||
int voff = 12;
|
||||
|
||||
Tool *tool = current_tool();
|
||||
|
||||
switch( e.key.keysym.sym ) {
|
||||
case SDLK_ESCAPE:
|
||||
m_quit_editor = true;
|
||||
break;
|
||||
case SDLK_LEFT: scroll( ctrl_pressed ? -hoff : -1, 0 ); break;
|
||||
case SDLK_RIGHT: scroll( ctrl_pressed ? +hoff : +1, 0 ); break;
|
||||
case SDLK_DOWN: scroll( 0, ctrl_pressed ? +voff : +1 ); break;
|
||||
case SDLK_UP: scroll( 0, ctrl_pressed ? -voff : -1 ); break;
|
||||
case SDLK_HOME: scroll_abs( 0, 0 ); break;
|
||||
|
||||
case SDLK_PAGEUP:
|
||||
tool->advance_group( -1 );
|
||||
update_cursor();
|
||||
break;
|
||||
case SDLK_PAGEDOWN:
|
||||
tool->advance_group( +1 );
|
||||
update_cursor();
|
||||
break;
|
||||
|
||||
case SDLK_PLUS:
|
||||
case SDLK_KP_PLUS:
|
||||
tool->advance_in_group( +1 );
|
||||
update_cursor();
|
||||
break;
|
||||
|
||||
case SDLK_MINUS:
|
||||
case SDLK_KP_MINUS:
|
||||
tool->advance_in_group( -1 );
|
||||
update_cursor();
|
||||
break;
|
||||
|
||||
case SDLK_a:
|
||||
if( shift_pressed )
|
||||
;
|
||||
set_mode( MODE_ACTORS );
|
||||
break;
|
||||
|
||||
case SDLK_f:
|
||||
if( shift_pressed )
|
||||
;
|
||||
set_mode( MODE_FLOOR );
|
||||
break;
|
||||
|
||||
case SDLK_i:
|
||||
if( shift_pressed )
|
||||
;
|
||||
set_mode( MODE_ITEMS );
|
||||
break;
|
||||
|
||||
case SDLK_s:
|
||||
set_mode( MODE_STONES );
|
||||
if( shift_pressed ) {
|
||||
tool = current_tool();
|
||||
tool->object_menu();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void editor::DefineFloorGroup( char const* name, char const* descr,
|
||||
int nentries, char ** entries )
|
||||
{
|
||||
Editor *ed = Editor::get_instance();
|
||||
|
||||
vector<string> entryvec(entries, entries+nentries);
|
||||
ObjectGroup group(name, descr, entryvec);
|
||||
ed->add_floor_group (group);
|
||||
}
|
||||
|
||||
void editor::DefineItemGroup( const char *name, const char *descr,
|
||||
int nentries, char **entries )
|
||||
{
|
||||
Editor *ed = Editor::get_instance();
|
||||
|
||||
vector<string> entryvec( entries, entries + nentries );
|
||||
ObjectGroup group( name, descr, entryvec );
|
||||
ed->add_item_group( group );
|
||||
}
|
||||
|
||||
void editor::DefineStoneGroup( const char *name, const char *descr,
|
||||
int nentries, char **entries )
|
||||
{
|
||||
Editor *ed = Editor::get_instance();
|
||||
|
||||
vector<string> entryvec( entries, entries+nentries );
|
||||
ObjectGroup group( name, descr, entryvec );
|
||||
ed->add_stone_group( group );
|
||||
}
|
||||
|
||||
|
||||
void editor::Run()
|
||||
{
|
||||
Editor *ed = Editor::get_instance();
|
||||
ed->init();
|
||||
ed->run();
|
||||
}
|
||||
37
project/jni/application/enigma/src/editor.hh
Normal file
37
project/jni/application/enigma/src/editor.hh
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef EDITOR_HH
|
||||
#define EDITOR_HH
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace editor
|
||||
{
|
||||
void Run();
|
||||
void DefineFloorGroup (const char *name, const char *descr,
|
||||
int nentries, char **entries);
|
||||
|
||||
void DefineItemGroup (const char *name, const char *descr,
|
||||
int nentries, char **entries);
|
||||
|
||||
void DefineStoneGroup (const char *name, const char *descr,
|
||||
int nentries, char **entries);
|
||||
}
|
||||
|
||||
#endif
|
||||
335
project/jni/application/enigma/src/editor_impl.hh
Normal file
335
project/jni/application/enigma/src/editor_impl.hh
Normal file
@@ -0,0 +1,335 @@
|
||||
namespace
|
||||
{
|
||||
class EditorState {
|
||||
public:
|
||||
EditorState();
|
||||
~EditorState();
|
||||
|
||||
void save (std::ostream &os);
|
||||
void load (std::istream &is);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class DL_Editor
|
||||
: public display::DisplayLayer
|
||||
{
|
||||
public:
|
||||
DL_Editor()
|
||||
{
|
||||
}
|
||||
|
||||
~DL_Editor()
|
||||
{
|
||||
}
|
||||
|
||||
void prepare_draw( const display::WorldArea & )
|
||||
{
|
||||
}
|
||||
|
||||
void draw( ecl::GC &gc, const display::WorldArea &a, int x, int y )
|
||||
{
|
||||
}
|
||||
|
||||
void draw_onepass( ecl::GC & gc )
|
||||
{
|
||||
//just a test...
|
||||
//ecl::set_color( gc, 240, 140, 20, 255 );
|
||||
//ecl::set_flags( gc.flags, GS_ANTIALIAS );
|
||||
//ecl::line( gc, 0, 0, 320, 240 );
|
||||
}
|
||||
|
||||
void tick( double dtime )
|
||||
{
|
||||
}
|
||||
|
||||
void new_world( int w, int h )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class EditorDisplay
|
||||
: public display::CommonDisplay
|
||||
{
|
||||
public:
|
||||
EditorDisplay();
|
||||
~EditorDisplay() {}
|
||||
|
||||
void redraw();
|
||||
|
||||
void tick(double /*dtime*/ ) {}
|
||||
|
||||
Model *make_model( const std::string &name );
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
class IconBar
|
||||
: public gui::Container
|
||||
{
|
||||
public:
|
||||
IconBar( const ScreenArea &a, int rows, int cols )
|
||||
: m_area( a )
|
||||
, m_rows( rows )
|
||||
, m_cols( cols )
|
||||
, m_bgcolor( 150, 150, 150 )
|
||||
{
|
||||
}
|
||||
|
||||
~IconBar() {}
|
||||
|
||||
ScreenArea get_area() const
|
||||
{
|
||||
return m_area;
|
||||
}
|
||||
|
||||
// Widget interface.
|
||||
void draw( ecl::GC &gc, const ecl::Rect &area_ )
|
||||
{
|
||||
set_color( gc, m_bgcolor );
|
||||
box( gc, area_ );
|
||||
}
|
||||
|
||||
private:
|
||||
// Variables.
|
||||
ScreenArea m_area;
|
||||
int m_rows, m_cols;
|
||||
ecl::RGB m_bgcolor;
|
||||
};
|
||||
|
||||
|
||||
enum EditMode {
|
||||
MODE_FLOOR,
|
||||
MODE_ITEMS,
|
||||
MODE_STONES,
|
||||
MODE_ACTORS,
|
||||
MODE_COUNT
|
||||
};
|
||||
|
||||
struct ObjectGroup {
|
||||
string name;
|
||||
string descr;
|
||||
vector<string> entries;
|
||||
|
||||
ObjectGroup( const string &name_,
|
||||
const string &descr_, const vector<string> entries_
|
||||
)
|
||||
: name( name_ )
|
||||
, descr( descr_ )
|
||||
, entries( entries_ )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Tool {
|
||||
public:
|
||||
virtual ~Tool() {}
|
||||
|
||||
virtual void object_menu() = 0;
|
||||
|
||||
virtual void advance_in_group( int offset ) = 0;
|
||||
virtual void advance_group( int offset ) = 0;
|
||||
virtual string current_object() = 0;
|
||||
|
||||
virtual void on_mousebutton( const SDL_Event &e, V2 worldpos ) = 0;
|
||||
|
||||
/// Rounds coordinates for item display. Actor-like tools
|
||||
/// will want to leave the coordinates intact, grid-like tools
|
||||
/// could want to round to integers.
|
||||
virtual void round_coordinates( V2 * worldpos ) = 0;
|
||||
};
|
||||
|
||||
class GridObjectTool
|
||||
: public Tool
|
||||
{
|
||||
public:
|
||||
|
||||
// Tool interface
|
||||
void object_menu();
|
||||
|
||||
void advance_in_group( int offset );
|
||||
void advance_group( int offset );
|
||||
|
||||
string current_object()
|
||||
{
|
||||
return m_groups[ m_groupidx ].entries[ m_objectidx ];
|
||||
}
|
||||
|
||||
void add_group( const ObjectGroup &g )
|
||||
{
|
||||
m_groups.push_back( g );
|
||||
}
|
||||
|
||||
// Constructors
|
||||
GridObjectTool( GridLayer layer )
|
||||
{
|
||||
m_groupidx = m_objectidx = 0;
|
||||
m_layer = layer;
|
||||
}
|
||||
|
||||
void round_coordinates( V2 * worldpos )
|
||||
{
|
||||
(*worldpos)[ 0 ] = round_down<int>( (*worldpos)[ 0 ] );
|
||||
(*worldpos)[ 1 ] = round_down<int>( (*worldpos)[ 1 ] );
|
||||
}
|
||||
|
||||
void on_mousebutton( const SDL_Event &e, V2 worldpos );
|
||||
|
||||
protected:
|
||||
|
||||
// Variables
|
||||
vector<ObjectGroup> m_groups;
|
||||
size_t m_groupidx;
|
||||
size_t m_objectidx;
|
||||
GridLayer m_layer;
|
||||
};
|
||||
|
||||
class FloorTool
|
||||
: public GridObjectTool
|
||||
{
|
||||
public:
|
||||
FloorTool()
|
||||
: GridObjectTool(GRID_FLOOR)
|
||||
{}
|
||||
};
|
||||
|
||||
class ItemTool
|
||||
: public GridObjectTool
|
||||
{
|
||||
public:
|
||||
ItemTool()
|
||||
: GridObjectTool( GRID_ITEMS )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class StoneTool
|
||||
: public GridObjectTool
|
||||
{
|
||||
public:
|
||||
StoneTool ()
|
||||
: GridObjectTool( GRID_STONES )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ActorTool
|
||||
: public Tool
|
||||
{
|
||||
public:
|
||||
// Tool interface.
|
||||
void object_menu() {}
|
||||
void advance_in_group( int /*offset*/ ) {}
|
||||
void advance_group( int /*offset*/ ) {}
|
||||
string current_object() { return "ac-blackball"; }
|
||||
void on_mousebutton( const SDL_Event & e, V2 worldpos );
|
||||
void round_coordinates( V2 * /*worldpos*/ ) {}
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
class Level {
|
||||
public:
|
||||
Level( EditorDisplay *display )
|
||||
: m_display( display )
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
// Variables.
|
||||
EditorDisplay *m_display;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Editor
|
||||
: private sdl::EventHandler
|
||||
{
|
||||
public:
|
||||
static Editor * get_instance()
|
||||
{
|
||||
if( m_instance == NULL ) {
|
||||
m_instance = new Editor;
|
||||
}
|
||||
return m_instance;
|
||||
}
|
||||
~Editor();
|
||||
|
||||
void init();
|
||||
void run();
|
||||
|
||||
Level *get_level() const
|
||||
{
|
||||
return m_level.get();
|
||||
}
|
||||
|
||||
void add_floor_group( const ObjectGroup &g )
|
||||
{
|
||||
m_floortool->add_group( g );
|
||||
}
|
||||
|
||||
void add_item_group( const ObjectGroup &g )
|
||||
{
|
||||
m_itemtool->add_group( g );
|
||||
}
|
||||
|
||||
void add_stone_group( const ObjectGroup &g )
|
||||
{
|
||||
m_stonetool->add_group( g );
|
||||
}
|
||||
|
||||
void set_floor( int x, int y, string const& name );
|
||||
void set_item( int x, int y, string const& name );
|
||||
void set_stone( int x, int y, string const& name );
|
||||
void set_actor( double x, double y, string const& name );
|
||||
|
||||
private:
|
||||
Editor();
|
||||
|
||||
|
||||
/* ---------- Private methods ---------- */
|
||||
void set_cursor( const string &name );
|
||||
|
||||
/// Change cursor face and position based on active tool.
|
||||
void update_cursor();
|
||||
|
||||
void set_mode( EditMode m );
|
||||
Tool *current_tool();
|
||||
|
||||
void new_world( int w, int h );
|
||||
|
||||
void scroll( double xoff, double yoff );
|
||||
void scroll_abs( double x, double y );
|
||||
|
||||
/*
|
||||
** EventHandler interface.
|
||||
*/
|
||||
bool on_mousemotion( SDL_Event &e );
|
||||
bool on_mousebutton( SDL_Event &e );
|
||||
bool on_keydown( SDL_Event &e );
|
||||
|
||||
/*
|
||||
** Variables.
|
||||
*/
|
||||
ScreenArea m_editarea;
|
||||
ScreenArea m_iconarea;
|
||||
EditorDisplay m_display;
|
||||
IconBar m_iconbar;
|
||||
bool m_quit_editor;
|
||||
display::SpriteHandle m_cursor;
|
||||
|
||||
lua_State *m_lua;
|
||||
|
||||
FloorTool *m_floortool;
|
||||
ItemTool *m_itemtool;
|
||||
StoneTool *m_stonetool;
|
||||
ActorTool *m_actortool;
|
||||
EditMode m_editmode;
|
||||
vector<Tool *> m_tools;
|
||||
auto_ptr<Level> m_level;
|
||||
|
||||
static Editor *m_instance;
|
||||
};
|
||||
}
|
||||
519
project/jni/application/enigma/src/enigma.cpp
Normal file
519
project/jni/application/enigma/src/enigma.cpp
Normal file
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "errors.hh"
|
||||
#include "enigma.hh"
|
||||
#include "ecl.hh"
|
||||
#include "main.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <set>
|
||||
|
||||
using namespace std;
|
||||
using namespace ecl;
|
||||
using namespace enigma;
|
||||
|
||||
|
||||
/* -------------------- Game Type -------------------- */
|
||||
|
||||
static const char *versionName[GAMET_COUNT+1] = {
|
||||
"enigma", // same indices as enum GameType
|
||||
"oxyd1",
|
||||
"per.oxyd",
|
||||
"oxyd.extra",
|
||||
"oxyd.magnum",
|
||||
0
|
||||
};
|
||||
|
||||
GameType enigma::GetGameType(std::string name) {
|
||||
GameType type = GAMET_UNKNOWN;
|
||||
for (int v = 0; v<GAMET_COUNT; ++v) {
|
||||
if (0 == strcmp(name.c_str(), versionName[v])) {
|
||||
type = GameType(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
std::string enigma::GetGameTypeName(GameType type) {
|
||||
if (type >= GAMET_FIRST && type <= GAMET_LAST)
|
||||
return versionName[type];
|
||||
else
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/* -------------------- Direction -------------------- */
|
||||
|
||||
Direction enigma::reverse(Direction d) {
|
||||
static Direction rdir[] = { NODIR, EAST, NORTH, WEST, SOUTH };
|
||||
return rdir[d+1];
|
||||
}
|
||||
|
||||
Direction enigma::rotate_cw (Direction d)
|
||||
{
|
||||
static Direction rdir[] = { NODIR, NORTH, WEST, SOUTH, EAST };
|
||||
return rdir[d+1];
|
||||
}
|
||||
|
||||
Direction enigma::rotate_ccw (Direction d)
|
||||
{
|
||||
static Direction rdir[] = { NODIR, SOUTH, EAST, NORTH, WEST };
|
||||
return rdir[d+1];
|
||||
}
|
||||
|
||||
Direction
|
||||
direction_fromto(GridPos source, GridPos target)
|
||||
{
|
||||
// source and target have to be adjacent
|
||||
|
||||
int dx = target.x-source.x;
|
||||
int dy = target.y-source.y;
|
||||
Direction d = NODIR;
|
||||
|
||||
if (dx == 0) {
|
||||
if (dy == -1) d = NORTH;
|
||||
else if (dy == 1) d = SOUTH;
|
||||
}
|
||||
else if (dy == 0) {
|
||||
if (dx == -1) d = WEST;
|
||||
else if (dx == 1) d = EAST;
|
||||
}
|
||||
|
||||
ASSERT(d != NODIR, XLevelRuntime,
|
||||
"direction_fromto: source and target not adjacent");
|
||||
return d;
|
||||
}
|
||||
|
||||
string enigma::to_suffix(Direction d) {
|
||||
static const char *sfx[] = { "", "-w", "-s", "-e", "-n" };
|
||||
return sfx[d+1];
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- DirectionBits -------------------- */
|
||||
|
||||
DirectionBits
|
||||
enigma::rotate(DirectionBits d, bool clockwise)
|
||||
{
|
||||
if (clockwise) {
|
||||
d = DirectionBits(((d>>1) | (d<<3)) & ALL_DIRECTIONS);
|
||||
} else {
|
||||
d = DirectionBits(((d>>3) | (d<<1)) & ALL_DIRECTIONS);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Value implementation -------------------- */
|
||||
|
||||
Value::Value(const char* str)
|
||||
: type(STRING)
|
||||
{
|
||||
val.str = new char[strlen(str)+1];
|
||||
strcpy(val.str, str);
|
||||
}
|
||||
|
||||
Value::~Value()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
Value::Value(const string& str)
|
||||
: type(STRING)
|
||||
{
|
||||
val.str = new char[str.length()+1];
|
||||
strcpy(val.str, str.c_str());
|
||||
}
|
||||
|
||||
Value::Value (const Value& other) : type(NIL) {
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
Value& Value::operator= (const Value& other) {
|
||||
if (this != &other) {
|
||||
if (other.type == STRING) {
|
||||
assign(other.val.str);
|
||||
} else {
|
||||
clear();
|
||||
type = other.type;
|
||||
val = other.val;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void Value::assign(const char* s) {
|
||||
clear();
|
||||
type = STRING;
|
||||
val.str = new char[strlen(s)+1];
|
||||
strcpy(val.str, s);
|
||||
}
|
||||
|
||||
void Value::assign(double d)
|
||||
{
|
||||
clear(); type=DOUBLE; val.dval=d;
|
||||
}
|
||||
|
||||
|
||||
void Value::clear() {
|
||||
if (type == STRING)
|
||||
delete[] val.str;
|
||||
type = NIL;
|
||||
}
|
||||
|
||||
double Value::get_double() const throw()
|
||||
{
|
||||
ASSERT(type == DOUBLE, XLevelRuntime, "get_double: type not double");
|
||||
return val.dval;
|
||||
}
|
||||
|
||||
const char* Value::get_string() const throw()
|
||||
{
|
||||
ASSERT(type == STRING, XLevelRuntime, "get_string: type not string");
|
||||
return val.str;
|
||||
}
|
||||
|
||||
Buffer& enigma::operator<<(Buffer& buf, const Value& val)
|
||||
{
|
||||
buf << Uint8(val.get_type());
|
||||
|
||||
switch (val.get_type()) {
|
||||
case Value::NIL:
|
||||
break;
|
||||
case Value::DOUBLE:
|
||||
buf << val.get_double();
|
||||
break;
|
||||
case Value::STRING:
|
||||
{
|
||||
const char* str = val.get_string();
|
||||
buf << (Uint16)strlen(str);
|
||||
buf.write(str, strlen(str));
|
||||
} break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Buffer& enigma::operator>>(Buffer& buf, Value& val)
|
||||
// {
|
||||
// Uint8 type = Value::NIL;
|
||||
// buf >> type;
|
||||
|
||||
// switch (type) {
|
||||
// case Value::NIL:
|
||||
// // ## fixme
|
||||
// break;
|
||||
// case Value::DOUBLE:
|
||||
// {
|
||||
// double tmp;
|
||||
// if (buf >> tmp)
|
||||
// val = Value(tmp);
|
||||
// } break;
|
||||
// case Value::STRING:
|
||||
// {
|
||||
// Uint16 len;
|
||||
// if (buf >> len) {
|
||||
// char* tmp = new char[len+1];
|
||||
// tmp[len] = 0;
|
||||
// if (buf.read(tmp, len))
|
||||
// val.assign(tmp);
|
||||
// delete[] tmp;
|
||||
// }
|
||||
// } break;
|
||||
// }
|
||||
// return buf;
|
||||
// }
|
||||
|
||||
int enigma::to_int(const Value &v) {
|
||||
switch (v.get_type()) {
|
||||
case Value::DOUBLE: return round_nearest<int>(v.get_double());
|
||||
case Value::STRING: return atoi(v.get_string());
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool enigma::to_bool(const Value &v) {
|
||||
return (v.get_type() != Value::NIL);
|
||||
}
|
||||
|
||||
double enigma::to_double(const Value &v) {
|
||||
switch (v.get_type()) {
|
||||
case Value::DOUBLE: return v.get_double();
|
||||
case Value::STRING: return atof(v.get_string());
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
const char * enigma::to_string(const Value &v) {
|
||||
static char buf[30];
|
||||
switch (v.get_type()) {
|
||||
case Value::NIL: return "";
|
||||
case Value::DOUBLE:
|
||||
snprintf(buf, sizeof(buf), "%f", v.get_double());
|
||||
return buf;
|
||||
case Value::STRING: return v.get_string();
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Direction enigma::to_direction (const Value &v) {
|
||||
int val = Clamp(to_int(v), 0, 3);
|
||||
return static_cast<Direction>(val);
|
||||
}
|
||||
|
||||
ostream& enigma::operator<<(ostream& os, const Value& val)
|
||||
{
|
||||
switch (val.get_type()) {
|
||||
case Value::NIL: os << "nil"; break;
|
||||
case Value::DOUBLE: os << val.get_double(); break;
|
||||
case Value::STRING: os << val.get_string(); break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
/* -------------------- GridPos -------------------- */
|
||||
|
||||
GridPos::GridPos(const ecl::V2& p)
|
||||
: x (round_down<int>(p[0])),
|
||||
y (round_down<int>(p[1]))
|
||||
{}
|
||||
|
||||
|
||||
std::ostream& enigma::operator<<(std::ostream& os, const GridPos& val)
|
||||
{
|
||||
return os << '(' << val.x << ',' << val.y << ')';
|
||||
}
|
||||
|
||||
/*
|
||||
516
|
||||
203
|
||||
748
|
||||
*/
|
||||
GridPos enigma::get_neighbour (GridPos p, int i)
|
||||
{
|
||||
ASSERT (i >= 0 && i <= 9, XLevelRuntime, "get_neighbour: index out of bounds");
|
||||
static int xoff[9] = { 0,0,-1,1,0,-1,1,-1,1 };
|
||||
static int yoff[9] = { 0,-1,0,0,1,-1,-1,1,1 };
|
||||
return GridPos(p.x + xoff[i], p.y + yoff[i]);
|
||||
}
|
||||
|
||||
/* -------------------- GridLoc -------------------- */
|
||||
|
||||
bool enigma::to_gridloc (const char *str, GridLoc &l) {
|
||||
GridLoc loc;
|
||||
const char *numstr = str + 3;
|
||||
|
||||
if (strncmp (str, "fl(", 3) == 0)
|
||||
loc.layer = GRID_FLOOR;
|
||||
else if (strncmp (str, "it(", 3) == 0)
|
||||
loc.layer = GRID_ITEMS;
|
||||
else if (strncmp (str, "st(", 3) == 0)
|
||||
loc.layer = GRID_STONES;
|
||||
else
|
||||
numstr = str;
|
||||
|
||||
if (2 != sscanf (numstr, "%d %d", &loc.pos.x, &loc.pos.y))
|
||||
return false;
|
||||
l = loc;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* -------------------- Random numbers -------------------- */
|
||||
|
||||
void enigma::Randomize ()
|
||||
{
|
||||
srand (time(NULL));
|
||||
}
|
||||
|
||||
void enigma::Randomize (unsigned seed)
|
||||
{
|
||||
srand (seed);
|
||||
}
|
||||
|
||||
int enigma::IntegerRand (int min, int max)
|
||||
{
|
||||
int r = round_down<int>((max-min+1) * (rand()/(RAND_MAX+1.0)));
|
||||
return r+min;
|
||||
}
|
||||
|
||||
double enigma::DoubleRand (double min, double max)
|
||||
{
|
||||
return min + double(rand())/RAND_MAX * (max-min);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Time & Date -------------------- */
|
||||
|
||||
#define MAX_DATE_LENGTH 256
|
||||
const char *enigma::date(const char *format) { // format see 'man strftime'
|
||||
static char *result = 0;
|
||||
char buffer[MAX_DATE_LENGTH];
|
||||
|
||||
time_t t;
|
||||
time(&t);
|
||||
|
||||
struct tm *tm = localtime(&t);
|
||||
strftime(buffer, MAX_DATE_LENGTH, format, tm);
|
||||
|
||||
if (result) free(result);
|
||||
result = strdup(buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Resource management -------------------- */
|
||||
|
||||
namespace
|
||||
{
|
||||
struct FontDescr {
|
||||
// Variables
|
||||
string name;
|
||||
string ttf_name;
|
||||
int ttf_size;
|
||||
string bitmap_name;
|
||||
int r, g, b;
|
||||
|
||||
// Constructor
|
||||
FontDescr (const string &name_,
|
||||
const string &ttf_name_,
|
||||
int ttf_size_,
|
||||
const string &bitmap_name_,
|
||||
int r_, int g_, int b_)
|
||||
: name (name_),
|
||||
ttf_name (ttf_name_),
|
||||
ttf_size (ttf_size_),
|
||||
bitmap_name (bitmap_name_),
|
||||
r (r_), g(g_), b(b_)
|
||||
{}
|
||||
};
|
||||
|
||||
class FontCache : public PtrCache<Font> {
|
||||
public:
|
||||
Font *acquire (const std::string &name) {
|
||||
Font *f = 0;
|
||||
if (m_fonts.has_key (name)) {
|
||||
const FontDescr &fd = m_fonts[name];
|
||||
f = load_ttf (fd.ttf_name, fd.ttf_size, fd.r, fd.g, fd.b);
|
||||
if (f == 0) {
|
||||
std::cerr << "Could not load .ttf file " << fd.ttf_name << "\n";
|
||||
f = load_bmf (fd.bitmap_name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
f = load_bmf (name);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void define_font (const FontDescr &descr) {
|
||||
remove (descr.name); // remove entry in cache (if any)
|
||||
if (m_fonts.has_key (descr.name))
|
||||
m_fonts[descr.name]= descr;
|
||||
else
|
||||
m_fonts.insert (descr.name, descr);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Font *load_bmf (const string &name) {
|
||||
string png, bmf;
|
||||
if (app.resourceFS->findFile(string("fonts/")+name+".png", png) &&
|
||||
app.resourceFS->findFile(string("fonts/")+name+".bmf", bmf))
|
||||
{
|
||||
return ecl::LoadBitmapFont(png.c_str(), bmf.c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Font *load_ttf (const string &name, int ptsize, int r, int g, int b) {
|
||||
string ttf;
|
||||
if (app.resourceFS->findFile(string("fonts/") + name, ttf))
|
||||
return ecl::LoadTTF (ttf.c_str(), ptsize, r, g, b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Variables
|
||||
ecl::Dict <FontDescr> m_fonts;
|
||||
};
|
||||
|
||||
// ---------- Variables ----------
|
||||
|
||||
FontCache font_cache;
|
||||
ImageCache image_cache;
|
||||
}
|
||||
|
||||
ecl::Surface *ImageCache::acquire (const std::string &name)
|
||||
{
|
||||
return ecl::LoadImage(name.c_str());
|
||||
}
|
||||
|
||||
void enigma::DefineFont (const char *name,
|
||||
const char *ttf_name,
|
||||
int ttf_size,
|
||||
const char *bmf_name,
|
||||
int r, int g, int b)
|
||||
{
|
||||
font_cache.define_font (FontDescr (name, ttf_name, ttf_size, bmf_name, r, g, b));
|
||||
}
|
||||
|
||||
ecl::Font *enigma::GetFont (const char *name)
|
||||
{
|
||||
return font_cache.get(name);
|
||||
}
|
||||
|
||||
void enigma::ClearFontCache() {
|
||||
font_cache.clear();
|
||||
}
|
||||
|
||||
ecl::Surface *enigma::LoadImage(const char *name)
|
||||
{
|
||||
string filename;
|
||||
if (app.resourceFS->findImageFile (string(name) + ".png", filename))
|
||||
return ecl::LoadImage(filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecl::Surface *enigma::GetImage(const char *name, const char *ext)
|
||||
{
|
||||
string filename;
|
||||
if (app.resourceFS->findImageFile (string(name) + ext, filename))
|
||||
return image_cache.get(filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecl::Surface *enigma::RegisterImage (const char *name, ecl::Surface *s)
|
||||
{
|
||||
image_cache.store(name, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void enigma::ClearImageCache() {
|
||||
image_cache.clear();
|
||||
}
|
||||
946
project/jni/application/enigma/src/enigma.doxygen
Normal file
946
project/jni/application/enigma/src/enigma.doxygen
Normal file
@@ -0,0 +1,946 @@
|
||||
# Doxyfile 1.2.16
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project
|
||||
#
|
||||
# All text after a hash (#) is considered a comment and will be ignored
|
||||
# The format is:
|
||||
# TAG = value [value, ...]
|
||||
# For lists items can also be appended using:
|
||||
# TAG += value [value, ...]
|
||||
# Values that contain spaces should be placed between quotes (" ")
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# General configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
|
||||
# by quotes) that should identify the project.
|
||||
|
||||
PROJECT_NAME =
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER =
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = doc
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
# The default language is English, other supported languages are:
|
||||
# Brazilian, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
|
||||
# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Korean,
|
||||
# Norwegian, Polish, Portuguese, Romanian, Russian, Slovak, Slovene,
|
||||
# Spanish, Swedish and Ukrainian.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
|
||||
# documentation are documented, even if no documentation was available.
|
||||
# Private class members and static file members will be hidden unless
|
||||
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
|
||||
|
||||
EXTRACT_ALL = NO
|
||||
|
||||
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_PRIVATE = NO
|
||||
|
||||
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_STATIC = NO
|
||||
|
||||
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
|
||||
# defined locally in source files will be included in the documentation.
|
||||
# If set to NO only classes defined in header files are included.
|
||||
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
|
||||
# undocumented members of documented classes, files or namespaces.
|
||||
# If set to NO (the default) these members will be included in the
|
||||
# various overviews, but no documentation section is generated.
|
||||
# This option has no effect if EXTRACT_ALL is enabled.
|
||||
|
||||
HIDE_UNDOC_MEMBERS = YES
|
||||
|
||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
|
||||
# undocumented classes that are normally visible in the class hierarchy.
|
||||
# If set to NO (the default) these class will be included in the various
|
||||
# overviews. This option has no effect if EXTRACT_ALL is enabled.
|
||||
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
||||
# include brief member descriptions after the members that are listed in
|
||||
# the file and class documentation (similar to JavaDoc).
|
||||
# Set to NO to disable this.
|
||||
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
|
||||
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
|
||||
# the brief description of a member or function before the detailed description.
|
||||
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
|
||||
# brief descriptions will be completely suppressed.
|
||||
|
||||
REPEAT_BRIEF = YES
|
||||
|
||||
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
|
||||
# Doxygen will generate a detailed section even if there is only a brief
|
||||
# description.
|
||||
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
|
||||
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
|
||||
# members of a class in the documentation of that class as if those members were
|
||||
# ordinary class members. Constructors, destructors and assignment operators of
|
||||
# the base classes will not be shown.
|
||||
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
|
||||
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
|
||||
# path before files name in the file list and in the header files. If set
|
||||
# to NO the shortest path that makes the file name unique will be used.
|
||||
|
||||
FULL_PATH_NAMES = NO
|
||||
|
||||
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
|
||||
# can be used to strip a user defined part of the path. Stripping is
|
||||
# only done if one of the specified strings matches the left-hand part of
|
||||
# the path. It is allowed to use relative paths in the argument list.
|
||||
|
||||
STRIP_FROM_PATH =
|
||||
|
||||
# The INTERNAL_DOCS tag determines if documentation
|
||||
# that is typed after a \internal command is included. If the tag is set
|
||||
# to NO (the default) then the documentation will be excluded.
|
||||
# Set it to YES to include the internal documentation.
|
||||
|
||||
INTERNAL_DOCS = NO
|
||||
|
||||
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
|
||||
# doxygen to hide any special comment blocks from generated source code
|
||||
# fragments. Normal C and C++ comments will always remain visible.
|
||||
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
|
||||
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
|
||||
# file names in lower case letters. If set to YES upper case letters are also
|
||||
# allowed. This is useful if you have classes or files whose names only differ
|
||||
# in case and if your file system supports case sensitive file names. Windows
|
||||
# users are adviced to set this option to NO.
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
|
||||
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
|
||||
# (but less readable) file names. This can be useful is your file systems
|
||||
# doesn't support long names like on DOS, Mac, or CD-ROM.
|
||||
|
||||
SHORT_NAMES = NO
|
||||
|
||||
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
|
||||
# will show members with their full class and namespace scopes in the
|
||||
# documentation. If set to YES the scope will be hidden.
|
||||
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
|
||||
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
|
||||
# will generate a verbatim copy of the header file for each class for
|
||||
# which an include is specified. Set to NO to disable this.
|
||||
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
|
||||
# will put list of the files that are included by a file in the documentation
|
||||
# of that file.
|
||||
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
|
||||
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
|
||||
# will interpret the first line (until the first dot) of a JavaDoc-style
|
||||
# comment as the brief description. If set to NO, the JavaDoc
|
||||
# comments will behave just like the Qt-style comments (thus requiring an
|
||||
# explict @brief command for a brief description.
|
||||
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
|
||||
# If the DETAILS_AT_TOP tag is set to YES then Doxygen
|
||||
# will output the detailed description near the top, like JavaDoc.
|
||||
# If set to NO, the detailed description appears after the member
|
||||
# documentation.
|
||||
|
||||
DETAILS_AT_TOP = NO
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
||||
# member inherits the documentation from any documented member that it
|
||||
# reimplements.
|
||||
|
||||
INHERIT_DOCS = YES
|
||||
|
||||
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
|
||||
# is inserted in the documentation for inline members.
|
||||
|
||||
INLINE_INFO = YES
|
||||
|
||||
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
|
||||
# will sort the (detailed) documentation of file and class members
|
||||
# alphabetically by member name. If set to NO the members will appear in
|
||||
# declaration order.
|
||||
|
||||
SORT_MEMBER_DOCS = YES
|
||||
|
||||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
||||
# tag is set to YES, then doxygen will reuse the documentation of the first
|
||||
# member in the group (if any) for the other members of the group. By default
|
||||
# all members of a group must be documented explicitly.
|
||||
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
|
||||
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
||||
# Doxygen uses this value to replace tabs by spaces in code fragments.
|
||||
|
||||
TAB_SIZE = 8
|
||||
|
||||
# The GENERATE_TODOLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the todo list. This list is created by putting \todo
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_TODOLIST = YES
|
||||
|
||||
# The GENERATE_TESTLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the test list. This list is created by putting \test
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_TESTLIST = YES
|
||||
|
||||
# The GENERATE_BUGLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the bug list. This list is created by putting \bug
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_BUGLIST = YES
|
||||
|
||||
# This tag can be used to specify a number of aliases that acts
|
||||
# as commands in the documentation. An alias has the form "name=value".
|
||||
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
|
||||
# put the command \sideeffect (or @sideeffect) in the documentation, which
|
||||
# will result in a user defined paragraph with heading "Side Effects:".
|
||||
# You can put \n's in the value part of an alias to insert newlines.
|
||||
|
||||
ALIASES =
|
||||
|
||||
# The ENABLED_SECTIONS tag can be used to enable conditional
|
||||
# documentation sections, marked by \if sectionname ... \endif.
|
||||
|
||||
ENABLED_SECTIONS =
|
||||
|
||||
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
|
||||
# the initial value of a variable or define consist of for it to appear in
|
||||
# the documentation. If the initializer consists of more lines than specified
|
||||
# here it will be hidden. Use a value of 0 to hide initializers completely.
|
||||
# The appearance of the initializer of individual variables and defines in the
|
||||
# documentation can be controlled using \showinitializer or \hideinitializer
|
||||
# command in the documentation regardless of this setting.
|
||||
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
|
||||
# only. Doxygen will then generate output that is more tailored for C.
|
||||
# For instance some of the names that are used will be different. The list
|
||||
# of all members will be omitted, etc.
|
||||
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
|
||||
# only. Doxygen will then generate output that is more tailored for Java.
|
||||
# For instance namespaces will be presented as packages, qualified scopes
|
||||
# will look different, etc.
|
||||
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
|
||||
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
|
||||
# at the bottom of the documentation of classes and structs. If set to YES the
|
||||
# list will mention the files that were used to generate the documentation.
|
||||
|
||||
SHOW_USED_FILES = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The QUIET tag can be used to turn on/off the messages that are generated
|
||||
# by doxygen. Possible values are YES and NO. If left blank NO is used.
|
||||
|
||||
QUIET = NO
|
||||
|
||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||
# generated by doxygen. Possible values are YES and NO. If left blank
|
||||
# NO is used.
|
||||
|
||||
WARNINGS = YES
|
||||
|
||||
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
|
||||
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
|
||||
# automatically be disabled.
|
||||
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
|
||||
# The WARN_FORMAT tag determines the format of the warning messages that
|
||||
# doxygen can produce. The string should contain the $file, $line, and $text
|
||||
# tags, which will be replaced by the file and line number from which the
|
||||
# warning originated and the warning text.
|
||||
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
|
||||
# The WARN_LOGFILE tag can be used to specify a file to which warning
|
||||
# and error messages should be written. If left blank the output is written
|
||||
# to stderr.
|
||||
|
||||
WARN_LOGFILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The INPUT tag can be used to specify the files and/or directories that contain
|
||||
# documented source files. You may enter file names like "myfile.cpp" or
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = enigma.cc world.hh objects.cc actors.cc laser.cc items.cc
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank the following patterns are tested:
|
||||
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
|
||||
# *.h++ *.idl *.odl
|
||||
|
||||
FILE_PATTERNS =
|
||||
|
||||
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
|
||||
# should be searched for input files as well. Possible values are YES and NO.
|
||||
# If left blank NO is used.
|
||||
|
||||
RECURSIVE = NO
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
||||
|
||||
EXCLUDE =
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
|
||||
# that are symbolic links (a Unix filesystem feature) are excluded from the input.
|
||||
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
||||
# certain files from those directories.
|
||||
|
||||
EXCLUDE_PATTERNS =
|
||||
|
||||
# The EXAMPLE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH =
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank all files are included.
|
||||
|
||||
EXAMPLE_PATTERNS =
|
||||
|
||||
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
|
||||
# searched for input files to be used with the \include or \dontinclude
|
||||
# commands irrespective of the value of the RECURSIVE tag.
|
||||
# Possible values are YES and NO. If left blank NO is used.
|
||||
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
|
||||
# The IMAGE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain image that are included in the documentation (see
|
||||
# the \image command).
|
||||
|
||||
IMAGE_PATH = gfx
|
||||
|
||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
||||
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
||||
# input file. Doxygen will then use the output that the filter program writes
|
||||
# to standard output.
|
||||
|
||||
INPUT_FILTER =
|
||||
|
||||
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
|
||||
# INPUT_FILTER) will be used to filter the input files when producing source
|
||||
# files to browse.
|
||||
|
||||
FILTER_SOURCE_FILES = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
|
||||
# be generated. Documented entities will be cross-referenced with these sources.
|
||||
|
||||
SOURCE_BROWSER = NO
|
||||
|
||||
# Setting the INLINE_SOURCES tag to YES will include the body
|
||||
# of functions and classes directly in the documentation.
|
||||
|
||||
INLINE_SOURCES = NO
|
||||
|
||||
# If the REFERENCED_BY_RELATION tag is set to YES (the default)
|
||||
# then for each documented function all documented
|
||||
# functions referencing it will be listed.
|
||||
|
||||
REFERENCED_BY_RELATION = YES
|
||||
|
||||
# If the REFERENCES_RELATION tag is set to YES (the default)
|
||||
# then for each documented function all documented entities
|
||||
# called/used by that function will be listed.
|
||||
|
||||
REFERENCES_RELATION = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
|
||||
# of all compounds will be generated. Enable this if the project
|
||||
# contains a lot of classes, structs, unions or interfaces.
|
||||
|
||||
ALPHABETICAL_INDEX = NO
|
||||
|
||||
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
|
||||
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
|
||||
# in which this list will be split (can be a number in the range [1..20])
|
||||
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
|
||||
# In case all classes in a project start with a common prefix, all
|
||||
# classes will be put under the same header in the alphabetical index.
|
||||
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
|
||||
# should be ignored while generating the index headers.
|
||||
|
||||
IGNORE_PREFIX =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
|
||||
# generate HTML output.
|
||||
|
||||
GENERATE_HTML = YES
|
||||
|
||||
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `html' will be used as the default path.
|
||||
|
||||
HTML_OUTPUT = html
|
||||
|
||||
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
|
||||
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
|
||||
# doxygen will generate files with .html extension.
|
||||
|
||||
HTML_FILE_EXTENSION = .html
|
||||
|
||||
# The HTML_HEADER tag can be used to specify a personal HTML header for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard header.
|
||||
|
||||
HTML_HEADER =
|
||||
|
||||
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard footer.
|
||||
|
||||
HTML_FOOTER =
|
||||
|
||||
# The HTML_STYLESHEET tag can be used to specify a user defined cascading
|
||||
# style sheet that is used by each HTML page. It can be used to
|
||||
# fine-tune the look of the HTML output. If the tag is left blank doxygen
|
||||
# will generate a default style sheet
|
||||
|
||||
HTML_STYLESHEET =
|
||||
|
||||
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
||||
# files or namespaces will be aligned in HTML using tables. If set to
|
||||
# NO a bullet list will be used.
|
||||
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for tools like the
|
||||
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
|
||||
# of the generated HTML documentation.
|
||||
|
||||
GENERATE_HTMLHELP = NO
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
|
||||
# controls if a separate .chi index file is generated (YES) or that
|
||||
# it should be included in the master .chm file (NO).
|
||||
|
||||
GENERATE_CHI = NO
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
|
||||
# controls whether a binary table of contents is generated (YES) or a
|
||||
# normal table of contents (NO) in the .chm file.
|
||||
|
||||
BINARY_TOC = NO
|
||||
|
||||
# The TOC_EXPAND flag can be set to YES to add extra items for group members
|
||||
# to the contents of the Html help documentation and to the tree view.
|
||||
|
||||
TOC_EXPAND = NO
|
||||
|
||||
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
||||
# top of each HTML page. The value NO (the default) enables the index and
|
||||
# the value YES disables it.
|
||||
|
||||
DISABLE_INDEX = NO
|
||||
|
||||
# This tag can be used to set the number of enum values (range [1..20])
|
||||
# that doxygen will group on one line in the generated HTML documentation.
|
||||
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
|
||||
# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
|
||||
# generated containing a tree-like index structure (just like the one that
|
||||
# is generated for HTML Help). For this to work a browser that supports
|
||||
# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
|
||||
# or Internet explorer 4.0+). Note that for large projects the tree generation
|
||||
# can take a very long time. In such cases it is better to disable this feature.
|
||||
# Windows users are probably better off using the HTML help feature.
|
||||
|
||||
GENERATE_TREEVIEW = NO
|
||||
|
||||
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
|
||||
# used to set the initial width (in pixels) of the frame in which the tree
|
||||
# is shown.
|
||||
|
||||
TREEVIEW_WIDTH = 250
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||
# generate Latex output.
|
||||
|
||||
GENERATE_LATEX = YES
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `latex' will be used as the default path.
|
||||
|
||||
LATEX_OUTPUT = latex
|
||||
|
||||
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
|
||||
|
||||
LATEX_CMD_NAME = latex
|
||||
|
||||
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
|
||||
# generate index for LaTeX. If left blank `makeindex' will be used as the
|
||||
# default command name.
|
||||
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
|
||||
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
|
||||
# LaTeX documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_LATEX = NO
|
||||
|
||||
# The PAPER_TYPE tag can be used to set the paper type that is used
|
||||
# by the printer. Possible values are: a4, a4wide, letter, legal and
|
||||
# executive. If left blank a4wide will be used.
|
||||
|
||||
PAPER_TYPE = a4wide
|
||||
|
||||
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
|
||||
# packages that should be included in the LaTeX output.
|
||||
|
||||
EXTRA_PACKAGES =
|
||||
|
||||
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
|
||||
# the generated latex document. The header should contain everything until
|
||||
# the first chapter. If it is left blank doxygen will generate a
|
||||
# standard header. Notice: only use this tag if you know what you are doing!
|
||||
|
||||
LATEX_HEADER =
|
||||
|
||||
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
|
||||
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
|
||||
# contain links (just like the HTML output) instead of page references
|
||||
# This makes the output suitable for online browsing using a pdf viewer.
|
||||
|
||||
PDF_HYPERLINKS = NO
|
||||
|
||||
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
|
||||
# plain latex in the generated Makefile. Set this option to YES to get a
|
||||
# higher quality PDF documentation.
|
||||
|
||||
USE_PDFLATEX = NO
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep
|
||||
# running if errors occur, instead of asking the user for help.
|
||||
# This option is also used when generating formulas in HTML.
|
||||
|
||||
LATEX_BATCHMODE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
|
||||
# The RTF output is optimised for Word 97 and may not look very pretty with
|
||||
# other RTF readers or editors.
|
||||
|
||||
GENERATE_RTF = NO
|
||||
|
||||
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `rtf' will be used as the default path.
|
||||
|
||||
RTF_OUTPUT = rtf
|
||||
|
||||
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
|
||||
# RTF documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_RTF = NO
|
||||
|
||||
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
|
||||
# will contain hyperlink fields. The RTF file will
|
||||
# contain links (just like the HTML output) instead of page references.
|
||||
# This makes the output suitable for online browsing using WORD or other
|
||||
# programs which support those fields.
|
||||
# Note: wordpad (write) and others do not support links.
|
||||
|
||||
RTF_HYPERLINKS = NO
|
||||
|
||||
# Load stylesheet definitions from file. Syntax is similar to doxygen's
|
||||
# config file, i.e. a series of assigments. You only have to provide
|
||||
# replacements, missing definitions are set to their default value.
|
||||
|
||||
RTF_STYLESHEET_FILE =
|
||||
|
||||
# Set optional variables used in the generation of an rtf document.
|
||||
# Syntax is similar to doxygen's config file.
|
||||
|
||||
RTF_EXTENSIONS_FILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
||||
# generate man pages
|
||||
|
||||
GENERATE_MAN = NO
|
||||
|
||||
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `man' will be used as the default path.
|
||||
|
||||
MAN_OUTPUT = man
|
||||
|
||||
# The MAN_EXTENSION tag determines the extension that is added to
|
||||
# the generated man pages (default is the subroutine's section .3)
|
||||
|
||||
MAN_EXTENSION = .3
|
||||
|
||||
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
|
||||
# then it will generate one additional man file for each entity
|
||||
# documented in the real man page(s). These additional files
|
||||
# only source the real man page, but without them the man command
|
||||
# would be unable to find the correct page. The default is NO.
|
||||
|
||||
MAN_LINKS = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_XML tag is set to YES Doxygen will
|
||||
# generate an XML file that captures the structure of
|
||||
# the code including all documentation. Note that this
|
||||
# feature is still experimental and incomplete at the
|
||||
# moment.
|
||||
|
||||
GENERATE_XML = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
|
||||
# generate an AutoGen Definitions (see autogen.sf.net) file
|
||||
# that captures the structure of the code including all
|
||||
# documentation. Note that this feature is still experimental
|
||||
# and incomplete at the moment.
|
||||
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
|
||||
# evaluate all C-preprocessor directives found in the sources and include
|
||||
# files.
|
||||
|
||||
ENABLE_PREPROCESSING = YES
|
||||
|
||||
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
|
||||
# names in the source code. If set to NO (the default) only conditional
|
||||
# compilation will be performed. Macro expansion can be done in a controlled
|
||||
# way by setting EXPAND_ONLY_PREDEF to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
|
||||
# then the macro expansion is limited to the macros specified with the
|
||||
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
|
||||
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
|
||||
# in the INCLUDE_PATH (see below) will be search if a #include is found.
|
||||
|
||||
SEARCH_INCLUDES = YES
|
||||
|
||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||
# contain include files that are not input files but should be processed by
|
||||
# the preprocessor.
|
||||
|
||||
INCLUDE_PATH =
|
||||
|
||||
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
||||
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
||||
# directories. If left blank, the patterns specified with FILE_PATTERNS will
|
||||
# be used.
|
||||
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
|
||||
# The PREDEFINED tag can be used to specify one or more macro names that
|
||||
# are defined before the preprocessor is started (similar to the -D option of
|
||||
# gcc). The argument of the tag is a list of macros of the form: name
|
||||
# or name=definition (no spaces). If the definition and the = are
|
||||
# omitted =1 is assumed.
|
||||
|
||||
PREDEFINED =
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
|
||||
# this tag can be used to specify a list of macro names that should be expanded.
|
||||
# The macro definition that is found in the sources will be used.
|
||||
# Use the PREDEFINED tag if you want to use a different macro definition.
|
||||
|
||||
EXPAND_AS_DEFINED =
|
||||
|
||||
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
|
||||
# doxygen's preprocessor will remove all function-like macros that are alone
|
||||
# on a line and do not end with a semicolon. Such function macros are typically
|
||||
# used for boiler-plate code, and will confuse the parser if not removed.
|
||||
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The TAGFILES tag can be used to specify one or more tagfiles.
|
||||
|
||||
TAGFILES =
|
||||
|
||||
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
||||
# a tag file that is based on the input files it reads.
|
||||
|
||||
GENERATE_TAGFILE =
|
||||
|
||||
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
||||
# in the class index. If set to NO only the inherited external classes
|
||||
# will be listed.
|
||||
|
||||
ALLEXTERNALS = NO
|
||||
|
||||
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
|
||||
# in the modules index. If set to NO, only the current project's groups will
|
||||
# be listed.
|
||||
|
||||
EXTERNAL_GROUPS = YES
|
||||
|
||||
# The PERL_PATH should be the absolute path and name of the perl script
|
||||
# interpreter (i.e. the result of `which perl').
|
||||
|
||||
PERL_PATH = /usr/bin/perl
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
|
||||
# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
|
||||
# super classes. Setting the tag to NO turns the diagrams off. Note that this
|
||||
# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
|
||||
# recommended to install and use dot, since it yield more powerful graphs.
|
||||
|
||||
CLASS_DIAGRAMS = YES
|
||||
|
||||
# If set to YES, the inheritance and collaboration graphs will hide
|
||||
# inheritance and usage relations if the target is undocumented
|
||||
# or is not a class.
|
||||
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
|
||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||
# available from the path. This tool is part of Graphviz, a graph visualization
|
||||
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
||||
# have no effect if this option is set to NO (the default)
|
||||
|
||||
HAVE_DOT = NO
|
||||
|
||||
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
# indirect inheritance relations. Setting this tag to YES will force the
|
||||
# the CLASS_DIAGRAMS tag to NO.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
|
||||
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
# indirect implementation dependencies (inheritance, containment, and
|
||||
# class references variables) of the class with other documented classes.
|
||||
|
||||
COLLABORATION_GRAPH = YES
|
||||
|
||||
# If set to YES, the inheritance and collaboration graphs will show the
|
||||
# relations between templates and their instances.
|
||||
|
||||
TEMPLATE_RELATIONS = YES
|
||||
|
||||
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
|
||||
# tags are set to YES then doxygen will generate a graph for each documented
|
||||
# file showing the direct and indirect include dependencies of the file with
|
||||
# other documented files.
|
||||
|
||||
INCLUDE_GRAPH = YES
|
||||
|
||||
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
|
||||
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
|
||||
# documented header file showing the documented files that directly or
|
||||
# indirectly include this file.
|
||||
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
|
||||
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
||||
# will graphical hierarchy of all classes instead of a textual one.
|
||||
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
|
||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||
# generated by dot. Possible values are png, jpg, or gif
|
||||
# If left blank png will be used.
|
||||
|
||||
DOT_IMAGE_FORMAT = png
|
||||
|
||||
# The tag DOT_PATH can be used to specify the path where the dot tool can be
|
||||
# found. If left blank, it is assumed the dot tool can be found on the path.
|
||||
|
||||
DOT_PATH =
|
||||
|
||||
# The DOTFILE_DIRS tag can be used to specify one or more directories that
|
||||
# contain dot files that are included in the documentation (see the
|
||||
# \dotfile command).
|
||||
|
||||
DOTFILE_DIRS =
|
||||
|
||||
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
|
||||
# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
|
||||
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
|
||||
# generate a legend page explaining the meaning of the various boxes and
|
||||
# arrows in the dot generated graphs.
|
||||
|
||||
GENERATE_LEGEND = YES
|
||||
|
||||
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
|
||||
# remove the intermedate dot files that are used to generate
|
||||
# the various graphs.
|
||||
|
||||
DOT_CLEANUP = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
||||
# used. If set to NO the values of all tags below this one will be ignored.
|
||||
|
||||
SEARCHENGINE = NO
|
||||
|
||||
# The CGI_NAME tag should be the name of the CGI script that
|
||||
# starts the search engine (doxysearch) with the correct parameters.
|
||||
# A script with this name will be generated by doxygen.
|
||||
|
||||
CGI_NAME = search.cgi
|
||||
|
||||
# The CGI_URL tag should be the absolute URL to the directory where the
|
||||
# cgi binaries are located. See the documentation of your http daemon for
|
||||
# details.
|
||||
|
||||
CGI_URL =
|
||||
|
||||
# The DOC_URL tag should be the absolute URL to the directory where the
|
||||
# documentation is located. If left blank the absolute path to the
|
||||
# documentation, with file:// prepended to it, will be used.
|
||||
|
||||
DOC_URL =
|
||||
|
||||
# The DOC_ABSPATH tag should be the absolute path to the directory where the
|
||||
# documentation is located. If left blank the directory on the local machine
|
||||
# will be used.
|
||||
|
||||
DOC_ABSPATH =
|
||||
|
||||
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
|
||||
# is installed.
|
||||
|
||||
BIN_ABSPATH = /usr/local/bin/
|
||||
|
||||
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
|
||||
# documentation generated for other projects. This allows doxysearch to search
|
||||
# the documentation for these projects as well.
|
||||
|
||||
EXT_DOC_PATHS =
|
||||
323
project/jni/application/enigma/src/enigma.hh
Normal file
323
project/jni/application/enigma/src/enigma.hh
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef ENIGMA_HH
|
||||
#define ENIGMA_HH
|
||||
|
||||
/*
|
||||
* This file contains declarations for facilities used by several
|
||||
* different parts of the program, like common types and constants,
|
||||
* and routines for resource management.
|
||||
*/
|
||||
|
||||
#include "fwd.hh"
|
||||
#include "file.hh"
|
||||
#include "ecl_fwd.hh"
|
||||
#include "ecl_math.hh"
|
||||
#include "ecl_util.hh"
|
||||
#include "ecl_cache.hh"
|
||||
|
||||
#define NUMENTRIES(array) (sizeof(array)/sizeof(*array))
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
|
||||
/* -------------------- Various types -------------------- */
|
||||
|
||||
enum Difficulty {
|
||||
DIFFICULTY_EASY = 1,
|
||||
DIFFICULTY_HARD = 2,
|
||||
DIFFICULTY_ANY = 3
|
||||
};
|
||||
|
||||
|
||||
/*! Enigma can run its own levels but also emulate various
|
||||
versions of Oxyd. All these games behave similarly, but there
|
||||
are a few differences in object behaviour, visual appearance,
|
||||
etc. */
|
||||
enum GameType {
|
||||
GAMET_FIRST,
|
||||
|
||||
GAMET_ENIGMA = GAMET_FIRST,
|
||||
GAMET_OXYD1,
|
||||
GAMET_PEROXYD,
|
||||
GAMET_OXYDEXTRA,
|
||||
GAMET_OXYDMAGNUM,
|
||||
|
||||
GAMET_LAST = GAMET_OXYDMAGNUM,
|
||||
GAMET_COUNT,
|
||||
GAMET_UNKNOWN
|
||||
};
|
||||
|
||||
GameType GetGameType(std::string name);
|
||||
std::string GetGameTypeName(GameType type);
|
||||
|
||||
/* -------------------- Resource Management -------------------- */
|
||||
|
||||
class ImageCache : public ecl::PtrCache<ecl::Surface> {
|
||||
public:
|
||||
using ecl::PtrCache<ecl::Surface>::store;
|
||||
|
||||
ecl::Surface *acquire(const std::string &name);
|
||||
};
|
||||
|
||||
|
||||
/* The `Get...' functions return a pointer to a cached copy of the
|
||||
font or image. The `Load...' functions load a new copy which
|
||||
you must deallocate yourself. */
|
||||
|
||||
|
||||
void DefineFont (const char *name,
|
||||
const char *ttf_name,
|
||||
int ttf_size,
|
||||
const char *bmf_name,
|
||||
int r, int g, int b);
|
||||
ecl::Font *GetFont (const char *name);
|
||||
void ClearFontCache();
|
||||
|
||||
ecl::Surface *LoadImage (const char *name);
|
||||
ecl::Surface *GetImage (const char *name, const char *ext = ".png");
|
||||
ecl::Surface *RegisterImage (const char *name, ecl::Surface *s);
|
||||
void ClearImageCache();
|
||||
|
||||
/* -------------------- Direction, DirectionBits -------------------- */
|
||||
|
||||
enum Direction {
|
||||
NODIR = -1,
|
||||
WEST = 0,
|
||||
SOUTH = 1,
|
||||
EAST = 2,
|
||||
NORTH = 3,
|
||||
};
|
||||
|
||||
Direction reverse (Direction d);
|
||||
Direction rotate_cw (Direction d);
|
||||
Direction rotate_ccw (Direction d);
|
||||
|
||||
std::string to_suffix(Direction d);
|
||||
|
||||
enum DirectionBits {
|
||||
NODIRBIT = 0,
|
||||
WESTBIT = 1 << WEST,
|
||||
SOUTHBIT = 1 << SOUTH,
|
||||
EASTBIT = 1 << EAST,
|
||||
NORTHBIT = 1 << NORTH,
|
||||
ALL_DIRECTIONS = 15
|
||||
};
|
||||
|
||||
DirectionBits rotate (DirectionBits d, bool clockwise);
|
||||
DirectionBits to_bits (Direction d);
|
||||
bool has_dir (DirectionBits db, Direction dir);
|
||||
|
||||
|
||||
/* -------------------- Value -------------------- */
|
||||
|
||||
class Value {
|
||||
public:
|
||||
enum Type { NIL, DOUBLE, STRING };
|
||||
|
||||
Value() : type(NIL) {}
|
||||
Value(double d) : type(DOUBLE) { val.dval = d; }
|
||||
Value(const char* str);
|
||||
Value(const std::string& str);
|
||||
~Value();
|
||||
|
||||
Value(const Value& v);
|
||||
Value& operator=(const Value& v);
|
||||
|
||||
void assign(double d);
|
||||
void assign(const char* s);
|
||||
|
||||
Type get_type() const { return type; }
|
||||
double get_double() const throw();
|
||||
const char* get_string() const throw();
|
||||
private:
|
||||
void clear();
|
||||
|
||||
// Variables
|
||||
Type type;
|
||||
union {
|
||||
double dval;
|
||||
char* str;
|
||||
} val;
|
||||
};
|
||||
|
||||
ecl::Buffer& operator<<(ecl::Buffer& buf, const Value& val);
|
||||
// ecl::Buffer& operator>>(ecl::Buffer& buf, Value& val);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Value& val);
|
||||
|
||||
bool to_bool(const Value &v);
|
||||
int to_int(const Value &v);
|
||||
double to_double(const Value &v);
|
||||
const char *to_string(const Value &v);
|
||||
Direction to_direction (const Value &v);
|
||||
|
||||
/* -------------------- Timers -------------------- */
|
||||
|
||||
/* Interface for time event handlers. */
|
||||
class TimeHandler {
|
||||
public:
|
||||
virtual ~TimeHandler() {}
|
||||
virtual void tick (double /*dtime*/) {}
|
||||
virtual void alarm() {}
|
||||
};
|
||||
|
||||
/* -------------------- GridPos -------------------- */
|
||||
|
||||
struct GridPos {
|
||||
// Variables
|
||||
int x, y;
|
||||
|
||||
// Methods
|
||||
explicit GridPos(int xx=0, int yy=0);
|
||||
explicit GridPos(const ecl::V2& p);
|
||||
void move(Direction dir);
|
||||
ecl::V2 center() const;
|
||||
};
|
||||
|
||||
GridPos move(GridPos p, Direction dir);
|
||||
GridPos move(GridPos p, Direction dir, Direction dir2);
|
||||
bool operator== (GridPos a, GridPos b);
|
||||
bool operator != (GridPos a, GridPos b);
|
||||
bool operator< (GridPos a, GridPos b);
|
||||
|
||||
/* 516
|
||||
203
|
||||
748 */
|
||||
GridPos get_neighbour (GridPos p, int i);
|
||||
|
||||
// source and target have to be adjacent
|
||||
Direction direction_fromto(GridPos source, GridPos target);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const GridPos& val);
|
||||
|
||||
|
||||
// ---------- GridLayer ----------
|
||||
|
||||
enum GridLayer {
|
||||
GRID_FLOOR,
|
||||
GRID_ITEMS,
|
||||
GRID_STONES,
|
||||
GRID_COUNT
|
||||
};
|
||||
|
||||
enum GridLayerBits {
|
||||
GRID_FLOOR_BIT = 1,
|
||||
GRID_ITEMS_BIT = 2,
|
||||
GRID_STONES_BIT = 4
|
||||
};
|
||||
|
||||
// ---------- GridLoc ----------
|
||||
|
||||
struct GridLoc {
|
||||
// Variables
|
||||
GridPos pos;
|
||||
GridLayer layer;
|
||||
|
||||
// Constructor
|
||||
GridLoc(GridLayer l = GRID_FLOOR, GridPos p = GridPos());
|
||||
};
|
||||
|
||||
/*! Converts strings like "it(10 10)", "st(5 2)" to GridLoc
|
||||
structures. */
|
||||
bool to_gridloc (const char *str, GridLoc &loc);
|
||||
|
||||
|
||||
/* -------------------- Random Numbers -------------------- */
|
||||
|
||||
void Randomize ();
|
||||
void Randomize (unsigned seed);
|
||||
int IntegerRand (int min, int max);
|
||||
double DoubleRand (double min, double max);
|
||||
|
||||
/* -------------------- Time & Date -------------------- */
|
||||
|
||||
const char *date(const char *format); // format see 'man strftime'
|
||||
|
||||
|
||||
/* ==================== Inline definitions ==================== */
|
||||
|
||||
inline DirectionBits to_bits(Direction d) {
|
||||
if (d==NODIR)
|
||||
return NODIRBIT;
|
||||
return DirectionBits(1 << d);
|
||||
}
|
||||
|
||||
inline bool has_dir(DirectionBits db, Direction dir) {
|
||||
return (db & to_bits(dir)) != 0;
|
||||
}
|
||||
|
||||
|
||||
// ---------- GridPos ----------
|
||||
|
||||
inline GridPos::GridPos(int xx, int yy)
|
||||
: x(xx), y(yy)
|
||||
{}
|
||||
|
||||
|
||||
inline void GridPos::move(Direction dir) {
|
||||
switch(dir) {
|
||||
case NORTH: y--; break;
|
||||
case SOUTH: y++; break;
|
||||
case EAST: x++; break;
|
||||
case WEST: x--; break;
|
||||
case NODIR: break;
|
||||
}
|
||||
}
|
||||
|
||||
inline ecl::V2 GridPos::center() const {
|
||||
return ecl::V2(x+.5, y+.5);
|
||||
}
|
||||
|
||||
|
||||
inline GridPos move(GridPos p, Direction dir) {
|
||||
GridPos tmp = p;
|
||||
tmp.move(dir);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline GridPos move(GridPos p, Direction dir, Direction dir2) {
|
||||
GridPos tmp = p;
|
||||
tmp.move(dir);
|
||||
tmp.move(dir2);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline bool operator == (GridPos a, GridPos b) {
|
||||
return (a.x==b.x && a.y==b.y);
|
||||
}
|
||||
|
||||
inline bool operator != (GridPos a, GridPos b) {
|
||||
return (a.x!=b.x || a.y!=b.y);
|
||||
}
|
||||
|
||||
inline bool operator< (GridPos a, GridPos b) {
|
||||
return ((a.y<<16) + a.x) < ((b.y<<16) + b.x);
|
||||
}
|
||||
|
||||
|
||||
// ---------- GridLoc ----------
|
||||
|
||||
inline GridLoc::GridLoc(GridLayer l, GridPos p)
|
||||
: pos(p), layer(l)
|
||||
{}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
BIN
project/jni/application/enigma/src/enigma.ico
Normal file
BIN
project/jni/application/enigma/src/enigma.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 98 KiB |
1
project/jni/application/enigma/src/enigma.rc
Normal file
1
project/jni/application/enigma/src/enigma.rc
Normal file
@@ -0,0 +1 @@
|
||||
enigma ICON "enigma.ico"
|
||||
56
project/jni/application/enigma/src/errors.hh
Normal file
56
project/jni/application/enigma/src/errors.hh
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef ERRORS_HH
|
||||
#define ERRORS_HH
|
||||
|
||||
#include "ecl_error.hh"
|
||||
#include <string>
|
||||
|
||||
namespace enigma {
|
||||
/* -------------------- Exceptions -------------------- */
|
||||
|
||||
class XLevelLoading : public ecl::XGeneric {
|
||||
public:
|
||||
XLevelLoading (const std::string &msg)
|
||||
: XGeneric (msg)
|
||||
{}
|
||||
};
|
||||
|
||||
class XLevelPackInit : public ecl::XGeneric {
|
||||
public:
|
||||
XLevelPackInit (const std::string &msg)
|
||||
: XGeneric (msg)
|
||||
{}
|
||||
};
|
||||
|
||||
class XLevelRuntime : public ecl::XGeneric {
|
||||
public:
|
||||
XLevelRuntime (const std::string &msg)
|
||||
: XGeneric (msg)
|
||||
{}
|
||||
};
|
||||
|
||||
class XFrontend : public ecl::XGeneric {
|
||||
public:
|
||||
XFrontend (const std::string &msg)
|
||||
: XGeneric (msg)
|
||||
{}
|
||||
};
|
||||
} // namespace enigma
|
||||
#endif
|
||||
372
project/jni/application/enigma/src/file.cpp
Normal file
372
project/jni/application/enigma/src/file.cpp
Normal file
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#include "file.hh"
|
||||
#include "enigma.hh"
|
||||
#include "video.hh"
|
||||
#include "main.hh"
|
||||
|
||||
#include "ecl_system.hh"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_DIRENT_H
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace enigma;
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
DirIter::DirIter() {}
|
||||
DirIter::~DirIter() {}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/* -------------------- DirIter (POSIX) -------------------- */
|
||||
|
||||
#ifdef HAVE_DIRENT_H
|
||||
|
||||
class DirIterOS : DirIter {
|
||||
public:
|
||||
DirIterOS (const std::string &path) : m_dir (NULL), m_entry (NULL) {
|
||||
open (path);
|
||||
dir_path = path;
|
||||
}
|
||||
virtual ~DirIterOS () {
|
||||
if (m_dir != NULL)
|
||||
closedir (m_dir);
|
||||
}
|
||||
|
||||
virtual bool open (const std::string &path) {
|
||||
m_dir = opendir (path.c_str());
|
||||
return m_dir != 0;
|
||||
}
|
||||
virtual bool get_next (DirEntry &entry) {
|
||||
if (m_dir == 0) return false;
|
||||
m_entry = readdir(m_dir);
|
||||
if (m_entry != NULL) {
|
||||
entry.name = m_entry->d_name;
|
||||
// entry.is_dir = false;
|
||||
entry.is_dir = ecl::FolderExists(dir_path + "/" + entry.name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
std::string dir_path;
|
||||
DIR *m_dir;
|
||||
struct dirent *m_entry;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- DirIter (Win32) -------------------- */
|
||||
|
||||
#elif defined (_MSC_VER)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class DirIterOS : DirIter {
|
||||
public:
|
||||
DirIterOS (const std::string &path)
|
||||
: m_handle (INVALID_HANDLE_VALUE)
|
||||
{
|
||||
open (path);
|
||||
}
|
||||
~DirIterOS () {
|
||||
close();
|
||||
}
|
||||
|
||||
bool open (const std::string &path) {
|
||||
std::string glob (path);
|
||||
glob += "\\*.*";
|
||||
m_handle = FindFirstFile (glob.c_str(), &m_dir);
|
||||
return m_handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
bool get_next (DirEntry &entry) {
|
||||
if (m_handle != INVALID_HANDLE_VALUE) {
|
||||
entry.name = m_dir.cFileName;
|
||||
// entry.is_dir = false;
|
||||
entry.is_dir = m_dir.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
if (!FindNextFile (m_handle, &m_dir))
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
void close () {
|
||||
if (m_handle != INVALID_HANDLE_VALUE) {
|
||||
FindClose (m_handle);
|
||||
m_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Variables.
|
||||
WIN32_FIND_DATA m_dir;
|
||||
HANDLE m_handle;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
DirIter * DirIter::instance(const std::string &path) {
|
||||
return reinterpret_cast<DirIter *>(new DirIterOS(path));
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- FileHandle_Dir -------------------- */
|
||||
//
|
||||
// FileHandle_Dir::FileHandle_Dir (const std::string &name)
|
||||
// : m_name (name)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// bool FileHandle_Dir::exists() const
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// void FileHandle_Dir::read (ByteVec &buffer)
|
||||
// {
|
||||
// std::ifstream ifs(m_name.c_str());
|
||||
// enigma::readfile (ifs, buffer);
|
||||
// }
|
||||
//
|
||||
|
||||
|
||||
/* -------------------- GameFS implementation -------------------- */
|
||||
|
||||
GameFS::GameFS()
|
||||
: entries ()
|
||||
{
|
||||
}
|
||||
|
||||
void GameFS::append_dir (const string &path)
|
||||
{
|
||||
std::string full_path = ecl::ExpandPath (path);
|
||||
entries.push_back (FSEntry (FS_DIRECTORY, full_path));
|
||||
}
|
||||
|
||||
void GameFS::prepend_dir (const string &path)
|
||||
{
|
||||
std::string full_path = ecl::ExpandPath (path);
|
||||
entries.insert (entries.begin(), FSEntry (FS_DIRECTORY, full_path));
|
||||
}
|
||||
|
||||
void GameFS::prepend_zip (const std::string &filename)
|
||||
{
|
||||
std::string path = ecl::ExpandPath (filename);
|
||||
entries.insert (entries.begin(), FSEntry (FS_ZIPFILE, path));
|
||||
}
|
||||
|
||||
void GameFS::setDataPath (const string &p)
|
||||
{
|
||||
clear();
|
||||
|
||||
std::vector<std::string> datapaths;
|
||||
split_copy (p, *ecl::PathsSeparator, back_inserter(datapaths));
|
||||
for (unsigned i=0; i<datapaths.size(); ++i)
|
||||
append_dir (datapaths[i]);
|
||||
}
|
||||
|
||||
std::string GameFS::getDataPath() {
|
||||
std::string path;
|
||||
|
||||
for (unsigned i=0, size=entries.size(); i < size; ++i) {
|
||||
const FSEntry &e = entries[i];
|
||||
if (i>0)
|
||||
path += ecl::PathsSeparator;
|
||||
path += e.location;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
std::vector<std::string> GameFS::getPaths() {
|
||||
std::vector<std::string> paths;
|
||||
for (unsigned i=0, size=entries.size(); i < size; ++i) {
|
||||
const FSEntry &e = entries[i];
|
||||
paths.push_back(e.location);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
bool GameFS::findFile (const string &filename, string &dest) const
|
||||
{
|
||||
for (unsigned i=0; i<entries.size(); ++i) {
|
||||
const FSEntry &e = entries[i];
|
||||
|
||||
switch (e.type) {
|
||||
case FS_DIRECTORY:
|
||||
{
|
||||
string complete_name = e.location + ecl::PathSeparator + filename;
|
||||
if (ecl::FileExists(complete_name))
|
||||
{
|
||||
dest = complete_name;
|
||||
return true;
|
||||
}
|
||||
} break;
|
||||
|
||||
case FS_ZIPFILE:
|
||||
{
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GameFS::findFile (const string &filename, string &dest,
|
||||
std::auto_ptr<std::istream> &isresult) const {
|
||||
std::string::size_type slpos = filename.rfind('/');
|
||||
std::string zipName;
|
||||
std::string zippedFilename1, zippedFilename2;
|
||||
bool searchZip = false;
|
||||
std::string complete_name;
|
||||
|
||||
if (slpos != std::string::npos) {
|
||||
// file may be zipped - for "levels/Sokoban/mic_60.xml" we will look for
|
||||
// "mic_60.xml" and "Sokoban/mic_60.xml" at "levels/Sokoban.zip"
|
||||
searchZip = true;
|
||||
zipName = filename.substr(0, slpos) + ".zip";
|
||||
zippedFilename1 = filename.substr(slpos + 1);
|
||||
std::string::size_type slpos2 = filename.rfind('/', slpos-1);
|
||||
zippedFilename2 = filename.substr(slpos2 + 1);
|
||||
}
|
||||
for (unsigned i=0; i<entries.size(); ++i) {
|
||||
const FSEntry &e = entries[i];
|
||||
|
||||
switch (e.type) {
|
||||
case FS_DIRECTORY: {
|
||||
complete_name = e.location + ecl::PathSeparator + filename;
|
||||
if (ecl::FileExists(complete_name)) {
|
||||
dest = complete_name;
|
||||
return true;
|
||||
} else if (searchZip){
|
||||
complete_name = e.location + ecl::PathSeparator + zipName;
|
||||
if (ecl::FileExists(complete_name) &&
|
||||
findInZip(complete_name, zippedFilename1,
|
||||
zippedFilename2, dest, isresult)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case FS_ZIPFILE: {
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// enigma::FileHandle *GameFS::findFile (const FileName &n)
|
||||
// {
|
||||
// string fname;
|
||||
// if (findFile (n, fname)) {
|
||||
// return new FileHandle_Dir (fname);
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
std::string GameFS::findFile(const string &filename)
|
||||
{
|
||||
string found_file;
|
||||
if (!findFile(filename, found_file)) {
|
||||
enigma::Log << "File not found: " << filename << endl;
|
||||
return filename;
|
||||
}
|
||||
return found_file;
|
||||
}
|
||||
|
||||
std::list <string>
|
||||
GameFS::findSubfolderFiles(const string &folder, const string &filename) const
|
||||
{
|
||||
std::list <string> matches;
|
||||
|
||||
for (unsigned i=0; i<entries.size(); ++i) {
|
||||
const FSEntry &e = entries[i];
|
||||
|
||||
switch (e.type) {
|
||||
case FS_DIRECTORY: {
|
||||
string complete_name = e.location + ecl::PathSeparator + folder;
|
||||
if (ecl::FolderExists(complete_name)) {
|
||||
DirIterOS iter (complete_name);
|
||||
DirEntry entry;
|
||||
while (iter.get_next (entry)) {
|
||||
if (entry.name != "." && entry.name != "..") {
|
||||
string tmp_name = complete_name + ecl::PathSeparator
|
||||
+ entry.name + ecl::PathSeparator + filename;
|
||||
if (ecl::FileExists (tmp_name))
|
||||
matches.push_back (tmp_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FS_ZIPFILE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
|
||||
/* First search in video mode specific directory, then in "gfx/". */
|
||||
bool GameFS::findImageFile (const string &basename, string &filename)
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
string fname = string(vminfo->gfxdir) + basename;
|
||||
if (!findFile(fname, filename)) {
|
||||
fname = string ("gfx/") + basename;
|
||||
return findFile(fname, filename);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------- Helper functions -------------------- */
|
||||
|
||||
std::istream &
|
||||
enigma::Readfile (std::istream &is, ByteVec &dest, int blocksize)
|
||||
{
|
||||
size_t len = dest.size();
|
||||
int nread=0;
|
||||
do {
|
||||
dest.resize(dest.size() + blocksize);
|
||||
is.read (&dest[len], blocksize);
|
||||
nread = is.gcount();
|
||||
len += nread;
|
||||
} while (nread == blocksize);
|
||||
dest.resize(len);
|
||||
return is;
|
||||
}
|
||||
|
||||
bool enigma::Copyfile(std::string fromPath, std::string toPath) {
|
||||
ByteVec content;
|
||||
ifstream ifs(fromPath.c_str(), ios::binary | ios::in);
|
||||
Readfile (ifs, content);
|
||||
ofstream ofs(toPath.c_str(), ios::binary | ios::out);
|
||||
ofs.write(&content[0], content.size());
|
||||
ofs.close();
|
||||
return !ofs.fail();
|
||||
}
|
||||
202
project/jni/application/enigma/src/file.hh
Normal file
202
project/jni/application/enigma/src/file.hh
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef FILE_HH_INCLUDED
|
||||
#define FILE_HH_INCLUDED
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include "ecl_error.hh"
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
typedef std::vector<char> ByteVec;
|
||||
typedef std::string FileName;
|
||||
using std::string;
|
||||
|
||||
enum FSType {
|
||||
FS_DIRECTORY,
|
||||
FS_ZIPFILE,
|
||||
};
|
||||
|
||||
struct FSEntry {
|
||||
FSType type;
|
||||
std::string location;
|
||||
|
||||
FSEntry (FSType type_, const std::string &location_)
|
||||
: type (type_), location (location_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct DirEntry {
|
||||
std::string name;
|
||||
bool is_dir;
|
||||
};
|
||||
|
||||
class DirIter {
|
||||
public:
|
||||
static DirIter * instance(const std::string &path);
|
||||
virtual ~DirIter ();
|
||||
virtual bool open(const std::string &path) = 0;
|
||||
virtual bool get_next (DirEntry &entry) = 0;
|
||||
protected:
|
||||
DirIter();
|
||||
};
|
||||
|
||||
/* -------------------- FileHandles --------------------*/
|
||||
//
|
||||
// class FileHandle {
|
||||
// public:
|
||||
// virtual ~FileHandle() {}
|
||||
//
|
||||
// // FileHandle interface.
|
||||
// virtual bool exists() const = 0;
|
||||
// virtual void read (ByteVec &buffer) = 0;
|
||||
// };
|
||||
//
|
||||
// class FileHandle_Dir : public FileHandle {
|
||||
// std::string m_name;
|
||||
// std::string m_path;
|
||||
// bool m_exists; // File exists
|
||||
//
|
||||
// public:
|
||||
// FileHandle_Dir (const std::string &name);
|
||||
//
|
||||
// // FileHandle interface.
|
||||
// bool exists() const;
|
||||
// void read (ByteVec &buffer);
|
||||
// };
|
||||
//
|
||||
// class FileHandle_Zip : public FileHandle {
|
||||
// public:
|
||||
// FileHandle_Zip();
|
||||
//
|
||||
// // FileHandle interface.
|
||||
// bool exists() const;
|
||||
// void read (ByteVec &buffer);
|
||||
// };
|
||||
|
||||
/**
|
||||
* A GameFS is a list of directories that are searched when
|
||||
* Enigma tries to find a data file (for example a png image). The
|
||||
* data path is usually specified as a single string like
|
||||
* ".:~/.enigma:/usr/local/share/enigma" list with entries separated by
|
||||
* the OS dependent separating ":" or ";" (ecl::PathsSeparator).
|
||||
*
|
||||
* <p> When searching for files, the file name may of course include
|
||||
* subdirectory names. For example:</p>
|
||||
* <p><code>
|
||||
* findFile("graphics/bomb.png")
|
||||
* -> "/usr/local/share/enigma/graphics/bomb.png"
|
||||
* or "/home/user/.enigma/graphics/bomb.png"
|
||||
* </code></p>
|
||||
* <p> Preconfigured GameFS instances are accessable via the Application
|
||||
* instance, f.e. <code>app.resourceFS</code></p>
|
||||
*/
|
||||
class GameFS {
|
||||
public:
|
||||
GameFS();
|
||||
|
||||
void clear() { entries.clear(); }
|
||||
|
||||
void append_dir (const string &path);
|
||||
void prepend_dir (const string &path);
|
||||
|
||||
void prepend_zip (const string &filename);
|
||||
void setDataPath (const string &p);
|
||||
std::string getDataPath();
|
||||
std::vector<std::string> getPaths();
|
||||
|
||||
/**
|
||||
* Search first occurence of a file on the GameFS. The file can be
|
||||
* a path component like "levels/index.lua".
|
||||
* @param filename the searched filename
|
||||
* @param dest the expanded full path of the first occurence.
|
||||
* @return has a file been found.
|
||||
*/
|
||||
bool findFile(const string &filename, string &dest) const;
|
||||
|
||||
/**
|
||||
* Search first occurence of a file on the GameFS. The file can be
|
||||
* a path component like "levels/e1/hello.lua". Zip archives are searched,
|
||||
* too. The path above would be looked up in "levels/e1.zip" as "hello.lua"
|
||||
* and as "e1/hello.lua". Plain files preceed zipped onces on every
|
||||
* search directory.
|
||||
* @param filename the searched filename
|
||||
* @param dest the expanded full path of the first occurence.
|
||||
* @param isptr an opened istream of the first occurence in case
|
||||
* the file is zipped
|
||||
* @return has a file been found.
|
||||
*/
|
||||
bool findFile(const string &filename, string &dest,
|
||||
std::auto_ptr<std::istream> &isptr) const;
|
||||
|
||||
// FileHandle *findFile (const FileName &);
|
||||
|
||||
/**
|
||||
* Search first occurence of a file on the GameFS. The file can be
|
||||
* a path component like "levels/index.lua". If the file can not be
|
||||
* located a message is logged - use this method if you have good
|
||||
* reasons to expect the file being found.
|
||||
* @param filename the searched filename
|
||||
* @return the expanded full path of the first occurence or ""
|
||||
*/
|
||||
std::string findFile(const string &filename);
|
||||
|
||||
/**
|
||||
* Lists the paths of all files with a given name that reside in
|
||||
* a subfolder of the given basepath.
|
||||
* The basepath itself is not searched for files. Only direct one
|
||||
* level deep subfolders are searched. Of course all components of
|
||||
* the GameFS are searched for! Used for searching index like files.
|
||||
* @param folder the basefolder path component, f.e. "levels"
|
||||
* @param filename the searched filename, f.e. "index.lua"
|
||||
* @return a list of fully expanded paths to matching files
|
||||
*/
|
||||
std::list <string> findSubfolderFiles (const string &folder,
|
||||
const string &filename) const;
|
||||
|
||||
/** Find an image file named `f' in the resolution-dependent
|
||||
* graphics directories "gfx??" or in "gfx" and store the
|
||||
* path in `dst_path'. Returns true if successful.
|
||||
*/
|
||||
bool findImageFile (const FileName &f, std::string &dst_path);
|
||||
|
||||
private:
|
||||
// Variables
|
||||
std::vector<FSEntry> entries;
|
||||
};
|
||||
|
||||
/* -------------------- Helper functions -------------------- */
|
||||
|
||||
/*! Load a complete file/input stream `is' into `dst'. */
|
||||
std::istream &Readfile (std::istream &is, ByteVec &dst, int blocksize=512);
|
||||
bool Copyfile(std::string fromPath, std::string toPath);
|
||||
|
||||
// banned code to file_zip.cc due to macro clashes
|
||||
bool findInZip(std::string zipPath, std::string zippedFilename1,
|
||||
std::string zippedFilename2, string &dest,
|
||||
std::auto_ptr<std::istream> &isresult);
|
||||
|
||||
bool writeToZip(std::ostream &zipStream, std::string filename, unsigned size, std::istream &contents);
|
||||
bool readFromZipStream(std::istream &zipFile, std::ostream &contents);
|
||||
|
||||
} // namespace enigma
|
||||
#endif
|
||||
81
project/jni/application/enigma/src/file_zip.cpp
Normal file
81
project/jni/application/enigma/src/file_zip.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// Whoever knows how to integrate this code into file.cc should do it!
|
||||
// The problem to solve is the clashing macro definitions in "zipios-config.h"
|
||||
// and "config.h"
|
||||
// The static var "zip" should be a private ivar of GameFS
|
||||
|
||||
#include "file.hh"
|
||||
#include "zipios++/zipfile.h"
|
||||
#include "zipios++/zipoutputstream.h"
|
||||
#include "zipios++/zipoutputstreambuf.h"
|
||||
#include "zipios++/zipinputstreambuf.h"
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <ctime>
|
||||
|
||||
using namespace enigma;
|
||||
using namespace std;
|
||||
using namespace zipios;
|
||||
|
||||
static std::auto_ptr<zipios::ZipFile> zip;
|
||||
static std::string lastZipPath;
|
||||
|
||||
|
||||
bool enigma::findInZip(std::string zipPath, std::string zippedFilename1,
|
||||
std::string zippedFilename2, string &dest,
|
||||
std::auto_ptr<std::istream> &isresult) {
|
||||
|
||||
// reuse last opened zip if possible
|
||||
if (lastZipPath != zipPath) {
|
||||
zip.reset (new zipios::ZipFile (zipPath));
|
||||
lastZipPath = zipPath;
|
||||
}
|
||||
std::auto_ptr<istream> isptr (zip->getInputStream (zippedFilename2));
|
||||
if(isptr.get() != 0) {
|
||||
isresult = isptr;
|
||||
dest = zippedFilename2;
|
||||
return true;
|
||||
}
|
||||
isptr.reset(zip->getInputStream (zippedFilename1));
|
||||
if(isptr.get() != 0) {
|
||||
isresult = isptr;
|
||||
dest = zippedFilename1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool enigma::writeToZip(std::ostream &zipStream, std::string filename, unsigned size, std::istream &contents) {
|
||||
ZipOutputStreambuf zos(zipStream.rdbuf());
|
||||
ZipCDirEntry ze(filename);
|
||||
ze.setSize(size);
|
||||
ze.setTime(time(NULL)); // seems not to be implemented in zipios !
|
||||
zos.putNextEntry(ze);
|
||||
std::ostream ozs( &zos );
|
||||
ozs << contents.rdbuf();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool enigma::readFromZipStream(std::istream &zipFile, std::ostream &contents) {
|
||||
ZipInputStreambuf zis(zipFile.rdbuf());
|
||||
std::istream is( &zis );
|
||||
contents << is.rdbuf();
|
||||
return true;
|
||||
}
|
||||
1021
project/jni/application/enigma/src/floors.cpp
Normal file
1021
project/jni/application/enigma/src/floors.cpp
Normal file
File diff suppressed because it is too large
Load Diff
144
project/jni/application/enigma/src/floors.hh
Normal file
144
project/jni/application/enigma/src/floors.hh
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef FLOORS_HH_INCLUDED
|
||||
#define FLOORS_HH_INCLUDED
|
||||
|
||||
namespace world
|
||||
{
|
||||
enum FloorFlags {
|
||||
flf_default = 0,
|
||||
flf_indestructible = 0x01,
|
||||
flf_no_items = 0x02,
|
||||
flf_norespawn = 0x04,
|
||||
};
|
||||
|
||||
enum FloorID {
|
||||
fl_abyss,
|
||||
fl_water,
|
||||
fl_swamp,
|
||||
fl_space,
|
||||
fl_thief
|
||||
};
|
||||
|
||||
enum FloorFireType {
|
||||
flft_default = 0,
|
||||
flft_burnable = 0x01, // Floor behaves as if it-burnable lies on it.
|
||||
flft_ignitable = 0x02, // Ignite on bomb explosions. Not used.
|
||||
flft_noash = 0x04, // Don't leave ash behind; floor might burn again.
|
||||
flft_burnagain = 0x08, // Not used yet, nor implemented; see flft_noash.
|
||||
flft_eternal = 0x10, // Fire doesn't stop burning by itself.
|
||||
flft_secure = 0x20, // Secures fire and heat-effects when neighbors burn.
|
||||
flft_fastfire = 0x40, // Suppress use of fire_countdown, resulting in faster fire.
|
||||
flft_initfire = 0x80 // Start burning (forcefire on init-message).
|
||||
// Note that only flft_burnable and flft_noash are really used as traits.
|
||||
// The others are 0 by default for all floors, but used as selectors
|
||||
// for has_firetype. (Future use for special floors not excluded.)
|
||||
};
|
||||
|
||||
struct FloorTraits {
|
||||
// Variables
|
||||
string name;
|
||||
double friction;
|
||||
double mousefactor;
|
||||
FloorFlags flags;
|
||||
FloorFireType firetype;
|
||||
string firetransform; // fire on the same tile
|
||||
string heattransform; // fire on neighboring tile
|
||||
|
||||
// Constructor
|
||||
FloorTraits (const char *n, double f, double m,
|
||||
FloorFlags flags_, FloorFireType flft = flft_default,
|
||||
const char *ft = "", const char *ht = "")
|
||||
: name(n), friction(f), mousefactor(m), flags(flags_),
|
||||
firetype(flft), firetransform(ft), heattransform(ht)
|
||||
{}
|
||||
};
|
||||
|
||||
enum FloorHeatFlags {
|
||||
// These are used as second argument to try_heating and try_ignite,
|
||||
// they contain the context of a call.
|
||||
flhf_message = 0, // Source is a user-message.
|
||||
flhf_fire = 0x01, // Source is fire.
|
||||
flhf_first = 0x02, // First heat message from a burning site.
|
||||
flhf_last = 0x04 // Last heat message from a burning site.
|
||||
};
|
||||
|
||||
class Floor : public GridObject {
|
||||
public:
|
||||
Floor (const FloorTraits &tr);
|
||||
Floor (const char *kind, double friction_, double mfactor,
|
||||
FloorFlags flags=flf_default, FloorFireType flft = flft_default,
|
||||
const char *firetransform_ = "", const char *heattransform_ = "");
|
||||
|
||||
// Object interface
|
||||
Floor *clone();
|
||||
void dispose();
|
||||
virtual Value message(const string& msg, const Value &val);
|
||||
|
||||
|
||||
// Floor interface
|
||||
virtual ecl::V2 process_mouseforce (Actor *a, ecl::V2 force);
|
||||
virtual void add_force(Actor *, ecl::V2 &); // Note: actor = 0 must be allowed!
|
||||
|
||||
virtual void on_drop (Item *) {}
|
||||
virtual void on_pickup (Item *) {}
|
||||
|
||||
virtual void stone_change(Stone *) {}
|
||||
virtual void actor_contact (Actor *) {}
|
||||
|
||||
virtual double friction() const;
|
||||
virtual double mousefactor() const;
|
||||
|
||||
virtual void get_sink_speed (double &sinkspeed, double &raisespeed) const;
|
||||
virtual bool is_destructible() const;
|
||||
|
||||
virtual void animcb();
|
||||
void on_burnable_animcb(bool justIgnited); // Called by burnable-items on it.
|
||||
|
||||
protected:
|
||||
// GridObject interface
|
||||
void set_model (const std::string &mname);
|
||||
display::Model *get_model ();
|
||||
void kill_model (GridPos p);
|
||||
// Fire interface
|
||||
virtual bool has_firetype(FloorFireType selector);
|
||||
virtual string get_firetransform();
|
||||
virtual string get_heattransform(bool override_mode);
|
||||
void heat_neighbor(Direction dir, FloorHeatFlags flhf);
|
||||
int get_fire_countdown();
|
||||
virtual bool on_heattransform(Direction sourcedir, FloorHeatFlags flhf);
|
||||
|
||||
private:
|
||||
virtual void on_actorhit(Actor * /*a*/) {}
|
||||
// Fire logic
|
||||
Value try_heating(Direction sourcedir, FloorHeatFlags flhf);
|
||||
Value try_ignite(Direction sourcedir, FloorHeatFlags flhf);
|
||||
Value force_fire();
|
||||
Value stop_fire(bool is_message);
|
||||
|
||||
FloorTraits traits;
|
||||
bool heating_animation;
|
||||
int fire_countdown; // used to delay ignition, default is 1.
|
||||
};
|
||||
|
||||
void InitFloors();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
55
project/jni/application/enigma/src/fwd.hh
Normal file
55
project/jni/application/enigma/src/fwd.hh
Normal file
@@ -0,0 +1,55 @@
|
||||
//======================================================================
|
||||
// Copyright (C) 2002 Daniel Heck
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//======================================================================
|
||||
#ifndef FWD_HH
|
||||
#define FWD_HH
|
||||
|
||||
namespace enigma_player
|
||||
{
|
||||
class Inventory;
|
||||
}
|
||||
|
||||
namespace enigma_levels
|
||||
{
|
||||
class Level;
|
||||
class LevelPack;
|
||||
}
|
||||
|
||||
namespace tools
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
namespace display
|
||||
{
|
||||
class Model;
|
||||
}
|
||||
|
||||
namespace world
|
||||
{
|
||||
class Object;
|
||||
class Stone;
|
||||
class Floor;
|
||||
class Item;
|
||||
class Actor;
|
||||
struct ActorInfo;
|
||||
struct StoneContact;
|
||||
struct Impulse;
|
||||
struct Message;
|
||||
}
|
||||
|
||||
#endif
|
||||
126
project/jni/application/enigma/src/game.cpp
Normal file
126
project/jni/application/enigma/src/game.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#include "game.hh"
|
||||
#include "errors.hh"
|
||||
#include "main.hh"
|
||||
#include "options.hh"
|
||||
#include "video.hh"
|
||||
#include "client.hh"
|
||||
#include "server.hh"
|
||||
#include "world.hh"
|
||||
#include "sound.hh"
|
||||
#include "lev/PersistentIndex.hh"
|
||||
|
||||
#include "ecl_sdl.hh"
|
||||
#include <cassert>
|
||||
|
||||
using namespace enigma;
|
||||
using namespace std;
|
||||
|
||||
|
||||
/* -------------------- Global variables -------------------- */
|
||||
|
||||
namespace
|
||||
{
|
||||
Uint32 last_tick_time;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Level previews -------------------- */
|
||||
|
||||
bool game::DrawLevelPreview (ecl::GC &gc, lev::Proxy *levelProxy)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
sound::TempDisableSound();
|
||||
try {
|
||||
server::Msg_LoadLevel (levelProxy, true);
|
||||
|
||||
display::DrawAll(gc);
|
||||
success = true;
|
||||
}
|
||||
catch (XLevelLoading &err) {
|
||||
// log the message as we cannot display it on the screen
|
||||
Log << "DrawLevelPreview load error:\n" << err.what();
|
||||
success = false;
|
||||
}
|
||||
sound::TempReEnableSound();
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void game::StartGame ()
|
||||
{
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
server::InitNewGame();
|
||||
|
||||
video::HideMouse();
|
||||
sdl::TempInputGrab grab(enigma::Nograb ? SDL_GRAB_OFF : SDL_GRAB_ON);
|
||||
|
||||
server::Msg_LoadLevel(ind->getCurrent(), false);
|
||||
|
||||
double dtime = 0;
|
||||
last_tick_time=SDL_GetTicks();
|
||||
while (!client::AbortGameP()) {
|
||||
try {
|
||||
client::Tick (dtime);
|
||||
server::Tick (dtime);
|
||||
}
|
||||
catch (XLevelRuntime& err) {
|
||||
client::Msg_Error (string("Server Error: level runtime error:\n")
|
||||
+ err.what());
|
||||
server::Msg_Panic(true);
|
||||
}
|
||||
|
||||
int sleeptime = 10 - (SDL_GetTicks()-last_tick_time);
|
||||
if (sleeptime >= 3) // only sleep if relatively idle
|
||||
SDL_Delay(sleeptime);
|
||||
|
||||
Uint32 current_tick_time = SDL_GetTicks();
|
||||
dtime = (current_tick_time - last_tick_time)/1000.0;
|
||||
|
||||
if (abs(1-dtime/0.01) < 0.2) {
|
||||
// less than 20% deviation from desired frame time?
|
||||
dtime = 0.01;
|
||||
last_tick_time += 10;
|
||||
} else {
|
||||
last_tick_time = current_tick_time;
|
||||
}
|
||||
|
||||
if (dtime > 500.0) /* Time has done something strange, perhaps
|
||||
run backwards */
|
||||
dtime = 0.0;
|
||||
// else if (dtime > 0.5)
|
||||
// dtime = 0.5;
|
||||
}
|
||||
// add last played level
|
||||
lev::PersistentIndex::addCurrentToHistory();
|
||||
|
||||
video::ShowMouse();
|
||||
}
|
||||
|
||||
void game::ResetGameTimer()
|
||||
{
|
||||
last_tick_time=SDL_GetTicks();
|
||||
}
|
||||
|
||||
|
||||
45
project/jni/application/enigma/src/game.hh
Normal file
45
project/jni/application/enigma/src/game.hh
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef ENIGMA_GAME_HH
|
||||
#define ENIGMA_GAME_HH
|
||||
|
||||
#include "fwd.hh"
|
||||
#include "ecl_fwd.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
namespace enigma_game
|
||||
{
|
||||
using enigma_levels::LevelPack;
|
||||
using enigma_levels::Level;
|
||||
|
||||
void ResetGameTimer();
|
||||
|
||||
void StartGame();
|
||||
|
||||
/*! Draw a level preview into video::BackBuffer(). Return true if
|
||||
successful. */
|
||||
bool DrawLevelPreview (ecl::GC &, enigma::lev::Proxy *levelProxy);
|
||||
|
||||
}
|
||||
|
||||
namespace enigma
|
||||
{
|
||||
namespace game = enigma_game;
|
||||
}
|
||||
#endif
|
||||
114
project/jni/application/enigma/src/gui/ErrorMenu.cpp
Normal file
114
project/jni/application/enigma/src/gui/ErrorMenu.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/ErrorMenu.hh"
|
||||
#include "enigma.hh"
|
||||
#include "video.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/* -------------------- HelpMenu -------------------- */
|
||||
|
||||
ErrorMenu::ErrorMenu(std::string message, std::string quitTitle) :
|
||||
text (message), rejectQuit (false), laterQuit (false),
|
||||
quit (new gui::StaticTextButton(quitTitle, this)) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
add(quit, Rect(vminfo->width-170, vminfo->height-60, 150, 40));
|
||||
}
|
||||
|
||||
ErrorMenu::ErrorMenu(std::string message, std::string quitTitle, std::string rejectTitle) :
|
||||
text (message), rejectQuit (false), laterQuit (false),
|
||||
quit (new gui::StaticTextButton(quitTitle, this)),
|
||||
reject (new gui::StaticTextButton(rejectTitle, this)) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
add(quit, Rect(vminfo->width-170, vminfo->height-60, 150, 40));
|
||||
add(reject, Rect(vminfo->width-340, vminfo->height-60, 150, 40));
|
||||
}
|
||||
|
||||
ErrorMenu::ErrorMenu(std::string message, std::string quitTitle, std::string rejectTitle,
|
||||
std::string laterTitle) :
|
||||
text (message), rejectQuit (false), laterQuit (false),
|
||||
quit (new gui::StaticTextButton(quitTitle, this)),
|
||||
reject (new gui::StaticTextButton(rejectTitle, this)),
|
||||
later (new gui::StaticTextButton(laterTitle, this)) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
add(quit, Rect(vminfo->width-170, vminfo->height-60, 150, 40));
|
||||
add(later, Rect(vminfo->width-340, vminfo->height-60, 150, 40));
|
||||
add(reject, Rect(vminfo->width-510, vminfo->height-60, 150, 40));
|
||||
}
|
||||
|
||||
bool ErrorMenu::isRejectQuit() {
|
||||
return rejectQuit;
|
||||
}
|
||||
|
||||
bool ErrorMenu::isLaterQuit() {
|
||||
return laterQuit;
|
||||
}
|
||||
|
||||
bool ErrorMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_RIGHT) {
|
||||
Menu::quit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ErrorMenu::on_action (gui::Widget *w) {
|
||||
if (w == quit) {
|
||||
Menu::quit();
|
||||
} else if (w == reject) {
|
||||
rejectQuit = true;
|
||||
Menu::quit();
|
||||
} else if (w == later) {
|
||||
laterQuit = true;
|
||||
Menu::quit();
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorMenu::draw_background (ecl::GC &gc) {
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
Font *f = enigma::GetFont("menufont");
|
||||
|
||||
vector<string> lines;
|
||||
|
||||
ecl::split_copy (text, '\n', back_inserter(lines));
|
||||
int x = 60;
|
||||
int y = 60;
|
||||
int yskip = 25;
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
int width = vminfo->width - 120;
|
||||
for (unsigned i=0; i<lines.size(); ) {
|
||||
std::string::size_type breakPos = breakString(f, lines[i],
|
||||
" ", width);
|
||||
f->render(gc, x, y, lines[i].substr(0,breakPos).c_str());
|
||||
y += yskip;
|
||||
if (breakPos != lines[i].size()) {
|
||||
// process rest of line
|
||||
lines[i] = lines[i].substr(breakPos);
|
||||
} else {
|
||||
// process next line
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
50
project/jni/application/enigma/src/gui/ErrorMenu.hh
Normal file
50
project/jni/application/enigma/src/gui/ErrorMenu.hh
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GUI_ERRORMENU_HH_INCLUDED
|
||||
#define GUI_ERRORMENU_HH_INCLUDED
|
||||
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "ecl.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
class ErrorMenu : public Menu {
|
||||
public:
|
||||
ErrorMenu (std::string message, std::string quitTitle);
|
||||
ErrorMenu (std::string message, std::string quitTitle, std::string rejectTitle);
|
||||
ErrorMenu (std::string message, std::string quitTitle, std::string rejectTitle,
|
||||
std::string laterTitle);
|
||||
bool isRejectQuit();
|
||||
bool isLaterQuit();
|
||||
private:
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action (gui::Widget *w);
|
||||
void draw_background (ecl::GC &gc);
|
||||
|
||||
std::string text;
|
||||
gui::Widget *quit;
|
||||
gui::Widget *reject;
|
||||
gui::Widget *later;
|
||||
bool rejectQuit;
|
||||
bool laterQuit;
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif // GUI_ERRORMENU_HH_INCLUDED
|
||||
|
||||
177
project/jni/application/enigma/src/gui/GameMenu.cpp
Normal file
177
project/jni/application/enigma/src/gui/GameMenu.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/GameMenu.hh"
|
||||
#include "gui/OptionsMenu.hh"
|
||||
#include "gui/LevelInspector.hh"
|
||||
#include "client.hh"
|
||||
#include "display.hh"
|
||||
#include "ecl.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "server.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- GameMenu -------------------- */
|
||||
|
||||
GameMenu::GameMenu (int zoomxpos_, int zoomypos_)
|
||||
: zoomed(0),
|
||||
zoomxpos(zoomxpos_),
|
||||
zoomypos(zoomypos_)
|
||||
{
|
||||
resume = new gui::StaticTextButton(N_("Resume Level"), this);
|
||||
restart = new gui::StaticTextButton(N_("Restart Level"), this);
|
||||
options = new gui::StaticTextButton(N_("Options"), this);
|
||||
info = new gui::StaticTextButton(N_("Level Info"), this);
|
||||
abort = new gui::StaticTextButton(N_("Abort Level"), this);
|
||||
|
||||
add(resume, Rect(0,0,180,40));
|
||||
add(restart, Rect(0,45,180,40));
|
||||
add(options, Rect(0,90,180,40));
|
||||
add(info, Rect(0,135,180,40));
|
||||
add(abort, Rect(0,180,180,40));
|
||||
center();
|
||||
}
|
||||
|
||||
GameMenu::~GameMenu() {
|
||||
delete(zoomed);
|
||||
}
|
||||
|
||||
void GameMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
|
||||
if (!zoomed) {
|
||||
Rect game_area = display::GetGameArea();
|
||||
int part_width = game_area.w/3;
|
||||
int part_height = (part_width*vminfo->height)/vminfo->width;
|
||||
|
||||
if (part_height > game_area.h) {
|
||||
part_height = game_area.h/3;
|
||||
part_width = (part_height*vminfo->width)/vminfo->height;
|
||||
assert(part_width <= game_area.w);
|
||||
}
|
||||
|
||||
// randomly choose ball offset
|
||||
int x, y;
|
||||
for (int trials = 5; trials; --trials) {
|
||||
x = IntegerRand(0, 5);
|
||||
y = IntegerRand(0, 3);
|
||||
|
||||
// try to avoid menu-ball overlap:
|
||||
if (x<2 || x>3 || y<1 || y>2 || (trials == 1)) {
|
||||
int ax = zoomxpos-game_area.x;
|
||||
int ay = zoomypos-game_area.y;
|
||||
|
||||
// upper left corner of part
|
||||
x = ax/32-1-x;
|
||||
y = ay/32-1-y;
|
||||
|
||||
// ensure part is inside game_area
|
||||
x = max(0, min(x, (game_area.w-part_width)/32-1));
|
||||
y = max(0, min(y, (game_area.h-part_height)/32-1));
|
||||
|
||||
// adjust to game fields
|
||||
x = x*32+24;
|
||||
y = y*32+16;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Be sure to redraw everything, or actors may appear on top
|
||||
// of the stones (actors are drawn in one pass and only
|
||||
// clipped to the screen boundary).
|
||||
display::RedrawAll(video::GetScreen());
|
||||
|
||||
// get the selected part from screen
|
||||
// SDL_Surface *back = video::GetScreen()->get_surface();
|
||||
Rect src_area(game_area.x+x, game_area.y+y, part_width, part_height);
|
||||
Surface *src = Grab(video::GetScreen()->get_surface(), src_area);
|
||||
|
||||
// zoom multiple times for softer image
|
||||
// const double stepsize = 0.3;
|
||||
// for (double zoom = 0.4; zoom < 0.9; zoom += stepsize) {
|
||||
// int sx = round_down<int>(zoom * vminfo->width);
|
||||
// int sy = round_down<int>(zoom * vminfo->height);
|
||||
// Surface *tmp = src->zoom(sx, sy);
|
||||
|
||||
// delete src;
|
||||
// src = tmp;
|
||||
// }
|
||||
zoomed = src->zoom(vminfo->width, vminfo->height);
|
||||
delete src;
|
||||
}
|
||||
|
||||
ecl::blit(gc, 0,0, zoomed);
|
||||
}
|
||||
|
||||
bool GameMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN
|
||||
&& e.button.button == SDL_BUTTON_RIGHT)
|
||||
{
|
||||
Menu::quit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GameMenu::on_action(gui::Widget *w) {
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
if (w == resume) {
|
||||
Menu::quit();
|
||||
}
|
||||
else if (w == abort) {
|
||||
client::Msg_Command("abort");
|
||||
Menu::quit();
|
||||
}
|
||||
else if (w == restart) {
|
||||
if (w->lastModifierKeys() & KMOD_CTRL && w->lastModifierKeys() & KMOD_SHIFT) {
|
||||
// force a reload from file
|
||||
lev::Proxy * curProxy = lev::Proxy::loadedLevel();
|
||||
if (curProxy != NULL)
|
||||
curProxy->release();
|
||||
}
|
||||
client::Stop ();
|
||||
server::Msg_LoadLevel(ind->getCurrent(), false);
|
||||
Menu::quit();
|
||||
|
||||
}
|
||||
else if (w == options) {
|
||||
enigma::gui::ShowOptionsMenu (0);
|
||||
invalidate_all();
|
||||
// Menu::quit();
|
||||
}
|
||||
else if (w == info) {
|
||||
LevelInspector m(ind->getCurrent());
|
||||
m.manage();
|
||||
invalidate_all();
|
||||
// Menu::quit();
|
||||
}
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
40
project/jni/application/enigma/src/gui/GameMenu.hh
Normal file
40
project/jni/application/enigma/src/gui/GameMenu.hh
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_GAMEMENU_HH_INCLUDED
|
||||
#define GUI_GAMEMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- GameMenu -------------------- */
|
||||
class GameMenu : public Menu {
|
||||
public:
|
||||
GameMenu(int zoomxpos_, int zoomypos_);
|
||||
virtual ~GameMenu();
|
||||
private:
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(gui::Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
|
||||
gui::Widget *resume, *restart, *options, *info, *abort;
|
||||
ecl::Surface *zoomed;
|
||||
int zoomxpos, zoomypos; // position to be zoomed
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
86
project/jni/application/enigma/src/gui/HelpMenu.cpp
Normal file
86
project/jni/application/enigma/src/gui/HelpMenu.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2003,2004 Daniel Heck, Ralf Westram
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "enigma.hh"
|
||||
#include "video.hh"
|
||||
#include "nls.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/* -------------------- HelpMenu -------------------- */
|
||||
|
||||
HelpMenu::HelpMenu (const char **helptext_, int xoffset_) :
|
||||
helptext (helptext_),
|
||||
ok (new gui::StaticTextButton(N_("Ok"), this)),
|
||||
cfg (xoffset_)
|
||||
{
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
add(ok, Rect(vminfo.width-170,vminfo.height-60,150,40));
|
||||
}
|
||||
|
||||
bool HelpMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_RIGHT)
|
||||
{
|
||||
Menu::quit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HelpMenu::on_action (gui::Widget *w)
|
||||
{
|
||||
if (w == ok)
|
||||
Menu::quit();
|
||||
}
|
||||
|
||||
void HelpMenu::draw_background (ecl::GC &gc)
|
||||
{
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
Font *f = enigma::GetFont(cfg.fontname.c_str());
|
||||
|
||||
int y = cfg.y0 + (vminfo.height - 480)/2;
|
||||
int x = (vminfo.width-640)/2;
|
||||
for (int i = 0; helptext[i]; i += 2)
|
||||
{
|
||||
f->render (gc, cfg.x0 + x, y, _(helptext[i])); // translate
|
||||
f->render (gc, cfg.x1 + x, y, _(helptext[i+1])); // translate
|
||||
y += cfg.yskip;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void displayHelp(const char **helptext, int xoffset)
|
||||
{
|
||||
FX_Fade (video::FADEOUT);
|
||||
HelpMenu menu(helptext, xoffset);
|
||||
menu.draw_all();
|
||||
FX_Fade (video::FADEIN);
|
||||
menu.manage();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
60
project/jni/application/enigma/src/gui/HelpMenu.hh
Normal file
60
project/jni/application/enigma/src/gui/HelpMenu.hh
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003 Daniel Heck, Ralf Westram
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ENIGMA_HELP_HH
|
||||
#define ENIGMA_HELP_HH
|
||||
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "ecl.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
struct HelpMenuConfig {
|
||||
int x0, x1; // x coordinates of first and second column
|
||||
int y0; // y coordinate
|
||||
int yskip;
|
||||
std::string fontname;
|
||||
|
||||
HelpMenuConfig (int xoffset) {
|
||||
x0 = 40;
|
||||
x1 = x0 + xoffset;
|
||||
y0 = 40;
|
||||
yskip = 30;
|
||||
fontname = "menufont";
|
||||
}
|
||||
};
|
||||
|
||||
class HelpMenu : public Menu {
|
||||
public:
|
||||
HelpMenu (const char **helptext_, int xoffset);
|
||||
private:
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action (gui::Widget *w);
|
||||
void draw_background (ecl::GC &gc);
|
||||
|
||||
const char **helptext;
|
||||
gui::Widget *ok;
|
||||
HelpMenuConfig cfg;
|
||||
};
|
||||
|
||||
void displayHelp (const char **helptext, int xoffset);
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif // ENIGMA_HELP_HH
|
||||
|
||||
84
project/jni/application/enigma/src/gui/InfoMenu.cpp
Normal file
84
project/jni/application/enigma/src/gui/InfoMenu.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
#include "gui/InfoMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "video.hh"
|
||||
#include "nls.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
InfoMenu::InfoMenu(const char **infotext, int pages) : info (infotext),
|
||||
curPage (0), numPages (pages) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
but_ok = new StaticTextButton(N_("Ok"), this);
|
||||
pgup = new ImageButton("ic-up", "ic-up1", this);
|
||||
pgdown = new ImageButton("ic-down", "ic-down1", this);
|
||||
|
||||
add(but_ok, Rect(vminfo.width-120, vminfo.height-60, 100, 40));
|
||||
add(pgup, Rect(vminfo.width-30, vminfo.height/2, 20, 50));
|
||||
add(pgdown, Rect(vminfo.width-30, vminfo.height/2 +70, 20, 50));
|
||||
}
|
||||
|
||||
void InfoMenu::draw_background(ecl::GC &gc) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
|
||||
Font *f = enigma::GetFont("menufont");
|
||||
int row = 0;
|
||||
for (int p=0; p<curPage; p++) {
|
||||
while (info[row])
|
||||
row++;
|
||||
// select first row of next page
|
||||
row++;
|
||||
}
|
||||
for (int i = 0; info[row]; row++, i++) {
|
||||
const char *t = _(info[row]);
|
||||
f->render (gc, 40 + (vminfo.width-640)/2,
|
||||
20 + (vminfo.height-480)/2 + i*f->get_height(), t);
|
||||
}
|
||||
}
|
||||
|
||||
void InfoMenu::on_action (gui::Widget *w) {
|
||||
if (w == but_ok) {
|
||||
Menu::quit();
|
||||
} else if (w == pgup) {
|
||||
if (curPage > 0) {
|
||||
curPage--;
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == pgdown) {
|
||||
if (curPage < numPages - 1) {
|
||||
curPage++;
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayInfo(const char **infotext, int pages) {
|
||||
FX_Fade (video::FADEOUT);
|
||||
InfoMenu menu(infotext, pages);
|
||||
menu.draw_all();
|
||||
FX_Fade (video::FADEIN);
|
||||
menu.manage();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
42
project/jni/application/enigma/src/gui/InfoMenu.hh
Normal file
42
project/jni/application/enigma/src/gui/InfoMenu.hh
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GUI_INFOMENU_HH_INCLUDED
|
||||
#define GUI_INFOMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
class InfoMenu : public gui::Menu {
|
||||
public:
|
||||
InfoMenu(const char **infotext, int pages);
|
||||
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
private:
|
||||
const char **info;
|
||||
int curPage;
|
||||
int numPages;
|
||||
Widget *but_ok;
|
||||
Widget *pgup;
|
||||
Widget *pgdown;
|
||||
};
|
||||
|
||||
void displayInfo(const char **helptext, int pages);
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
231
project/jni/application/enigma/src/gui/LPGroupConfig.cpp
Normal file
231
project/jni/application/enigma/src/gui/LPGroupConfig.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/LPGroupConfig.hh"
|
||||
#include "gui/LevelPackConfig.hh"
|
||||
#include "ecl.hh"
|
||||
#include "errors.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
LPGroupConfig::LPGroupConfig(std::string groupName) : oldGroupName (groupName) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
groups = lev::Index::getGroupNames();
|
||||
|
||||
position = -1;
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (groups[i] == groupName) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
oldPosition = position;
|
||||
if (position < 0) {
|
||||
groups.push_back(groupName);
|
||||
position = groups.size() - 1;
|
||||
}
|
||||
|
||||
VList * titleVList = new VList;
|
||||
titleVList->set_spacing(12);
|
||||
titleVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
titleVList->set_default_size(160, 35);
|
||||
Label * groupLabel = new Label(N_("Group:"), HALIGN_RIGHT);
|
||||
titleVList->add_back(groupLabel);
|
||||
|
||||
VList * groupsVList = new VList;
|
||||
groupsVList->set_spacing(12);
|
||||
groupsVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
groupsVList->set_default_size(160, 35);
|
||||
|
||||
Label * positionLabel = new Label(N_("Position:"), HALIGN_LEFT);
|
||||
pre2Group = new UntranslatedLabel("");
|
||||
pre1Group = new UntranslatedLabel("");
|
||||
tf_groupName = new TextField(groupName);
|
||||
post1Group = new UntranslatedLabel("");
|
||||
post2Group = new UntranslatedLabel("");
|
||||
Label * dummyLabel = new Label("");
|
||||
|
||||
groupsVList->add_back(positionLabel);
|
||||
groupsVList->add_back(pre2Group);
|
||||
groupsVList->add_back(pre1Group);
|
||||
groupsVList->add_back(tf_groupName);
|
||||
groupsVList->add_back(post1Group);
|
||||
groupsVList->add_back(post2Group);
|
||||
groupsVList->add_back(dummyLabel);
|
||||
|
||||
VList * scrollVList = new VList;
|
||||
scrollVList->set_spacing(12);
|
||||
scrollVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
scrollVList->set_default_size(40, 35);
|
||||
|
||||
scrollUp = new ImageButton("ic-up", "ic-up1", this);
|
||||
scrollDown = new ImageButton("ic-down", "ic-down1", this);
|
||||
scrollVList->add_back(scrollUp);
|
||||
scrollVList->add_back(scrollDown);
|
||||
|
||||
this->add(titleVList, Rect(vminfo.width/2 - 290, 0, 160, vminfo.height-100));
|
||||
this->add(groupsVList, Rect(vminfo.width/2 - 80, 0, 160, vminfo.height-100));
|
||||
this->add(scrollVList, Rect(vminfo.width/2 + 130, 0, 40, vminfo.height-100));
|
||||
|
||||
errorLabel = new Label("", HALIGN_CENTER);
|
||||
this->add(errorLabel, Rect(10, vminfo.height-100, vminfo.width-20, 35));
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
but_newPack = new StaticTextButton(N_("New Pack"), this);
|
||||
but_delete = new StaticTextButton(N_("Delete Group"), this);
|
||||
but_ignore = new StaticTextButton(N_("Undo"), this);
|
||||
but_ok = new StaticTextButton(N_("Ok"), this);
|
||||
|
||||
HList * commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
commandHList->add_back(but_newPack);
|
||||
commandHList->add_back(but_delete);
|
||||
commandHList->add_back(but_ignore);
|
||||
commandHList->add_back(but_ok);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
|
||||
updateGroupList();
|
||||
}
|
||||
|
||||
void LPGroupConfig::updateGroupList() {
|
||||
pre2Group->set_text((position > 1) ? groups[position - 2] : "");
|
||||
pre1Group->set_text((position > 0) ? groups[position - 1] : "");
|
||||
post1Group->set_text((position < groups.size() - 1) ? groups[position + 1] : "");
|
||||
post2Group->set_text((position < groups.size() - 2) ? groups[position + 2] : "");
|
||||
}
|
||||
|
||||
bool LPGroupConfig::doChanges() {
|
||||
// rename first for consistency
|
||||
std::string newName = tf_groupName->getText();
|
||||
std::string::size_type lastChar = newName.find_last_not_of(" ");
|
||||
if (lastChar == std::string::npos) {
|
||||
// the name is effectively an empty string
|
||||
errorLabel->set_text(N_("Error: empty group name not allowed - press \"Undo\" to exit without modifications"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// strip off trailing and leading spaces
|
||||
newName = newName.substr(0 , lastChar + 1);
|
||||
newName = newName.substr(newName.find_first_not_of(" "));
|
||||
|
||||
// check if new group name is unique
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (i != position && groups[i] == newName) {
|
||||
errorLabel->set_text(N_("Error: group name is a duplicate of an existing group"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (newName == INDEX_EVERY_GROUP) {
|
||||
errorLabel->set_text(N_("Error: \"Every group\" is a reserved group name"));
|
||||
return false;
|
||||
}
|
||||
if (newName.size() > 2 && newName[0] == '['
|
||||
&& newName[newName.size() -1] == ']') {
|
||||
errorLabel->set_text(N_("Error: group name must not be enclosed in square brackets"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (oldGroupName.empty()) {
|
||||
// menu called without an existing group
|
||||
lev::Index::insertGroup(newName, position);
|
||||
} else {
|
||||
// menu called with an existing group
|
||||
if (newName != oldGroupName)
|
||||
lev::Index::renameGroup(oldGroupName, newName);
|
||||
|
||||
if (oldPosition >= 0 && position != oldPosition) {
|
||||
// move the group to the new position
|
||||
lev::Index::moveGroup(newName, position);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LPGroupConfig::on_action(Widget *w) {
|
||||
if (w == but_ok) {
|
||||
if (doChanges())
|
||||
Menu::quit();
|
||||
else
|
||||
invalidate_all();
|
||||
} else if (w == but_ignore) {
|
||||
Menu::quit();
|
||||
} else if (w == scrollUp) {
|
||||
if (position > 0) {
|
||||
std::string tmp = groups[position];
|
||||
groups[position] = groups[position - 1];
|
||||
groups[position - 1] = tmp;
|
||||
position--;
|
||||
updateGroupList();
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == scrollDown) {
|
||||
if (position < groups.size() - 1) {
|
||||
std::string tmp = groups[position];
|
||||
groups[position] = groups[position + 1];
|
||||
groups[position + 1] = tmp;
|
||||
position++;
|
||||
updateGroupList();
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == but_delete) {
|
||||
std::vector<lev::Index *> * indices = lev::Index::getGroup(oldGroupName);
|
||||
if (indices != NULL) {
|
||||
// reassign remaining indices from back to front to keep the
|
||||
// group vector valid
|
||||
for (int i = indices->size() - 1; i >= 0; i--) {
|
||||
if ((*indices)[i]->getGroupName() != INDEX_EVERY_GROUP) {
|
||||
LevelPackConfig m((*indices)[i]->getName(), oldGroupName, true);
|
||||
if (!m.manage() || m.isUndoQuit()) {
|
||||
errorLabel->set_text(N_("Error: group not empty"));
|
||||
invalidate_all();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
lev::Index::deleteGroup(oldGroupName);
|
||||
}
|
||||
Menu::quit();
|
||||
} else if (w == but_newPack) {
|
||||
if (doChanges()) {
|
||||
LevelPackConfig m("");
|
||||
m.manage();
|
||||
Menu::quit();
|
||||
} else {
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LPGroupConfig::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Level Pack Group Configuration"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
|
||||
}} // namespace enigma::gui
|
||||
56
project/jni/application/enigma/src/gui/LPGroupConfig.hh
Normal file
56
project/jni/application/enigma/src/gui/LPGroupConfig.hh
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GUI_LPGROUPCONFIG_HH_INCLUDED
|
||||
#define GUI_LPGROUPCONFIG_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
class LPGroupConfig : public gui::Menu {
|
||||
public:
|
||||
LPGroupConfig (std::string groupName);
|
||||
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
private:
|
||||
void updateGroupList();
|
||||
bool doChanges();
|
||||
|
||||
TextField *tf_groupName;
|
||||
Label *pre2Group;
|
||||
Label *pre1Group;
|
||||
Label *post1Group;
|
||||
Label *post2Group;
|
||||
Widget *scrollUp;
|
||||
Widget *scrollDown;
|
||||
Label *errorLabel;
|
||||
Widget *but_newPack;
|
||||
Widget *but_delete;
|
||||
Widget *but_ignore;
|
||||
Widget *but_ok;
|
||||
std::vector<std::string> groups;
|
||||
int position; // new position of group that the user selected
|
||||
int oldPosition; // position of group when entering menu, -1 for new group
|
||||
std::string oldGroupName;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
|
||||
712
project/jni/application/enigma/src/gui/LevelInspector.cpp
Normal file
712
project/jni/application/enigma/src/gui/LevelInspector.cpp
Normal file
@@ -0,0 +1,712 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "errors.hh"
|
||||
#include "gui/LevelInspector.hh"
|
||||
#include "main.hh"
|
||||
#include "enigma.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
#include "ecl_util.hh"
|
||||
#include "gui/MonospacedLabel.hh"
|
||||
#include "gui/LevelPreviewCache.hh"
|
||||
#include "gui/ScreenshotViewer.hh"
|
||||
#include "lev/RatingManager.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
#include "StateManager.hh"
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace enigma;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
class IntelligenceButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getIntelligence(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setIntelligence(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
IntelligenceButton(lev::Proxy *aLevel) : ValueButton(0, 5),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class DexterityButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getDexterity(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setDexterity(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
DexterityButton(lev::Proxy *aLevel) : ValueButton(0, 5),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class PatienceButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getPatience(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setPatience(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
PatienceButton(lev::Proxy *aLevel) : ValueButton(0, 5),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class KnowledgeButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getKnowledge(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setKnowledge(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
KnowledgeButton(lev::Proxy *aLevel) : ValueButton(0, 6),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class SpeedButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theRatingMgr->getSpeed(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theRatingMgr->setSpeed(theLevel, value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
SpeedButton(lev::Proxy *aLevel) : ValueButton(0, 5),
|
||||
theLevel (aLevel) {
|
||||
theRatingMgr = lev::RatingManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::RatingManager *theRatingMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
class RatingButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return theScoreMgr->getRating(theLevel);
|
||||
}
|
||||
void set_value(int value) {
|
||||
theScoreMgr->setRating(theLevel, value);
|
||||
if (get_parent() != NULL) {
|
||||
get_parent()->invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return (value == -1) ? "-" : ecl::strf("%d", value);
|
||||
}
|
||||
public:
|
||||
RatingButton(lev::Proxy *aLevel) : ValueButton(-1, 10),
|
||||
theLevel (aLevel) {
|
||||
theScoreMgr = lev::ScoreManager::instance();
|
||||
init();
|
||||
}
|
||||
private:
|
||||
lev::ScoreManager *theScoreMgr;
|
||||
lev::Proxy *theLevel;
|
||||
};
|
||||
|
||||
LevelInspector::LevelInspector(lev::Proxy *aLevel, bool showDeveloperInfo):
|
||||
levelProxy(aLevel), isDeveloperMode(showDeveloperInfo), annotation (new TextField()),
|
||||
back (new StaticTextButton(N_("Ok"), this)),
|
||||
screenshot (new StaticTextButton(N_("Screenshot"), this))
|
||||
{
|
||||
bool didGenerate; // dummy
|
||||
previewImage = LevelPreviewCache::instance()->getPreview(aLevel, true, didGenerate);
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
vspacing = vminfo->height < 500 ? 2 :(vminfo->height < 650 ? 3 : 4);
|
||||
vspacing2 = vminfo->height < 500 ? 16 :(vminfo->height < 650 ? 14 : 16);
|
||||
vmargin = vminfo->height < 500 ? 10 :(vminfo->height < 650 ? 20 : 30);
|
||||
hmargin = vminfo->width < 660 ? 10 : (vminfo->width < 900 ? 20 : 30);
|
||||
bool highres = vminfo->height > 650 ? true : false;
|
||||
bool lowres = vminfo->height < 600 ? true : false;
|
||||
|
||||
add(back, Rect(vminfo->width-130-2*hmargin,vminfo->height-50,130,35));
|
||||
add(screenshot, Rect(vminfo->width-260-3*hmargin,vminfo->height-50,130,35));
|
||||
|
||||
try {
|
||||
aLevel->loadMetadata(true);
|
||||
}
|
||||
catch (XLevelLoading &err) {
|
||||
std::vector<string> lines;
|
||||
std::string errmsg = _("Server Error: could not load level '")
|
||||
+ aLevel->getNormLevelPath() + "'\n"
|
||||
+ err.what();
|
||||
ecl::split_copy (errmsg, '\n', back_inserter(lines));
|
||||
int x = 60;
|
||||
int y = 60;
|
||||
int yskip = 25;
|
||||
for (unsigned i=0; i<lines.size(); ++i) {
|
||||
add(new Label(lines[i], HALIGN_LEFT), Rect(x, y, vminfo->width-80,yskip));
|
||||
y += yskip;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::string tmp, tmp2;
|
||||
lev::RatingManager *theRatingMgr = lev::RatingManager::instance();
|
||||
lev::ScoreManager *theScoreMgr = lev::ScoreManager::instance();
|
||||
withEasy = aLevel->hasEasymode();
|
||||
ratingInherited = theScoreMgr->isRatingInherited(aLevel);
|
||||
ecl::Font *menufont = enigma::GetFont("menufont");
|
||||
levelPathString =
|
||||
(levelProxy->getNormPathType() == lev::Proxy::pt_resource) ?
|
||||
levelProxy->getAbsLevelPath() : levelProxy->getNormLevelPath();
|
||||
// substitute all backslashes by slashes
|
||||
for (std::string::size_type slpos = levelPathString.find('\\');
|
||||
slpos != std::string::npos; slpos = levelPathString.find('\\'))
|
||||
levelPathString.replace(slpos, 1, 1, '/');
|
||||
BuildVList authorT(this, Rect(hmargin,vmargin,110,25), vspacing);
|
||||
authorT.add(new Label(N_("Level: "), HALIGN_RIGHT));
|
||||
authorT.add(new Label((""), HALIGN_RIGHT)); // subtitle
|
||||
authorT.add(new Label(N_("Author: "), HALIGN_RIGHT));
|
||||
authorT.add(new Label(N_("Contact: "), HALIGN_RIGHT));
|
||||
authorT.add(new Label(N_("Homepage: "), HALIGN_RIGHT));
|
||||
|
||||
BuildVList author(this, Rect(hmargin+110+10,vmargin,
|
||||
vminfo->width-(hmargin+110+10)-10-(vminfo->thumbw+10)-hmargin,25), vspacing);
|
||||
tmp = levelProxy->getTitle();
|
||||
tmp2 = levelProxy->getLocalizedString("title");
|
||||
if (tmp != tmp2)
|
||||
tmp = tmp + " -- " + tmp2;
|
||||
author.add(new Label( tmp, HALIGN_LEFT));
|
||||
tmp = levelProxy->getLocalizedString("subtitle");
|
||||
if (tmp == "subtitle")
|
||||
tmp = "";
|
||||
author.add(new Label(tmp, HALIGN_LEFT)); // subtitle
|
||||
author.add(new Label(levelProxy->getAuthor(), HALIGN_LEFT));
|
||||
|
||||
BuildVList address(this, Rect(hmargin+110+10,vmargin+3*(25+vspacing),
|
||||
vminfo->width-(hmargin+110+10)-hmargin,25), vspacing);
|
||||
address.add(new Label(levelProxy->getContact(), HALIGN_LEFT));
|
||||
address.add(new Label(levelProxy->getHomepage(), HALIGN_LEFT));
|
||||
|
||||
BuildVList ratingPubT(this, Rect(hmargin+65,vmargin+5*25+4*vspacing+vspacing2, 130,25), 2);
|
||||
ratingPubT.add(new Label(N_("Public Ratings"), HALIGN_CENTER));
|
||||
BuildVList ratingPubST(this, Rect(hmargin,vmargin+6*25+5*vspacing+vspacing2, 130,25), 2);
|
||||
ratingPubST.add(new Label(N_("Intelligence: "), HALIGN_RIGHT));
|
||||
ratingPubST.add(new Label(N_("Dexterity: "), HALIGN_RIGHT));
|
||||
ratingPubST.add(new Label(N_("Patience: "), HALIGN_RIGHT));
|
||||
ratingPubST.add(new Label(N_("Knowledge: "), HALIGN_RIGHT));
|
||||
ratingPubST.add(new Label(N_("Speed: "), HALIGN_RIGHT));
|
||||
if (!lowres) ratingPubST.add(new Label(N_("Difficulty: "), HALIGN_RIGHT));
|
||||
|
||||
|
||||
BuildVList ratingPub(this, Rect(hmargin+130+15,vmargin+6*25+5*vspacing+vspacing2, 30,25), 2);
|
||||
if (WizardMode) {
|
||||
ratingPub.add(new IntelligenceButton(aLevel));
|
||||
ratingPub.add(new DexterityButton(aLevel));
|
||||
ratingPub.add(new PatienceButton(aLevel));
|
||||
ratingPub.add(new KnowledgeButton(aLevel));
|
||||
ratingPub.add(new SpeedButton(aLevel));
|
||||
if (!lowres) ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getDifficulty(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
} else {
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getIntelligence(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getDexterity(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getPatience(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getKnowledge(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getSpeed(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
if (!lowres) ratingPub.add(new MonospacedLabel(ratingToString(theRatingMgr->getDifficulty(aLevel)).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
}
|
||||
|
||||
BuildVList scoresT(this, Rect(vminfo->width/2-100-20,vmargin+5*25+4*vspacing+vspacing2,100,25), 2);
|
||||
scoresT.add(new Label(N_("Scores"), HALIGN_RIGHT));
|
||||
|
||||
BuildVList scoresST(this, Rect(vminfo->width/2-100-20,vmargin+6*25+5*vspacing+vspacing2,100,25), 2);
|
||||
scoresST.add(new Label(N_("You: "), HALIGN_RIGHT));
|
||||
scoresST.add(new Label(N_("World: "), HALIGN_RIGHT));
|
||||
// TRANSLATORS: PAR = professional average rate - an expression used by golfers
|
||||
scoresST.add(new Label(N_("PAR: "), HALIGN_RIGHT));
|
||||
scoresST.add(new Label(N_("Author: "), HALIGN_RIGHT));
|
||||
scoresST.add(new Label(N_("Solved %: "), HALIGN_RIGHT));
|
||||
if (!lowres) scoresST.add(new Label(N_("Solved #: "), HALIGN_RIGHT));
|
||||
|
||||
BuildVList scores(this, Rect(vminfo->width/2-15+(withEasy?0:20),
|
||||
vmargin+6*25+5*vspacing+vspacing2,(withEasy?117:54),25), 2);
|
||||
scores.add(new MonospacedLabel(scoreToString(theScoreMgr->getBestUserScore(aLevel, DIFFICULTY_EASY),
|
||||
theScoreMgr->getBestUserScore(aLevel, DIFFICULTY_HARD),aLevel,true).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
scores.add(new MonospacedLabel(scoreToString(theRatingMgr->getBestScoreEasy(aLevel),
|
||||
theRatingMgr->getBestScoreDifficult(aLevel),aLevel,true).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
scores.add(new MonospacedLabel(scoreToString(theRatingMgr->getParScoreEasy(aLevel),
|
||||
theRatingMgr->getParScoreDifficult(aLevel),aLevel,true).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
scores.add(new MonospacedLabel(scoreToString(aLevel->getEasyScore(),
|
||||
aLevel->getDifficultScore(),aLevel,true).c_str(),'8', " 0123456789", HALIGN_CENTER));
|
||||
scores.add(new MonospacedLabel(withEasy ? (theRatingMgr->getPcSolvedEasy(aLevel) +
|
||||
" /" + theRatingMgr->getPcSolvedDifficult(aLevel) + " ").c_str() :
|
||||
(theRatingMgr->getPcSolvedDifficult(aLevel) + " ").c_str(),
|
||||
'8', " 0123456789", HALIGN_CENTER));
|
||||
if (!lowres) scores.add(new MonospacedLabel(withEasy ? (ecl::strf("%5d", theRatingMgr->getNumSolvedEasy(aLevel)) +
|
||||
" /" + ecl::strf("%5d", theRatingMgr->getNumSolvedDifficult(aLevel)) + " ").c_str() :
|
||||
(ecl::strf("%5d", theRatingMgr->getNumSolvedDifficult(aLevel)) + " ").c_str(),
|
||||
'8', " 0123456789", HALIGN_CENTER));
|
||||
|
||||
BuildVList versionT(this, Rect(vminfo->width-100/2-90-2*hmargin,vmargin+5*25+4*vspacing+vspacing2,100,25), 2);
|
||||
versionT.add(new Label(N_("Version"), HALIGN_CENTER));
|
||||
BuildVList versionST(this, Rect(vminfo->width-110-90-2*hmargin,vmargin+6*25+5*vspacing+vspacing2,110,25), 2);
|
||||
if (!lowres || aLevel->getLevelStatus() == lev::STATUS_RELEASED)
|
||||
versionST.add(new Label(N_("Score: "), HALIGN_RIGHT));
|
||||
else
|
||||
versionST.add(new Label(N_("Status: "), HALIGN_RIGHT));
|
||||
versionST.add(new Label(N_("Release: "), HALIGN_RIGHT));
|
||||
versionST.add(new Label(N_("Revision: "), HALIGN_RIGHT));
|
||||
if (!lowres)
|
||||
versionST.add(new Label(N_("Status: "), HALIGN_RIGHT));
|
||||
versionST.add(new Label(N_("Control: "), HALIGN_RIGHT));
|
||||
versionST.add(new Label(N_("Target: "), HALIGN_RIGHT));
|
||||
|
||||
BuildVList version(this, Rect(vminfo->width-80-2*hmargin,vmargin+6*25+5*vspacing+vspacing2,80+2*hmargin,25), 2);
|
||||
if (!lowres || aLevel->getLevelStatus() == lev::STATUS_RELEASED)
|
||||
version.add(new MonospacedLabel(ecl::strf("%6d", aLevel->getScoreVersion()).c_str(),
|
||||
'8', " 0123456789", HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_STABLE)
|
||||
version.add(new Label(N_("stable"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_TEST)
|
||||
version.add(new Label(N_("test"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_EXPERIMENTAL)
|
||||
version.add(new Label(N_("experimental"), HALIGN_LEFT));
|
||||
else
|
||||
version.add(new Label(N_("unknown"), HALIGN_LEFT));
|
||||
|
||||
version.add(new MonospacedLabel(ecl::strf("%6d", aLevel->getReleaseVersion()).c_str(),
|
||||
'8', " 0123456789", HALIGN_LEFT));
|
||||
version.add(new MonospacedLabel(ecl::strf("%6d", aLevel->getRevisionNumber()).c_str(),
|
||||
'8', " 0123456789", HALIGN_LEFT));
|
||||
if (!lowres)
|
||||
if (aLevel->getLevelStatus() == lev::STATUS_RELEASED)
|
||||
version.add(new Label(N_("released"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_STABLE)
|
||||
version.add(new Label(N_("stable"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_TEST)
|
||||
version.add(new Label(N_("test"), HALIGN_LEFT));
|
||||
else if (aLevel->getLevelStatus() == lev::STATUS_EXPERIMENTAL)
|
||||
version.add(new Label(N_("experimental"), HALIGN_LEFT));
|
||||
else
|
||||
version.add(new Label(N_("unknown"), HALIGN_LEFT));
|
||||
|
||||
switch (aLevel->getControl()) {
|
||||
case lev::force:
|
||||
version.add(new Label(N_("force"), HALIGN_LEFT));
|
||||
break;
|
||||
case lev::balance:
|
||||
version.add(new Label(N_("balance"), HALIGN_LEFT));
|
||||
break;
|
||||
case lev::key:
|
||||
version.add(new Label(N_("key"), HALIGN_LEFT));
|
||||
break;
|
||||
default:
|
||||
version.add(new Label(N_("unknown"), HALIGN_LEFT));
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
// fake gettext to register the following strings for I18N
|
||||
_("time")
|
||||
_("pushes")
|
||||
_("moves")
|
||||
#endif
|
||||
version.add(new Label(aLevel->getScoreTarget().c_str(), HALIGN_LEFT));
|
||||
|
||||
int bestScoreHolderLines = 0;
|
||||
int creditsLines = 0;
|
||||
int dedicationLines = 0;
|
||||
int levelPathLines = 0;
|
||||
int annotationLines = 0;
|
||||
int compatibilityLines = 0;
|
||||
int idLines = 0;
|
||||
int vnext = vmargin+ (lowres?11:12)*25+(lowres?9:10)*vspacing+2*vspacing2;
|
||||
int textwidth = vminfo->width-3*hmargin-110-10;
|
||||
dispatchBottomLines(bestScoreHolderLines, creditsLines, dedicationLines,
|
||||
levelPathLines, annotationLines, compatibilityLines, idLines,
|
||||
(vminfo->height-vnext-vmargin-25-vspacing2)/27, textwidth);
|
||||
if (bestScoreHolderLines == 1) {
|
||||
add(new Label(N_("World Record Holders: "), HALIGN_RIGHT),Rect(hmargin,vnext,200,25));
|
||||
std::string holders;
|
||||
if (withEasy) {
|
||||
holders = theRatingMgr->getBestScoreEasyHolder(aLevel);
|
||||
if (holders.empty())
|
||||
holders = " - ";
|
||||
holders += " / ";
|
||||
}
|
||||
if (theRatingMgr->getBestScoreDifficultHolder(aLevel).empty())
|
||||
holders += " -";
|
||||
else
|
||||
holders += theRatingMgr->getBestScoreDifficultHolder(aLevel);
|
||||
Label *wrLabel = new Label(holders, HALIGN_LEFT);
|
||||
add(wrLabel, Rect(hmargin+200+10,vnext,textwidth-90,25));
|
||||
if (!wrLabel->text_fits()) {
|
||||
int cutEasy = 0;
|
||||
int cutDiff = 0;
|
||||
std::string diffHolders = theRatingMgr->getBestScoreDifficultHolder(aLevel);
|
||||
if (withEasy) {
|
||||
std::string easyHolders = theRatingMgr->getBestScoreEasyHolder(aLevel);
|
||||
bool hasEasyHolders = !easyHolders.empty();
|
||||
bool hasDiffHolders = !diffHolders.empty();
|
||||
int limit = 10;
|
||||
do {
|
||||
std::string cutHolders;
|
||||
wrLabel->set_text(easyHolders);
|
||||
if (!wrLabel->text_fits(0.48)) {
|
||||
cutHolders = theRatingMgr->getBestScoreEasyHolder(aLevel, ++cutEasy);
|
||||
if (cutHolders.empty())
|
||||
cutEasy--;
|
||||
else
|
||||
easyHolders = cutHolders;
|
||||
}
|
||||
wrLabel->set_text(diffHolders);
|
||||
if (!wrLabel->text_fits(0.48)) {
|
||||
cutHolders = theRatingMgr->getBestScoreDifficultHolder(aLevel, ++cutDiff);
|
||||
if (cutHolders.empty())
|
||||
cutDiff--;
|
||||
else
|
||||
diffHolders = cutHolders;
|
||||
}
|
||||
holders = (hasEasyHolders ? easyHolders : std::string(" - "))
|
||||
+ " / " + (hasDiffHolders ? diffHolders : std::string(" -"));
|
||||
wrLabel->set_text(holders);
|
||||
limit--;
|
||||
} while (!wrLabel->text_fits() && limit > 0);
|
||||
} else {
|
||||
std::string cutHolders;
|
||||
do {
|
||||
cutHolders = theRatingMgr->getBestScoreDifficultHolder(aLevel, ++cutDiff);
|
||||
wrLabel->set_text(cutHolders);
|
||||
} while (!wrLabel->text_fits());
|
||||
if (cutHolders.empty()) {
|
||||
// we did cut off to many holders, take last attempt even if it was too long
|
||||
wrLabel->set_text(theRatingMgr->getBestScoreDifficultHolder(aLevel, --cutDiff));
|
||||
}
|
||||
}
|
||||
}
|
||||
vnext += 25 + vspacing;
|
||||
}
|
||||
if (creditsLines >= 1) {
|
||||
add(new Label(N_("Credits: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
std::string creditsString = levelProxy->getCredits(true);
|
||||
for (int i = 0; i< creditsLines; i++) {
|
||||
std::string::size_type breakPos = breakString(menufont, creditsString,
|
||||
" ", textwidth);
|
||||
add(new Label(creditsString.substr(0,breakPos), HALIGN_LEFT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
creditsString = creditsString.substr(breakPos);
|
||||
vnext += (25 + vspacing);
|
||||
}
|
||||
}
|
||||
if (dedicationLines >= 1) {
|
||||
add(new Label(N_("Dedication: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
std::string dedicationString = levelProxy->getDedication(true);
|
||||
for (int i = 0; i< dedicationLines; i++) {
|
||||
std::string::size_type breakPos = breakString( menufont, dedicationString,
|
||||
" ", textwidth);
|
||||
add(new Label(dedicationString.substr(0,breakPos), HALIGN_LEFT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
dedicationString = dedicationString.substr(breakPos);
|
||||
vnext += (25 + vspacing);
|
||||
}
|
||||
}
|
||||
if (levelPathLines >= 1) {
|
||||
add(new Label(N_("Level Path: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
std::string workString = levelPathString;
|
||||
for (int i = 0; i< levelPathLines - 1; i++) {
|
||||
std::string::size_type breakPos = breakString(menufont, workString,
|
||||
"/", textwidth);
|
||||
add(new Label(workString.substr(0,breakPos), HALIGN_LEFT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
workString = workString.substr(breakPos);
|
||||
vnext += (25 + vspacing);
|
||||
}
|
||||
// show as much as possible from last line
|
||||
if (menufont->get_width(workString.c_str()) > textwidth) {
|
||||
// show the filename at the end - skip leading parts if necessary
|
||||
add(new Label(workString, HALIGN_RIGHT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
} else {
|
||||
// display up to the last character
|
||||
add(new Label(workString, HALIGN_LEFT), Rect(hmargin+110+10,vnext,textwidth,25));
|
||||
}
|
||||
vnext += (25 + vspacing);
|
||||
}
|
||||
if (idLines >= 1) {
|
||||
add(new Label(N_("Id: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
add(new Label(levelProxy->getId(), HALIGN_LEFT),Rect(hmargin+110+10, vnext, textwidth, 25));
|
||||
vnext += (25 + vspacing)*idLines;
|
||||
}
|
||||
if (compatibilityLines >= 1) {
|
||||
add(new Label(N_("Compatibility: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
std::string compString = ecl::strf("Enigma v%.2f / ", levelProxy->getEnigmaCompatibility()) +
|
||||
GetGameTypeName(levelProxy->getEngineCompatibility());
|
||||
add(new Label(compString , HALIGN_LEFT),Rect(hmargin+110+10, vnext, textwidth, 25));
|
||||
vnext += (25 + vspacing)*compatibilityLines;
|
||||
}
|
||||
annotation->set_text(app.state->getAnnotation(levelProxy->getId())); // field needs to initialized for saves
|
||||
if (annotationLines >= 1) {
|
||||
add(new Label(N_("Annotation: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
add(annotation, Rect(hmargin+110+10, vnext, textwidth, 25));
|
||||
vnext += (25 + vspacing)*annotationLines;
|
||||
}
|
||||
vnext += vspacing2 - vspacing;
|
||||
add(new Label(N_("Rating: "), HALIGN_RIGHT),Rect(hmargin,vnext,110,25));
|
||||
add(new RatingButton(aLevel),Rect(hmargin+110+10,vnext,40,25));
|
||||
add(new Label(N_("Average: "), HALIGN_RIGHT),Rect(hmargin+110+10+40+20,vnext,105,25));
|
||||
add(new Label(theRatingMgr->getAverageRating(aLevel), HALIGN_RIGHT),Rect(hmargin+110+10+40+18+105+6,vnext,31,25));
|
||||
}
|
||||
|
||||
LevelInspector::~LevelInspector () {
|
||||
}
|
||||
|
||||
bool LevelInspector::isEndDeveloperMode() {
|
||||
return isDeveloperMode;
|
||||
}
|
||||
|
||||
bool LevelInspector::on_event (const SDL_Event &e) {
|
||||
bool handled = false;
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
handled=true;
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_F2:
|
||||
if (!isDeveloperMode) {
|
||||
if (!annotation->getText().empty() ||
|
||||
!app.state->getAnnotation(levelProxy->getId()).empty()) {
|
||||
app.state->setAnnotation(levelProxy->getId(), annotation->getText());
|
||||
}
|
||||
LevelInspector m(levelProxy, true);
|
||||
m.manage();
|
||||
if (m.isEndDeveloperMode()) {
|
||||
// reinit user input fields
|
||||
annotation->set_text(app.state->getAnnotation(levelProxy->getId()));
|
||||
invalidate_all();
|
||||
} else {
|
||||
Menu::quit();
|
||||
}
|
||||
} else {
|
||||
if (!annotation->getText().empty() ||
|
||||
!app.state->getAnnotation(levelProxy->getId()).empty()) {
|
||||
app.state->setAnnotation(levelProxy->getId(), annotation->getText());
|
||||
}
|
||||
Menu::quit();
|
||||
}
|
||||
break;
|
||||
default: handled=false; break;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void LevelInspector::on_action(gui::Widget *w) {
|
||||
if (w == back) {
|
||||
// save annotation - but avoid to save unnecessary empty annotations
|
||||
if (!annotation->getText().empty() ||
|
||||
!app.state->getAnnotation(levelProxy->getId()).empty()) {
|
||||
app.state->setAnnotation(levelProxy->getId(), annotation->getText());
|
||||
}
|
||||
isDeveloperMode = false;
|
||||
Menu::quit();
|
||||
} else if (w == screenshot) {
|
||||
ScreenshotViewer m(levelProxy);
|
||||
m.manage();
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
void LevelInspector::draw_background(ecl::GC &gc) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
video::SetCaption((std::string("Enigma - Level ") +
|
||||
(isDeveloperMode ? "Developer " : "") + "Inspector").c_str());
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
blit(gc, vminfo->width-vminfo->thumbw-10-hmargin, vmargin, previewImage);
|
||||
Surface *img_hard = enigma::GetImage("completed");
|
||||
if (withEasy) {
|
||||
Surface *img_easy = enigma::GetImage("completed-easy");
|
||||
blit (gc, vminfo->width/2-4, vmargin+5*25+4*vspacing+vspacing2, img_easy);
|
||||
blit (gc, vminfo->width/2-4+63, vmargin+5*25+4*vspacing+vspacing2, img_hard);
|
||||
} else {
|
||||
blit (gc, vminfo->width/2-4+20, vmargin+5*25+4*vspacing+vspacing2, img_hard);
|
||||
}
|
||||
Surface *img_changed = enigma::GetImage("changed");
|
||||
ratingInherited = lev::ScoreManager::instance()->isRatingInherited(levelProxy);
|
||||
if (ratingInherited) {
|
||||
int numLines = vminfo->height < 500 ? 14 :(vminfo->height < 650 ? 18 : 19);
|
||||
blit (gc, hmargin+110+10+40, vmargin + numLines*25 +
|
||||
(numLines-3)*vspacing + 3*vspacing2, img_changed);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelInspector::tick(double dtime) {
|
||||
}
|
||||
|
||||
std::string LevelInspector::ratingToString(int value) {
|
||||
if (value == 0) {
|
||||
// no rating available
|
||||
return " ";
|
||||
} else {
|
||||
return ecl::strf("%3d", value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LevelInspector::scoreToString(int easy, int difficult,
|
||||
lev::Proxy *aLevel, bool constLengthForCenteredClipping) {
|
||||
if (withEasy) {
|
||||
if (!constLengthForCenteredClipping)
|
||||
return scoreToString(easy, aLevel) + " / " +
|
||||
scoreToString(difficult, aLevel);
|
||||
else
|
||||
if (aLevel->getScoreUnit() == lev::duration)
|
||||
//
|
||||
return (easy >= 0 ? "- " : ": ") +
|
||||
scoreToString(easy, aLevel) + " / " +
|
||||
scoreToString(difficult, aLevel) +
|
||||
(difficult >= 0 ? " -" : " :") ;
|
||||
else
|
||||
return (easy >= 0 ? "- " : " ") +
|
||||
scoreToString(easy, aLevel) + " / " +
|
||||
scoreToString(difficult, aLevel) +
|
||||
(difficult >= 0 ? " -" : " ") ;
|
||||
} else {
|
||||
return scoreToString(difficult, aLevel);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LevelInspector::scoreToString(int score, lev::Proxy *aLevel) {
|
||||
if (aLevel->getScoreUnit() == lev::duration)
|
||||
if (score >= 0 && score <= (99*60+59))
|
||||
return ecl::strf("%2d:%02d", score/60, score%60);
|
||||
else
|
||||
return " - ";
|
||||
else
|
||||
if (score >= 0 && score <= 9999)
|
||||
return ecl::strf("%4d", score);
|
||||
else
|
||||
return " -";
|
||||
}
|
||||
|
||||
void LevelInspector::dispatchBottomLines(int &bestScoreHolderLines,
|
||||
int &creditsLines, int &dedicationLines, int &levelPathLines,
|
||||
int &annotationLines, int &compatibilityLines, int &idLines, int numLines, int width) {
|
||||
enum botType {holder, credits, dedication, path, annotation, compatibility, id};
|
||||
const int sequenceSize = 13;
|
||||
botType sequence1[sequenceSize] = {credits, dedication, annotation, path,
|
||||
holder, annotation, path, compatibility, credits, dedication,
|
||||
annotation, credits, annotation};
|
||||
botType sequence2[sequenceSize] = {id, path, compatibility, holder, path,
|
||||
annotation, annotation, credits, dedication,
|
||||
credits, dedication, annotation, annotation};
|
||||
botType *sequence = isDeveloperMode ? sequence2 : sequence1;
|
||||
int j = 0;
|
||||
std::string creditsString = levelProxy->getCredits(true);
|
||||
std::string dedicationString = levelProxy->getDedication(true);
|
||||
std::string pathWorkString = levelPathString;
|
||||
ecl::Font *menufont = enigma::GetFont("menufont");
|
||||
for (int i = 0; i<numLines; i++) {
|
||||
bool assigned = false;
|
||||
do {
|
||||
switch (sequence[j++]) {
|
||||
case holder:
|
||||
bestScoreHolderLines++;
|
||||
assigned = true;
|
||||
break;
|
||||
case credits:
|
||||
if (!(creditsString.empty())) {
|
||||
creditsLines++;
|
||||
creditsString = creditsString.substr(breakString(menufont,
|
||||
creditsString, " ", width));
|
||||
assigned = true;
|
||||
}
|
||||
break;
|
||||
case dedication:
|
||||
if (!(dedicationString.empty())) {
|
||||
dedicationLines++;
|
||||
dedicationString = dedicationString.substr(breakString(menufont,
|
||||
dedicationString, " ", width));
|
||||
assigned = true;
|
||||
}
|
||||
break;
|
||||
case path:
|
||||
if (!(pathWorkString.empty())) {
|
||||
levelPathLines++;
|
||||
pathWorkString = pathWorkString.substr(breakString(menufont,
|
||||
pathWorkString, "/", width));
|
||||
assigned = true;
|
||||
}
|
||||
break;
|
||||
case annotation:
|
||||
annotationLines++;
|
||||
assigned = true;
|
||||
break;
|
||||
case compatibility:
|
||||
compatibilityLines++;
|
||||
assigned = true;
|
||||
break;
|
||||
case id:
|
||||
idLines++;
|
||||
assigned = true;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!assigned && j < sequenceSize);
|
||||
if (j == sequenceSize)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace enigma::lev
|
||||
68
project/jni/application/enigma/src/gui/LevelInspector.hh
Normal file
68
project/jni/application/enigma/src/gui/LevelInspector.hh
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GUI_LEVELINSPECTOR_HH_INCLUDED
|
||||
#define GUI_LEVELINSPECTOR_HH_INCLUDED
|
||||
|
||||
#include "ecl.hh"
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
class LevelInspector : public gui::Menu {
|
||||
public:
|
||||
LevelInspector (lev::Proxy *aLevel, bool showDeveloperInfo = false);
|
||||
~LevelInspector ();
|
||||
bool isEndDeveloperMode();
|
||||
private:
|
||||
// ActionListener interface.
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(gui::Widget *w);
|
||||
|
||||
// Menu interface.
|
||||
void draw_background(ecl::GC &gc);
|
||||
void tick(double dtime);
|
||||
|
||||
//
|
||||
std::string ratingToString(int value);
|
||||
std::string scoreToString(int easy, int difficult, lev::Proxy *aLevel,
|
||||
bool constLengthForCenteredClipping);
|
||||
std::string scoreToString(int score, lev::Proxy *aLevel);
|
||||
void dispatchBottomLines(int &bestScoreHolderLines,
|
||||
int &creditsLines, int &dedicationLines, int &levelPathLines,
|
||||
int &annotationLines, int &compatibilityLines, int &idLines, int numLines, int width);
|
||||
// Variables.
|
||||
gui::Widget *back;
|
||||
gui::Widget *screenshot;
|
||||
gui::TextField *annotation;
|
||||
ecl::Surface *previewImage;
|
||||
lev::Proxy *levelProxy;
|
||||
std::string levelPathString;
|
||||
int vspacing;
|
||||
int vspacing2;
|
||||
int vmargin;
|
||||
int hmargin;
|
||||
bool withEasy;
|
||||
bool ratingInherited;
|
||||
bool isDeveloperMode;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
|
||||
499
project/jni/application/enigma/src/gui/LevelMenu.cpp
Normal file
499
project/jni/application/enigma/src/gui/LevelMenu.cpp
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/LevelMenu.hh"
|
||||
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "gui/LevelPackMenu.hh"
|
||||
|
||||
#include "ecl.hh"
|
||||
#include "game.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "server.hh"
|
||||
#include "sound.hh"
|
||||
#include "StateManager.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace ecl;
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Level Menu -------------------- */
|
||||
|
||||
struct LevelMenuConfig {
|
||||
int buttonw, ibuttonw, buttonh;
|
||||
int lbuttonw, lbuttonh;
|
||||
ecl::Rect previewarea;
|
||||
int thumbsy; // y coordinate of thumbnail window
|
||||
int leftborder;
|
||||
|
||||
LevelMenuConfig (const ecl::Rect &screen)
|
||||
: buttonw (140), ibuttonw (90), buttonh (35),
|
||||
lbuttonw (140), lbuttonh (100),
|
||||
previewarea (10, 60, screen.w-50, screen.h-130),
|
||||
thumbsy (60),
|
||||
leftborder (10)
|
||||
{}
|
||||
};
|
||||
|
||||
LevelMenu::LevelMenu()
|
||||
: but_advancemode (new AdvanceModeButton),
|
||||
but_next (new ImageButton("ic-next", "ic-next1", this)),
|
||||
but_back (new StaticTextButton(N_("Main Menu"), this)),
|
||||
but_difficulty (new DifficultyButton),
|
||||
but_levelpack (new StaticTextButton(N_("Level Pack"), this)),
|
||||
lbl_lpinfo (new Label("")),
|
||||
lbl_statistics (new Label("")),
|
||||
lbl_levelname (new Label("", HALIGN_LEFT)),
|
||||
lbl_levelinfo (new Label("", HALIGN_LEFT)),
|
||||
shown_text_ttl(-1.0), main_quit (false)
|
||||
{
|
||||
HList *hl, *hll, *hlr ;
|
||||
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
|
||||
// Levelmenu configuration
|
||||
const int Y2 = 10; // y position for information area
|
||||
const int Y3 = vminfo.height-50; // y position for bottom button row
|
||||
LevelMenuConfig c (Rect (0, 0, vminfo.width, vminfo.height));
|
||||
|
||||
but_difficulty->set_listener (this);
|
||||
|
||||
|
||||
// Create buttons
|
||||
hll = new HList;
|
||||
hll->set_spacing (10);
|
||||
hll->set_alignment (HALIGN_CENTER, VALIGN_TOP);
|
||||
hll->set_default_size (c.ibuttonw, c.buttonh);
|
||||
hll->add_back (but_advancemode);
|
||||
hll->add_back (but_next);
|
||||
hll->add_back (but_difficulty);
|
||||
|
||||
hlr = new HList;
|
||||
hlr->set_spacing (10);
|
||||
hlr->set_alignment (HALIGN_CENTER, VALIGN_TOP);
|
||||
hlr->set_default_size (c.buttonw, c.buttonh);
|
||||
hlr->add_back (but_levelpack);
|
||||
hlr->add_back (but_back);
|
||||
|
||||
hl = new HList;
|
||||
hl->set_spacing (10);
|
||||
hl->set_alignment (HALIGN_CENTER, VALIGN_TOP);
|
||||
hl->set_default_size (2*c.buttonw + 10, c.buttonh);
|
||||
hl->add_back (hll);
|
||||
hl->add_back (hlr);
|
||||
this->add (hl, Rect(c.leftborder, Y3, vminfo.width-20, c.buttonh));
|
||||
|
||||
// Add navigation buttons
|
||||
pgup = new ImageButton("ic-up", "ic-up1", this);
|
||||
pgdown = new ImageButton("ic-down", "ic-down1", this);
|
||||
start = new ImageButton("ic-top", "ic-top1", this);
|
||||
end = new ImageButton("ic-bottom", "ic-bottom1", this);
|
||||
|
||||
Rect r(vminfo.width-30, c.thumbsy, 20, 50);
|
||||
r.y = c.thumbsy;
|
||||
add (pgup, r);
|
||||
r.y += 60;
|
||||
add (pgdown, r);
|
||||
r.y = c.thumbsy + 240;
|
||||
add (start, r);
|
||||
r.y += 60;
|
||||
add (end, r);
|
||||
|
||||
// Information area
|
||||
hl = new HList;
|
||||
hl->add_back (lbl_levelname, List::EXPAND);
|
||||
hl->add_back (lbl_lpinfo, List::TIGHT);
|
||||
this->add (hl, Rect (5, Y2, vminfo.width - 10, 28));
|
||||
|
||||
hl_info_stat = new HList;
|
||||
hl_info_stat->add_back (lbl_levelinfo, List::EXPAND); //Rect (c.leftborder, Y2+20,305, 28));
|
||||
hl_info_stat->add_back (lbl_statistics, List::TIGHT);
|
||||
this->add (hl_info_stat, Rect (5, Y2+20, vminfo.width - 10, 28));
|
||||
|
||||
// Prepare level selection widget
|
||||
levelwidget = new LevelWidget();
|
||||
levelwidget->set_listener(this);
|
||||
levelwidget->realize (c.previewarea);
|
||||
levelwidget->set_area (c.previewarea);
|
||||
|
||||
this->add (levelwidget);
|
||||
|
||||
updateIndex();
|
||||
}
|
||||
|
||||
void LevelMenu::tick(double dtime)
|
||||
{
|
||||
levelwidget->tick(dtime);
|
||||
static double timeaccu = 0.0;
|
||||
|
||||
// info texts disappear after some time
|
||||
if (shown_text_ttl>0.0) {
|
||||
shown_text_ttl -= dtime;
|
||||
if (shown_text_ttl <= 0.0)
|
||||
shown_text = "";
|
||||
}
|
||||
timeaccu += dtime;
|
||||
if (timeaccu > 0.1) {
|
||||
update_info();
|
||||
timeaccu = 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const char *helptext_levelmenu[] = {
|
||||
N_("Escape:"), N_("Skip to main menu"),
|
||||
"F1:", N_("Show this help"),
|
||||
"F5:", 0, // see below
|
||||
N_("Arrows:"), N_("Select level"),
|
||||
N_("Return:"), N_("Play selected level"),
|
||||
N_("Back/Space:"), N_("Previous/next levelpack"),
|
||||
"u", N_("Mark current level as Unsolved"),
|
||||
// "s", N_("Mark current level as Solved"),
|
||||
N_("Alt+Return:"), N_("Switch between fullscreen and window"),
|
||||
N_("Left click:"), N_("Play selected level"),
|
||||
N_("Right or control click:"), N_("Inspect selected level"),
|
||||
0
|
||||
};
|
||||
|
||||
bool LevelMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
// Pass all events to the level widget first
|
||||
bool handled=levelwidget->on_event(e);
|
||||
|
||||
if (!handled) {
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
handled=true;
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_SPACE: next_levelpack(); break;
|
||||
case SDLK_BACKSPACE: previous_levelpack(); break;
|
||||
case SDLK_F1:
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST)
|
||||
helptext_levelmenu[5] = N_("Select next level for world record hunt");
|
||||
else
|
||||
helptext_levelmenu[5] = N_("Select next unsolved level");
|
||||
|
||||
displayHelp(helptext_levelmenu, 200);
|
||||
draw_all();
|
||||
break;
|
||||
case SDLK_F5:
|
||||
next_unsolved();
|
||||
break;
|
||||
case SDLK_u: {
|
||||
lev::ScoreManager::instance()->markUnsolved(lev::Index::getCurrentProxy(),
|
||||
app.state->getInt("Difficulty"));
|
||||
invalidate_all();
|
||||
break;
|
||||
}
|
||||
case SDLK_s:
|
||||
lev::ScoreManager::instance()->markSolved(lev::Index::getCurrentProxy(),
|
||||
app.state->getInt("Difficulty"));
|
||||
invalidate_all();
|
||||
break;
|
||||
default: handled=false; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
handled = Menu::on_event (e);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void LevelMenu::on_action(Widget *w)
|
||||
{
|
||||
if (w==levelwidget) {
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
int ilevel = ind->getCurrentPosition();
|
||||
if (w->lastModifierKeys() & KMOD_CTRL && w->lastModifierKeys() & KMOD_SHIFT) {
|
||||
// force a reload from file
|
||||
lev::Proxy * curProxy = lev::Proxy::loadedLevel();
|
||||
if (curProxy != NULL)
|
||||
curProxy->release();
|
||||
}
|
||||
|
||||
if ((unsigned)ilevel < ind->size()) {
|
||||
if (ind->mayPlayLevel(ilevel+1)) {
|
||||
game::StartGame();
|
||||
ilevel = ind->getCurrentPosition();
|
||||
invalidate_all();
|
||||
ind->setCurrentPosition(ilevel);
|
||||
levelwidget->syncFromIndexMgr();
|
||||
}
|
||||
else
|
||||
show_text(_("You are not allowed to play this level yet."));
|
||||
}
|
||||
} else if (w == but_back) {
|
||||
main_quit = true;
|
||||
Menu::quit();
|
||||
} else if (w == pgup) {
|
||||
levelwidget->page_up();
|
||||
} else if (w == pgdown) {
|
||||
levelwidget->page_down();
|
||||
} else if (w == start) {
|
||||
levelwidget->start();
|
||||
} else if (w == end) {
|
||||
levelwidget->end();
|
||||
} else if (w == but_next) {
|
||||
next_unsolved();
|
||||
} else if (w == but_levelpack) {
|
||||
main_quit = false;
|
||||
Menu::quit();
|
||||
} else if (w == but_difficulty) {
|
||||
but_difficulty->on_action(w);
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
void LevelMenu::update_info() {
|
||||
// Note: all format strings have to be translated directly
|
||||
// as the formatted strings can no longer be translated.
|
||||
// The instant language change is guaranteed by the frequent
|
||||
// call of is method!
|
||||
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
int size = ind->size();
|
||||
lev::ScoreManager *scm = lev::ScoreManager::instance();
|
||||
lev::Proxy *curProxy = ind->getCurrent();
|
||||
int difficulty = app.state->getInt("Difficulty");
|
||||
|
||||
lbl_lpinfo->set_text(ecl::strf(_("%s: %d levels"),
|
||||
ind->getName().c_str(), size));
|
||||
|
||||
if (size == 0) {
|
||||
// empty level pack
|
||||
lbl_statistics->set_text ("-");
|
||||
lbl_levelname->set_text ("-");
|
||||
lbl_levelinfo->set_text ("-");
|
||||
}
|
||||
else {
|
||||
int iselected = ind->getCurrentPosition();
|
||||
|
||||
// Display levelpack statistics (percentage of solved levels)
|
||||
|
||||
if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_NOT_BEST) {
|
||||
int pct = 100* scm->countBestScore(ind, difficulty)/ size;
|
||||
lbl_statistics->set_text(ecl::strf(_("%d%% best"), pct));
|
||||
}
|
||||
else if (app.state->getInt("NextLevelMode") == lev::NEXT_LEVEL_OVER_PAR) {
|
||||
int pct = 100* scm->countParScore(ind, difficulty)/ size;
|
||||
double hcp = scm->calcHCP(ind, difficulty);
|
||||
lbl_statistics->set_text(ecl::strf(_("%d%% par, hcp %.1f"), pct, hcp));
|
||||
}
|
||||
else {
|
||||
int pct = 100* scm->countSolved(ind, difficulty) / size;
|
||||
lbl_statistics->set_text(ecl::strf(_("%d%% solved"), pct));
|
||||
}
|
||||
|
||||
// Display level name
|
||||
if (enigma::WizardMode) {
|
||||
// add level path info - we just can display the normalized path
|
||||
// as we did not yet locate the absolute path - the user can
|
||||
// use the inspector to check the absolute path!
|
||||
lbl_levelname->set_text(ecl::strf("#%d: %s (%s)",
|
||||
ind->getCurrentLevel(), curProxy->getTitle().c_str(),
|
||||
curProxy->getNormLevelPath().c_str()));
|
||||
} else {
|
||||
lbl_levelname->set_text(ecl::strf("#%d: %s",
|
||||
ind->getCurrentLevel(), curProxy->getTitle().c_str()));
|
||||
}
|
||||
|
||||
// Display best time
|
||||
if (shown_text.length()) {
|
||||
lbl_levelinfo->set_text(shown_text);
|
||||
}
|
||||
else {
|
||||
// TODO prepare for scores that are not time based!
|
||||
char txt[200];
|
||||
lev::RatingManager *ratingMgr = lev::RatingManager::instance();
|
||||
int wr_time = ratingMgr->getBestScore(curProxy, difficulty);
|
||||
int par_time = ratingMgr->getParScore(curProxy, difficulty);
|
||||
bool is_par = scm->parScoreReached(curProxy, difficulty);
|
||||
int best_user_time = scm->getBestUserScore(curProxy, difficulty);
|
||||
string wr_name = ratingMgr->getBestScoreHolder(curProxy, difficulty);
|
||||
bool wr_name_displayed = false;
|
||||
|
||||
string your_time;
|
||||
string wr_text;
|
||||
|
||||
if (best_user_time>0) {
|
||||
your_time = strf(_("Your time: %d:%02d"),
|
||||
best_user_time/60, best_user_time%60);
|
||||
|
||||
if (wr_time>0) {
|
||||
int below = wr_time - best_user_time;
|
||||
if (below == 0)
|
||||
wr_text = _("That's world record.");
|
||||
else if (below>0)
|
||||
wr_text = strf(_("That's %d:%02d below world record."),
|
||||
below/60, below%60);
|
||||
}
|
||||
}
|
||||
|
||||
if (wr_text.length() == 0 && wr_time>0) {
|
||||
if (wr_name.length()) {
|
||||
wr_name_displayed = true;
|
||||
} else
|
||||
if (is_par || par_time < 0)
|
||||
wr_text = strf(_("World record: %d:%02d"), wr_time/60, wr_time%60);
|
||||
else
|
||||
wr_text = strf(_("Par: %d:%02d World record: %d:%02d"),
|
||||
par_time/60, par_time%60, wr_time/60, wr_time%60);
|
||||
}
|
||||
|
||||
if (!your_time.empty())
|
||||
your_time += " ";
|
||||
|
||||
int wr_cut = 0;
|
||||
do {
|
||||
if (wr_name_displayed) {
|
||||
std::string tmp = ratingMgr->getBestScoreHolder(curProxy, difficulty, wr_cut++);
|
||||
if (!tmp.empty())
|
||||
wr_name = tmp;
|
||||
if (is_par || par_time < 0)
|
||||
wr_text = strf(_("World record by %s: %d:%02d"),
|
||||
wr_name.c_str(), wr_time/60, wr_time%60);
|
||||
else
|
||||
wr_text = strf(_("Par: %d:%02d World record by %s: %d:%02d"),
|
||||
par_time/60, par_time%60, wr_name.c_str(), wr_time/60, wr_time%60);
|
||||
}
|
||||
lbl_levelinfo->set_text(your_time + wr_text);
|
||||
} while (!hl_info_stat->fits() && wr_name_displayed && (wr_cut < 20));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelMenu::updateIndex()
|
||||
{
|
||||
levelwidget->syncFromIndexMgr();
|
||||
|
||||
update_info();
|
||||
}
|
||||
|
||||
void LevelMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
video::SetCaption(("Enigma - Level Menu"));
|
||||
sound::PlayMusic (options::GetString("MenuMusicFile"));
|
||||
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
void LevelMenu::next_unsolved()
|
||||
{
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
if (ind->advanceLevel(lev::ADVANCE_NEXT_MODE)) {
|
||||
levelwidget->syncFromIndexMgr();
|
||||
} else
|
||||
show_text(_("No further unsolved level available!"));
|
||||
}
|
||||
|
||||
void LevelMenu::next_levelpack()
|
||||
{
|
||||
lev::Index::setCurrentIndex(lev::Index::nextGroupIndex()->getName());
|
||||
updateIndex();
|
||||
}
|
||||
|
||||
void LevelMenu::previous_levelpack() {
|
||||
lev::Index::setCurrentIndex(lev::Index::previousGroupIndex()->getName());
|
||||
updateIndex();
|
||||
}
|
||||
|
||||
void LevelMenu::show_text(const string& text) {
|
||||
shown_text = text;
|
||||
shown_text_ttl = 2.0; // show for two seconds
|
||||
}
|
||||
|
||||
bool LevelMenu::isMainQuit() {
|
||||
return main_quit;
|
||||
}
|
||||
|
||||
/* -------------------- DifficultyButton -------------------- */
|
||||
|
||||
DifficultyButton::DifficultyButton() : ImageButton("ic-easymode","ic-easymode",this) {
|
||||
update();
|
||||
}
|
||||
|
||||
void DifficultyButton::update() {
|
||||
if (app.state->getInt("Difficulty") == DIFFICULTY_EASY)
|
||||
ImageButton::set_images("ic-easymode","ic-normalmode");
|
||||
else
|
||||
ImageButton::set_images("ic-normalmode","ic-easymode");
|
||||
}
|
||||
|
||||
void DifficultyButton::on_action(Widget *)
|
||||
{
|
||||
int newdifficulty = (DIFFICULTY_EASY+DIFFICULTY_HARD) - app.state->getInt("Difficulty");
|
||||
app.state->setProperty("Difficulty", newdifficulty); update();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void DifficultyButton::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
update();
|
||||
ImageButton::draw(gc, r);
|
||||
}
|
||||
|
||||
/* -------------------- AdvanceModeButton -------------------- */
|
||||
|
||||
AdvanceModeButton::AdvanceModeButton() : ImageButton("","",this) {
|
||||
update();
|
||||
}
|
||||
|
||||
void AdvanceModeButton::update() {
|
||||
switch (app.state->getInt("NextLevelMode")) {
|
||||
case lev::NEXT_LEVEL_UNSOLVED :
|
||||
ImageButton::set_images("ic-unsolved", "par");
|
||||
break;
|
||||
case lev::NEXT_LEVEL_OVER_PAR :
|
||||
ImageButton::set_images("par", "ic-worldrecord");
|
||||
break;
|
||||
case lev::NEXT_LEVEL_NOT_BEST :
|
||||
ImageButton::set_images("ic-worldrecord", "ic-strictlynext");
|
||||
break;
|
||||
case lev::NEXT_LEVEL_STRICTLY : // use as default, too
|
||||
default:
|
||||
ImageButton::set_images("ic-strictlynext","ic-unsolved");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AdvanceModeButton::on_action(Widget *)
|
||||
{
|
||||
switch (app.state->getInt("NextLevelMode")) {
|
||||
case lev::NEXT_LEVEL_STRICTLY :
|
||||
app.state->setProperty("NextLevelMode", lev::NEXT_LEVEL_UNSOLVED);
|
||||
break;
|
||||
case lev::NEXT_LEVEL_UNSOLVED :
|
||||
app.state->setProperty("NextLevelMode", lev::NEXT_LEVEL_OVER_PAR);
|
||||
break;
|
||||
case lev::NEXT_LEVEL_OVER_PAR :
|
||||
app.state->setProperty("NextLevelMode", lev::NEXT_LEVEL_NOT_BEST);
|
||||
break;
|
||||
case lev::NEXT_LEVEL_NOT_BEST :
|
||||
default:
|
||||
app.state->setProperty("NextLevelMode", lev::NEXT_LEVEL_STRICTLY);
|
||||
}
|
||||
update();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
99
project/jni/application/enigma/src/gui/LevelMenu.hh
Normal file
99
project/jni/application/enigma/src/gui/LevelMenu.hh
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_LEVELMENU_HH_INCLUDED
|
||||
#define GUI_LEVELMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/LevelWidget.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelMenu -------------------- */
|
||||
|
||||
class LevelMenu : public Menu {
|
||||
public:
|
||||
LevelMenu();
|
||||
|
||||
// Rotate through levels and packs
|
||||
void next_levelpack();
|
||||
void previous_levelpack();
|
||||
void show_text(const string& text);
|
||||
bool isMainQuit();
|
||||
|
||||
private:
|
||||
void update_info();
|
||||
void next_unsolved();
|
||||
|
||||
void updateIndex();
|
||||
|
||||
// Menu interface.
|
||||
void tick (double time);
|
||||
void draw_background(ecl::GC &gc);
|
||||
|
||||
// Widget interface.
|
||||
bool on_event (const SDL_Event &e);
|
||||
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *w);
|
||||
|
||||
// Variables.
|
||||
|
||||
|
||||
Widget *pgup, *pgdown, *start, *end;
|
||||
Widget *but_advancemode; // Next unsolved level button
|
||||
Widget *but_next;
|
||||
Widget *but_back; // "Back" button
|
||||
Widget *but_difficulty; // "Difficulty" button
|
||||
TextButton *but_levelpack; // "Levelpack" button
|
||||
HList *hl_info_stat;
|
||||
Label *lbl_lpinfo; // Levelpack information
|
||||
Label *lbl_statistics; // percentage solved
|
||||
Label *lbl_levelname;
|
||||
Label *lbl_levelinfo;
|
||||
LevelWidget *levelwidget;
|
||||
string shown_text; // info text (disappears automatically)
|
||||
double shown_text_ttl; // rest duration for shown_text
|
||||
bool main_quit;
|
||||
};
|
||||
|
||||
/* -------------------- Buttons -------------------- */
|
||||
|
||||
class DifficultyButton : public ImageButton {
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *);
|
||||
public:
|
||||
DifficultyButton();
|
||||
virtual void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
void update();
|
||||
};
|
||||
|
||||
class AdvanceModeButton : public ImageButton {
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *);
|
||||
public:
|
||||
AdvanceModeButton();
|
||||
private:
|
||||
void update();
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
391
project/jni/application/enigma/src/gui/LevelPackComposer.cpp
Normal file
391
project/jni/application/enigma/src/gui/LevelPackComposer.cpp
Normal file
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/LevelPackComposer.hh"
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "errors.hh"
|
||||
#include "nls.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
lev::PersistentIndex * LevelPackComposer::clipboard = NULL;
|
||||
|
||||
static const char *helptext[] = {
|
||||
N_("Shift click:"), N_("Add to clipboard"),
|
||||
N_("Shift delete:"), N_("Clear clipboard"),
|
||||
N_("F8:"), N_("Insert clipboard as reference"),
|
||||
N_("F9:"), N_("Insert clipboard as copy"),
|
||||
// N_("F10:"), N_("Move clipboard levels"),
|
||||
N_("Alt left arrow:"), N_("Exchange level with predecessor"),
|
||||
N_("Alt right arrow:"), N_("Exchange level with successor"),
|
||||
N_("Delete:"), N_("Delete level"),
|
||||
N_("F5:"), N_("Update index from levels"),
|
||||
0
|
||||
};
|
||||
#if 0
|
||||
// fake gettext to register the following strings for I18N
|
||||
_("F10")
|
||||
_("Move clipboard levels")
|
||||
#endif
|
||||
|
||||
|
||||
LevelPackComposer::LevelPackComposer(bool enableEdit) :
|
||||
isEditable (enableEdit), isModified (false) {
|
||||
if (clipboard == NULL) {
|
||||
std::vector<std::string> dummy;
|
||||
clipboard = new lev::PersistentIndex(" ", false); // mark as incomplete
|
||||
}
|
||||
|
||||
curIndex = dynamic_cast<lev::PersistentIndex *>(lev::Index::getCurrentIndex());
|
||||
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
// Add navigation buttons
|
||||
pgup = new ImageButton("ic-up", "ic-up1", this);
|
||||
pgdown = new ImageButton("ic-down", "ic-down1", this);
|
||||
start = new ImageButton("ic-top", "ic-top1", this);
|
||||
end = new ImageButton("ic-bottom", "ic-bottom1", this);
|
||||
|
||||
Rect r(vminfo.width-30, 60, 20, 50);
|
||||
r.y = 60;
|
||||
add (pgup, r);
|
||||
r.y += 60;
|
||||
add (pgdown, r);
|
||||
r.y = 60 + 240;
|
||||
add (start, r);
|
||||
r.y += 60;
|
||||
add (end, r);
|
||||
|
||||
// Prepare level selection widget
|
||||
levelwidget = new LevelWidget(false, isEditable);
|
||||
levelwidget->set_listener(this);
|
||||
ecl::Rect previewarea(10, 60, vminfo.width-50, vminfo.height-130);
|
||||
levelwidget->realize (previewarea);
|
||||
levelwidget->set_area (previewarea);
|
||||
|
||||
this->add(levelwidget);
|
||||
|
||||
// Information area
|
||||
lbl_lpinfo = new Label();
|
||||
lbl_clipinfo = new Label();
|
||||
lbl_levelname = new Label();
|
||||
lbl_clipcontent = new Label();
|
||||
|
||||
HList *hl = new HList;
|
||||
hl->set_spacing(10);
|
||||
hl->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
hl->set_default_size(vminfo.width/2 - 10, 28);
|
||||
hl->add_back (lbl_lpinfo);
|
||||
hl->add_back (lbl_clipinfo);
|
||||
this->add (hl, Rect (5, 10, vminfo.width - 10, 28));
|
||||
|
||||
hl = new HList;
|
||||
hl->set_spacing(10);
|
||||
hl->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
clipContentWidth = vminfo.width/2 - 10;
|
||||
hl->set_default_size(clipContentWidth, 28);
|
||||
hl->add_back (lbl_levelname);
|
||||
hl->add_back (lbl_clipcontent);
|
||||
this->add (hl, Rect (5, 10+20, vminfo.width - 10, 28));
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
but_ignore = new StaticTextButton(N_("Undo"), this);
|
||||
but_back = new StaticTextButton(N_("Ok"), this);
|
||||
|
||||
HList * commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
commandHList->add_back(new Label());
|
||||
commandHList->add_back(new Label());
|
||||
commandHList->add_back(but_ignore);
|
||||
commandHList->add_back(but_back);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
|
||||
}
|
||||
|
||||
void LevelPackComposer::tick(double dtime)
|
||||
{
|
||||
levelwidget->tick(dtime);
|
||||
static double timeaccu = 0.0;
|
||||
|
||||
// // info texts disappear after some time
|
||||
// if (shown_text_ttl>0.0) {
|
||||
// shown_text_ttl -= dtime;
|
||||
// if (shown_text_ttl <= 0.0)
|
||||
// shown_text = "";
|
||||
// }
|
||||
timeaccu += dtime;
|
||||
if (timeaccu > 0.1) {
|
||||
update_info();
|
||||
timeaccu = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelPackComposer::on_event (const SDL_Event &e) {
|
||||
// Pass all events to the level widget first
|
||||
bool handled=levelwidget->on_event(e);
|
||||
|
||||
if (!handled) {
|
||||
if (e.type == SDL_KEYDOWN) {
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_DELETE:
|
||||
if (SDL_GetModState() & KMOD_SHIFT) {
|
||||
// delete clipboard
|
||||
clipboard->clear();
|
||||
handled=true;
|
||||
} else {
|
||||
// delete level
|
||||
if (isEditable) {
|
||||
int pos = curIndex->getCurrentPosition();
|
||||
lev::Proxy * curProxy = curIndex->getCurrent();
|
||||
if (curProxy == NULL) {
|
||||
// levelpack is empty
|
||||
handled=true;
|
||||
break;
|
||||
}
|
||||
if (curIndex->isSource(curProxy) &&
|
||||
backups.find(curProxy->getNormLevelPath()) == backups.end()) {
|
||||
// mark as deletion candidate - the final check
|
||||
// if we delete it really occurs on save
|
||||
deletions.insert(curProxy->getNormLevelPath());
|
||||
}
|
||||
curIndex->erase(pos);
|
||||
if (pos >= curIndex->size() && pos > 0)
|
||||
curIndex->setCurrentPosition(pos-1);
|
||||
levelwidget->syncFromIndexMgr();
|
||||
isModified = true;
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_F8:
|
||||
if (isEditable) {
|
||||
int pos = (curIndex->size() == 0) ? 0 : curIndex->getCurrentPosition() + 1;
|
||||
for (int i = 0; i < clipboard->size(); i++) {
|
||||
lev::Variation var = clipboard->getVariation(i);
|
||||
curIndex->insertProxy(pos++, clipboard->getProxy(i), true,
|
||||
var.ctrl, var.unit, var.target, var.extensions);
|
||||
isModified = true;
|
||||
}
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_F9:
|
||||
if (isEditable && !curIndex->isCross()) {
|
||||
int pos = (curIndex->size() == 0) ? 0 : curIndex->getCurrentPosition() + 1;
|
||||
for (int i = 0; i < clipboard->size(); i++) {
|
||||
lev::Variation var = clipboard->getVariation(i);
|
||||
lev::Proxy *levelCopy = clipboard->getProxy(i)->copy(app.userPath + "/levels",
|
||||
curIndex->getPackPath(), true);
|
||||
if (levelCopy == NULL) {
|
||||
// insert a crossreference
|
||||
curIndex->insertProxy(pos++, clipboard->getProxy(i), true,
|
||||
var.ctrl, var.unit, var.target, var.extensions);
|
||||
} else {
|
||||
// insert reference to our copy
|
||||
curIndex->insertProxy(pos++, levelCopy, true,
|
||||
var.ctrl, var.unit, var.target, var.extensions);
|
||||
backups.insert(levelCopy->getNormLevelPath());
|
||||
deletions.erase(levelCopy->getNormLevelPath());
|
||||
}
|
||||
isModified = true;
|
||||
}
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
if (isEditable && (SDL_GetModState() & KMOD_ALT)) {
|
||||
int pos = curIndex->getCurrentPosition();
|
||||
if (pos > 0) {
|
||||
curIndex->exchange(pos, pos-1);
|
||||
levelwidget->syncFromIndexMgr();
|
||||
isModified = true;
|
||||
}
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
if (isEditable && (SDL_GetModState() & KMOD_ALT)) {
|
||||
int pos = curIndex->getCurrentPosition();
|
||||
if (pos < curIndex->size() - 1) {
|
||||
curIndex->exchange(pos, pos+1);
|
||||
levelwidget->syncFromIndexMgr();
|
||||
isModified = true;
|
||||
}
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_F5:
|
||||
if (isEditable) {
|
||||
curIndex->updateFromProxies();
|
||||
isModified = true;
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
}
|
||||
break;
|
||||
case SDLK_F1:
|
||||
displayHelp(helptext, 200);
|
||||
invalidate_all();
|
||||
handled=true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
handled = Menu::on_event (e);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void LevelPackComposer::on_action(Widget *w) {
|
||||
if (w==levelwidget) {
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
int ilevel = ind->getCurrentPosition();
|
||||
if (w->lastModifierKeys() & KMOD_SHIFT) {
|
||||
lev::Variation var;
|
||||
lev::Proxy * curProxy = lev::Index::getCurrentProxy();
|
||||
if (curProxy->getNormPathType() != lev::Proxy::pt_absolute) {
|
||||
// all but absolute commandline proxies may be put on the clipboard
|
||||
if (curIndex != NULL)
|
||||
var = curIndex->getVariation(curIndex->getCurrentPosition());
|
||||
clipboard->appendProxy(curProxy, var.ctrl,
|
||||
var.unit, var.target, var.extensions);
|
||||
sound::EmitSoundEvent ("menuok");
|
||||
} else {
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
}
|
||||
}
|
||||
} else if (w == but_back) {
|
||||
if (isModified) {
|
||||
// save index
|
||||
curIndex->save(true);
|
||||
// delete levelfiles
|
||||
std::set<std::string>::iterator it;
|
||||
for (it = deletions.begin(); it != deletions.end(); it++) {
|
||||
if (!curIndex->hasNormLevelPath(*it)) {
|
||||
// delete plain files on user path - ignore system and zip levels
|
||||
std::string path = app.userPath + "/levels/" + (*it);
|
||||
std::remove((path + ".xml").c_str());
|
||||
std::remove((path + ".lua").c_str());
|
||||
}
|
||||
}
|
||||
// delete backups
|
||||
std::string base = app.userPath + "/levels/";
|
||||
for (it = backups.begin(); it != backups.end(); it++) {
|
||||
std::remove((base + *it + ".xml~").c_str());
|
||||
std::remove((base + *it + ".lua~").c_str());
|
||||
}
|
||||
}
|
||||
Menu::quit();
|
||||
} else if (w == but_ignore) {
|
||||
if (isModified) {
|
||||
// we need to reload the index
|
||||
curIndex->loadDoc();
|
||||
// restore backups
|
||||
std::string base = app.userPath + "/levels/";
|
||||
std::set<std::string>::iterator it;
|
||||
for (it = backups.begin(); it != backups.end(); it++) {
|
||||
std::remove((base + *it + ".xml").c_str());
|
||||
std::rename((base + *it + ".xml~").c_str(), (base + *it + ".xml").c_str());
|
||||
std::remove((base + *it + ".lua").c_str());
|
||||
std::rename((base + *it + ".lua~").c_str(), (base + *it + ".lua").c_str());
|
||||
}
|
||||
}
|
||||
Menu::quit();
|
||||
} else if (w == pgup) {
|
||||
levelwidget->page_up();
|
||||
} else if (w == pgdown) {
|
||||
levelwidget->page_down();
|
||||
} else if (w == start) {
|
||||
levelwidget->start();
|
||||
} else if (w == end) {
|
||||
levelwidget->end();
|
||||
}
|
||||
}
|
||||
void LevelPackComposer::update_info() {
|
||||
// Note: all format strings have to be translated directly
|
||||
// as the formatted strings can no longer be translated.
|
||||
// The instant language change is guaranteed by the frequent
|
||||
// call of is method!
|
||||
|
||||
lev::Index *ind = lev::Index::getCurrentIndex();
|
||||
int size = ind->size();
|
||||
lev::Proxy *curProxy = ind->getCurrent();
|
||||
|
||||
lbl_lpinfo->set_text(ecl::strf(_("%s: %d levels"),
|
||||
ind->getName().c_str(), size));
|
||||
|
||||
if (size == 0) {
|
||||
// empty level pack
|
||||
lbl_levelname->set_text ("-");
|
||||
}
|
||||
else {
|
||||
lbl_levelname->set_text(ecl::strf("#%d:(%s)",
|
||||
ind->getCurrentLevel(),
|
||||
curProxy->getNormLevelPath().c_str()));
|
||||
}
|
||||
|
||||
int csize = clipboard->size();
|
||||
lbl_clipinfo->set_text(ecl::strf(_("Clipboard: %d levels"), csize));
|
||||
if (csize == 0) {
|
||||
// empty level pack
|
||||
lbl_clipcontent->set_text ("-");
|
||||
}
|
||||
else {
|
||||
std::string clipstring = clipboard->getProxy(0)->getTitle();
|
||||
for (int i = 1; i < csize; i++)
|
||||
clipstring += ", " + clipboard->getProxy(i)->getTitle();
|
||||
lbl_clipcontent->set_text(clipstring);
|
||||
if (enigma::GetFont("menufont")->get_width(clipstring.c_str()) > clipContentWidth)
|
||||
lbl_clipcontent->set_alignment(HALIGN_RIGHT);
|
||||
else
|
||||
lbl_clipcontent->set_alignment(HALIGN_CENTER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LevelPackComposer::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Level Pack Composer"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
if (isModified)
|
||||
|
||||
blit(gc, 0,0, enigma::GetImage("changed"));
|
||||
}
|
||||
|
||||
|
||||
}} // namespace enigma::gui
|
||||
61
project/jni/application/enigma/src/gui/LevelPackComposer.hh
Normal file
61
project/jni/application/enigma/src/gui/LevelPackComposer.hh
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GUI_LEVELPACKCOMPOSER_HH_INCLUDED
|
||||
#define GUI_LEVELPACKCOMPOSER_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/LevelWidget.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/PersistentIndex.hh"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
class LevelPackComposer : public gui::Menu {
|
||||
public:
|
||||
LevelPackComposer(bool enableEdit);
|
||||
|
||||
void tick(double dtime);
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
private:
|
||||
void update_info();
|
||||
|
||||
static lev::PersistentIndex * clipboard;
|
||||
bool isEditable;
|
||||
bool isModified;
|
||||
lev::PersistentIndex * curIndex;
|
||||
std::set<std::string> deletions; // normLevelPath
|
||||
std::set<std::string> backups; // normLevelPath
|
||||
Widget *pgup, *pgdown, *start, *end;
|
||||
LevelWidget *levelwidget;
|
||||
Label *lbl_lpinfo; // Levelpack information
|
||||
Label *lbl_levelname;
|
||||
Label *lbl_clipinfo;
|
||||
Label *lbl_clipcontent;
|
||||
int clipContentWidth;
|
||||
Widget *but_ignore;
|
||||
Widget *but_back;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
540
project/jni/application/enigma/src/gui/LevelPackConfig.cpp
Normal file
540
project/jni/application/enigma/src/gui/LevelPackConfig.cpp
Normal file
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
* Copyright (C) 2006, 2007 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/LevelPackConfig.hh"
|
||||
#include "gui/LevelPackComposer.hh"
|
||||
#include "ecl.hh"
|
||||
#include "errors.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
GroupButton::GroupButton(std::vector<std::string> groups, int pos) :
|
||||
ValueButton(0, groups.size() - 1),
|
||||
position (pos), groupNames (groups) {
|
||||
init();
|
||||
}
|
||||
|
||||
int GroupButton::get_value() const {
|
||||
return position;
|
||||
}
|
||||
|
||||
void GroupButton::set_value(int value) {
|
||||
position = value;
|
||||
}
|
||||
|
||||
std::string GroupButton::get_text(int value) const {
|
||||
return groupNames[value];
|
||||
}
|
||||
|
||||
/* ------------------- LevelmodeButton -------------------- */
|
||||
|
||||
LevelmodeButton::LevelmodeButton(bool initialMode) :
|
||||
ImageButton("ic-link_copy","ic-link_copy",this), mode (initialMode) {
|
||||
update();
|
||||
}
|
||||
|
||||
bool LevelmodeButton::isLinkOnly() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
void LevelmodeButton::update() {
|
||||
if (mode)
|
||||
ImageButton::set_images("ic-link","ic-link_copy");
|
||||
else
|
||||
ImageButton::set_images("ic-link_copy","ic-link");
|
||||
}
|
||||
|
||||
void LevelmodeButton::on_action(Widget *)
|
||||
{
|
||||
mode = !mode;
|
||||
update();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void LevelmodeButton::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
update();
|
||||
ImageButton::draw(gc, r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LevelPackConfig::LevelPackConfig(std::string indexName, std::string groupName,
|
||||
bool forceGroupReasign) : isReasignOnly (forceGroupReasign),
|
||||
undo_quit (false), didEditMetaData (false), titleTF (NULL) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
if (indexName.empty())
|
||||
// new levelpack
|
||||
packIndex = new lev::PersistentIndex(" ", false,
|
||||
INDEX_DEFAULT_PACK_LOCATION, "",
|
||||
INDEX_STD_FILENAME, lev::Index::getCurrentGroup()); // mark as incomplete
|
||||
else
|
||||
packIndex = lev::Index::findIndex(indexName);
|
||||
ASSERT (packIndex != NULL, XFrontend, "not existing index Name");
|
||||
persIndex = dynamic_cast<lev::PersistentIndex *>(packIndex);
|
||||
isPersistent = (persIndex != NULL);
|
||||
isEditable = isPersistent ? persIndex->isUserEditable() : false;
|
||||
|
||||
// build a list of allowed group
|
||||
std::vector<std::string> groups = lev::Index::getGroupNames();
|
||||
// eliminate pseudo group "All Packs"
|
||||
std::vector<std::string>::iterator itg = groups.begin();
|
||||
while (itg != groups.end()) {
|
||||
if (*itg == INDEX_ALL_PACKS) {
|
||||
itg = groups.erase(itg);
|
||||
break;
|
||||
}
|
||||
if (itg != groups.end())
|
||||
itg++;
|
||||
}
|
||||
// add pseudo group "[Every Group]"
|
||||
groups.push_back(std::string("[") + INDEX_EVERY_GROUP +"]");
|
||||
intialGroupPosition = groups.size() - 1; // INDEX_EVERY_GROUP as default
|
||||
// mark index's default group with square brackets and find current group
|
||||
bool defaultGroupFound = false;
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (groups[i] == packIndex->getGroupName()) {
|
||||
intialGroupPosition = i;
|
||||
}
|
||||
if (groups[i] == packIndex->getDefaultGroupName()) {
|
||||
groups[i] = std::string("[") + groups[i] +"]";
|
||||
defaultGroupFound = true;
|
||||
}
|
||||
}
|
||||
if (!defaultGroupFound) {
|
||||
groups.push_back(std::string("[") + packIndex->getDefaultGroupName() +"]");
|
||||
}
|
||||
groupButton = new GroupButton(groups, intialGroupPosition);
|
||||
|
||||
// index location list setup
|
||||
std::vector<lev::Index *> * allIndices = lev::Index::getGroup(INDEX_ALL_PACKS);
|
||||
for (int i = 0; i < allIndices->size(); i++)
|
||||
locationList.push_back((*allIndices)[i]->getName());
|
||||
position = -1;
|
||||
for (int i = 0; i < locationList.size(); i++) {
|
||||
if (locationList[i] == indexName) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
oldPosition = position;
|
||||
if (position < 0) {
|
||||
// append new levelpack as last
|
||||
locationList.push_back(indexName);
|
||||
position = locationList.size() - 1;
|
||||
}
|
||||
|
||||
VList * titleLeftVList = new VList;
|
||||
titleLeftVList->set_spacing(11);
|
||||
titleLeftVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
titleLeftVList->set_default_size(140, 35);
|
||||
Label * titleLabel = new Label(N_("Levelpack:"), HALIGN_RIGHT);
|
||||
Label * ownerLabel = new Label(N_("Owner:"), HALIGN_RIGHT);
|
||||
Label * groupLabel = new Label(N_("Group:"), HALIGN_RIGHT);
|
||||
Label * loactionLabel1 = new Label(N_("Location"), HALIGN_LEFT);
|
||||
Label * loactionLabel2 = new Label(N_("in [All Packs]:"), HALIGN_RIGHT);
|
||||
titleLeftVList->add_back(titleLabel);
|
||||
if (!isReasignOnly) {
|
||||
titleLeftVList->add_back(ownerLabel);
|
||||
}
|
||||
titleLeftVList->add_back(groupLabel);
|
||||
if (!isReasignOnly) {
|
||||
titleLeftVList->add_back(new Label());
|
||||
titleLeftVList->add_back(loactionLabel1);
|
||||
titleLeftVList->add_back(loactionLabel2);
|
||||
titleLeftVList->add_back(new Label());
|
||||
titleLeftVList->add_back(new Label());
|
||||
}
|
||||
|
||||
valueLeftVList = new VList;
|
||||
valueLeftVList->set_spacing(11);
|
||||
valueLeftVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
valueLeftVList->set_default_size(160, 35);
|
||||
|
||||
titleValueLabel = new UntranslatedLabel(indexName, HALIGN_CENTER);
|
||||
ownerValueLabel = new UntranslatedLabel(isPersistent ? persIndex->getOwner() : "System");
|
||||
|
||||
pre2Index = new UntranslatedLabel();
|
||||
pre1Index = new UntranslatedLabel();
|
||||
thisIndex = new UntranslatedLabel();
|
||||
post1Index = new UntranslatedLabel();
|
||||
post2Index = new UntranslatedLabel();
|
||||
|
||||
valueLeftVList->add_back(titleValueLabel);
|
||||
if (!isReasignOnly) {
|
||||
valueLeftVList->add_back(ownerValueLabel);
|
||||
}
|
||||
valueLeftVList->add_back(groupButton);
|
||||
if (!isReasignOnly) {
|
||||
valueLeftVList->add_back(pre2Index);
|
||||
valueLeftVList->add_back(pre1Index);
|
||||
valueLeftVList->add_back(thisIndex);
|
||||
valueLeftVList->add_back(post1Index);
|
||||
valueLeftVList->add_back(post2Index);
|
||||
}
|
||||
|
||||
VList * scrollVList = new VList;
|
||||
scrollVList->set_spacing(12);
|
||||
scrollVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
scrollVList->set_default_size(30, 35);
|
||||
|
||||
scrollUp = new ImageButton("ic-up", "ic-up1", this);
|
||||
scrollDown = new ImageButton("ic-down", "ic-down1", this);
|
||||
scrollVList->add_back(scrollUp);
|
||||
scrollVList->add_back(scrollDown);
|
||||
|
||||
VList * metaVList = new VList;
|
||||
metaVList->set_spacing(12);
|
||||
metaVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
metaVList->set_default_size(140, 35);
|
||||
|
||||
if (isEditable)
|
||||
but_metadata = new StaticTextButton(N_("Edit Metadata"), this);
|
||||
else
|
||||
but_metadata = new Label();
|
||||
Label * releaseLabel = new Label(N_("Release:"), HALIGN_RIGHT);
|
||||
Label * revisionLabel = new Label(N_("Revision:"), HALIGN_RIGHT);
|
||||
Label * compatibilityLabel = new Label(N_("Compatibility:"), HALIGN_RIGHT);
|
||||
Label * defLocationLabel = new Label(N_("Default Location:"), HALIGN_RIGHT);
|
||||
Label * crossmodeLabel = new Label(N_("Level types:"), HALIGN_RIGHT);
|
||||
|
||||
if (!isReasignOnly) {
|
||||
metaVList->add_back(but_metadata);
|
||||
metaVList->add_back(new Label());
|
||||
if (WizardMode) {
|
||||
metaVList->add_back(releaseLabel);
|
||||
metaVList->add_back(revisionLabel);
|
||||
} else {
|
||||
metaVList->add_back(new Label());
|
||||
metaVList->add_back(new Label());
|
||||
}
|
||||
metaVList->add_back(crossmodeLabel);
|
||||
if (WizardMode) {
|
||||
metaVList->add_back(compatibilityLabel);
|
||||
} else {
|
||||
metaVList->add_back(new Label());
|
||||
}
|
||||
metaVList->add_back(defLocationLabel);
|
||||
metaVList->add_back(new Label());
|
||||
}
|
||||
|
||||
valueMetaVList = new VList;
|
||||
valueMetaVList->set_spacing(12);
|
||||
valueMetaVList->set_alignment(HALIGN_CENTER, VALIGN_CENTER);
|
||||
valueMetaVList->set_default_size(75, 35);
|
||||
Widget * levelmodeWidget;
|
||||
if (indexName.empty()){
|
||||
levelmode = new LevelmodeButton(false);
|
||||
levelmodeWidget = levelmode;
|
||||
} else {
|
||||
levelmodeWidget = new Image(isPersistent && !(persIndex->isCross()) ?
|
||||
"ic-link_copy" : "ic-link");
|
||||
}
|
||||
defLocationValueLabel = new Label(ecl::strf("%g", packIndex->getDefaultLocation()));
|
||||
releaseValueLabel = new Label(isPersistent ? ecl::strf("%d", persIndex->getRelease()) : "-");
|
||||
revisionValueLabel = new Label(isPersistent ? ecl::strf("%d", persIndex->getRevision()) : "-");
|
||||
compatibilityValueLabel = new Label(isPersistent ? ecl::strf("%.2f", persIndex->getCompatibility()) : "-");
|
||||
|
||||
if (!isReasignOnly) {
|
||||
valueMetaVList->add_back(new Label());
|
||||
valueMetaVList->add_back(new Label());
|
||||
if (WizardMode) {
|
||||
valueMetaVList->add_back(releaseValueLabel);
|
||||
valueMetaVList->add_back(revisionValueLabel);
|
||||
} else {
|
||||
valueMetaVList->add_back(new Label());
|
||||
valueMetaVList->add_back(new Label());
|
||||
}
|
||||
valueMetaVList->add_back(levelmodeWidget);
|
||||
if (WizardMode) {
|
||||
valueMetaVList->add_back(compatibilityValueLabel);
|
||||
} else {
|
||||
valueMetaVList->add_back(new Label());
|
||||
}
|
||||
valueMetaVList->add_back(defLocationValueLabel);
|
||||
valueMetaVList->add_back(new Label());
|
||||
}
|
||||
|
||||
|
||||
if (isReasignOnly) {
|
||||
this->add(titleLeftVList, Rect(vminfo.width/2 - 270, 15, 140, vminfo.height-97));
|
||||
this->add(valueLeftVList, Rect(vminfo.width/2 - 80, 15, 160, vminfo.height-97));
|
||||
} else {
|
||||
this->add(titleLeftVList, Rect(vminfo.width/2 - 300, 15, 140, vminfo.height-97));
|
||||
this->add(valueLeftVList, Rect(vminfo.width/2 - 140, 15, 160, vminfo.height-97));
|
||||
this->add(scrollVList, Rect(vminfo.width/2 + 30, 15+3*(35+12) + (vminfo.height-480)/2, 30, 5*35+4*12));
|
||||
this->add(metaVList, Rect(vminfo.width/2 + 80, 15, 140, vminfo.height-97));
|
||||
this->add(valueMetaVList, Rect(vminfo.width/2 + 235, 15, 75, vminfo.height-97));
|
||||
}
|
||||
|
||||
errorLabel = new Label("", HALIGN_CENTER);
|
||||
this->add(errorLabel, Rect(10, vminfo.height-97, vminfo.width-20, 35));
|
||||
|
||||
if (isReasignOnly)
|
||||
errorLabel->set_text(N_("Please reasign levelpack to another group for group deletion"));
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
but_edit = new StaticTextButton(N_("Compose Pack"), this);
|
||||
if (isPersistent && persIndex->isUpdatable() && persIndex->isCross()) {
|
||||
but_update = new StaticTextButton(N_("Update Pack"), this);
|
||||
} else {
|
||||
but_update = new Label();
|
||||
}
|
||||
but_ignore = new StaticTextButton(N_("Undo"), this);
|
||||
but_back = new StaticTextButton(N_("Ok"), this);
|
||||
|
||||
HList * commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
if (isReasignOnly) {
|
||||
commandHList->add_back(new Label());
|
||||
commandHList->add_back(new Label());
|
||||
} else {
|
||||
commandHList->add_back(but_edit);
|
||||
commandHList->add_back(but_update);
|
||||
}
|
||||
commandHList->add_back(but_ignore);
|
||||
commandHList->add_back(but_back);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
|
||||
updateLocationList();
|
||||
if (indexName.empty())
|
||||
// new levelpack
|
||||
switchToMetadataEdit();
|
||||
}
|
||||
|
||||
void LevelPackConfig::updateLocationList() {
|
||||
pre2Index->set_text((position > 1) ? locationList[position - 2] : "");
|
||||
pre1Index->set_text((position > 0) ? locationList[position - 1] : "");
|
||||
thisIndex->set_text(didEditMetaData ? titleTF->getText() : packIndex->getName());
|
||||
post1Index->set_text((position < locationList.size() - 1) ? locationList[position + 1] : "");
|
||||
post2Index->set_text((position < locationList.size() - 2) ? locationList[position + 2] : "");
|
||||
}
|
||||
|
||||
void LevelPackConfig::switchToMetadataEdit() {
|
||||
if (!didEditMetaData) {
|
||||
didEditMetaData = true;
|
||||
titleTF = new TextField(titleValueLabel->getText(), this);
|
||||
valueLeftVList->exchange_child(titleValueLabel, titleTF);
|
||||
delete titleValueLabel;
|
||||
ownerTF = new TextField(ownerValueLabel->getText());
|
||||
valueLeftVList->exchange_child(ownerValueLabel, ownerTF);
|
||||
delete ownerValueLabel;
|
||||
defLocationTF = new TextField(defLocationValueLabel->getText());
|
||||
valueMetaVList->exchange_child(defLocationValueLabel, defLocationTF);
|
||||
delete defLocationValueLabel;
|
||||
if (WizardMode) {
|
||||
releaseTF = new TextField(releaseValueLabel->getText());
|
||||
valueMetaVList->exchange_child(releaseValueLabel, releaseTF);
|
||||
delete releaseValueLabel;
|
||||
revisionTF = new TextField(revisionValueLabel->getText());
|
||||
valueMetaVList->exchange_child(revisionValueLabel, revisionTF);
|
||||
delete revisionValueLabel;
|
||||
compatibilityTF = new TextField(compatibilityValueLabel->getText());
|
||||
valueMetaVList->exchange_child(compatibilityValueLabel, compatibilityTF);
|
||||
delete compatibilityValueLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelPackConfig::isUndoQuit() {
|
||||
return undo_quit;
|
||||
}
|
||||
|
||||
bool LevelPackConfig::doChanges() {
|
||||
// change metadata
|
||||
if (didEditMetaData) {
|
||||
// the Index is persistent, user editabel and the user did switch to edit mode
|
||||
bool needSave = false;
|
||||
bool isNewIndex = persIndex->getName().empty();
|
||||
|
||||
// check for valid input
|
||||
// title
|
||||
std::string newtitle = titleTF->getText();
|
||||
std::string::size_type lastChar = newtitle.find_last_not_of(" ");
|
||||
if (lastChar == std::string::npos) {
|
||||
// the title is effectively an empty string
|
||||
errorLabel->set_text(N_("Error: empty title not allowed - press \"Undo\" to exit without modifications"));
|
||||
return false;
|
||||
}
|
||||
// strip off trailing and leading spaces
|
||||
newtitle = newtitle.substr(0 , lastChar + 1);
|
||||
newtitle = newtitle.substr(newtitle.find_first_not_of(" "));
|
||||
if (newtitle != persIndex->getName()) {
|
||||
if (isNewIndex) {
|
||||
// check for filename usability of title
|
||||
const std::string validChars("_- .#0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
if (newtitle.find_first_not_of(validChars, 0) != std::string::npos ||
|
||||
(newtitle.length() >= 1 && newtitle[0] == '.')) {
|
||||
errorLabel->set_text(N_("Error: use only \"a-zA-Z0-9 _-#\" for levelpack title"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// set packPath to cross if link only
|
||||
if (levelmode->isLinkOnly())
|
||||
persIndex->markNewAsCross();
|
||||
}
|
||||
if (!persIndex->setName(newtitle)) {
|
||||
errorLabel->set_text(N_("Error: title already in use - choose another title"));
|
||||
return false;
|
||||
}
|
||||
needSave = true;
|
||||
}
|
||||
|
||||
// check rest for need of save
|
||||
if (ownerTF->getText() != persIndex->getOwner()) {
|
||||
persIndex->setOwner(ownerTF->getText());
|
||||
needSave = true;
|
||||
}
|
||||
if (defLocationTF->getText() != ecl::strf("%g", packIndex->getDefaultLocation())) {
|
||||
double d = 0;
|
||||
// check value - keep old value on error
|
||||
if ((sscanf(defLocationTF->getText().c_str(),"%lg", &d) == 1) &&
|
||||
d > 0) {
|
||||
packIndex->setDefaultLocation(d);
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (WizardMode) {
|
||||
if (releaseTF->getText() != ecl::strf("%d", persIndex->getRelease())) {
|
||||
int i = 0;
|
||||
// check value - keep old value on error
|
||||
if ((sscanf(releaseTF->getText().c_str(),"%d", &i) == 1) &&
|
||||
i > 0) {
|
||||
persIndex->setRelease(i);
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
if (revisionTF->getText() != ecl::strf("%d", persIndex->getRevision())) {
|
||||
int i = 0;
|
||||
// check value - keep old value on error
|
||||
if ((sscanf(revisionTF->getText().c_str(),"%d", &i) == 1) &&
|
||||
i > 0) {
|
||||
persIndex->setRevision(i);
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
if (compatibilityTF->getText() != ecl::strf("%.2f", persIndex->getCompatibility())) {
|
||||
double d = 0;
|
||||
// check value - keep old value on error
|
||||
if ((sscanf(compatibilityTF->getText().c_str(),"%lg", &d) == 1) &&
|
||||
d >= 1) {
|
||||
persIndex->setCompatibility(d);
|
||||
needSave = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save
|
||||
if (needSave)
|
||||
persIndex->save();
|
||||
if (isNewIndex) {
|
||||
lev::Index::registerIndex(persIndex);
|
||||
lev::Index::setCurrentIndex(persIndex->getName());
|
||||
}
|
||||
}
|
||||
// regroup
|
||||
if (groupButton->get_value() != intialGroupPosition) {
|
||||
std::string newGroupName = groupButton->get_text(groupButton->get_value());
|
||||
// strip off square brackets used to mark default and pseudo groups
|
||||
if (newGroupName.size() > 2 && newGroupName[0] == '[' &&
|
||||
newGroupName[newGroupName.size() -1] == ']') {
|
||||
newGroupName = newGroupName.substr(1, newGroupName.size() - 2);
|
||||
}
|
||||
packIndex->moveToGroup(newGroupName);
|
||||
} else if (isReasignOnly) {
|
||||
// the user did not reasign - take as an undo request
|
||||
undo_quit = true;
|
||||
}
|
||||
// relocate
|
||||
if (position != oldPosition)
|
||||
packIndex->locateBehind(position > 0 ? locationList[position - 1] : "");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LevelPackConfig::on_action(Widget *w) {
|
||||
if (w == but_back) {
|
||||
if (doChanges())
|
||||
Menu::quit();
|
||||
else
|
||||
invalidate_all();
|
||||
} else if (w == but_ignore) {
|
||||
if (packIndex->getName().empty()) {
|
||||
delete packIndex;
|
||||
}
|
||||
undo_quit = true;
|
||||
Menu::quit();
|
||||
} else if (w == but_update) {
|
||||
if (isPersistent && doChanges()) {
|
||||
persIndex->load(false, true);
|
||||
persIndex->save(true);
|
||||
Menu::quit();
|
||||
}
|
||||
invalidate_all();
|
||||
} else if (w == but_edit) {
|
||||
if (doChanges()) {
|
||||
LevelPackComposer m(isEditable);
|
||||
m.manage();
|
||||
Menu::quit();
|
||||
} else {
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == scrollUp) {
|
||||
if (position > 0) {
|
||||
std::string tmp = locationList[position];
|
||||
locationList[position] = locationList[position - 1];
|
||||
locationList[position - 1] = tmp;
|
||||
position--;
|
||||
updateLocationList();
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == scrollDown) {
|
||||
if (position < locationList.size() - 1) {
|
||||
std::string tmp = locationList[position];
|
||||
locationList[position] = locationList[position + 1];
|
||||
locationList[position + 1] = tmp;
|
||||
position++;
|
||||
updateLocationList();
|
||||
invalidate_all();
|
||||
}
|
||||
} else if (w == but_metadata && !didEditMetaData) {
|
||||
switchToMetadataEdit();
|
||||
invalidate_all();
|
||||
} else if (w == titleTF && w != NULL) {
|
||||
thisIndex->set_text(titleTF->getText());
|
||||
}
|
||||
}
|
||||
|
||||
void LevelPackConfig::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Level Pack Configuration"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
|
||||
}} // namespace enigma::gui
|
||||
112
project/jni/application/enigma/src/gui/LevelPackConfig.hh
Normal file
112
project/jni/application/enigma/src/gui/LevelPackConfig.hh
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GUI_LEVELPACKCONFIG_HH_INCLUDED
|
||||
#define GUI_LEVELPACKCONFIG_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/PersistentIndex.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
class GroupButton : public ValueButton {
|
||||
public:
|
||||
GroupButton(std::vector<std::string> groups, int pos);
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
private:
|
||||
std::vector<std::string> groupNames;
|
||||
int position;
|
||||
};
|
||||
|
||||
class LevelmodeButton : public ImageButton {
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *);
|
||||
public:
|
||||
LevelmodeButton(bool initialMode = false);
|
||||
bool isLinkOnly();
|
||||
virtual void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
void update();
|
||||
bool mode;
|
||||
};
|
||||
|
||||
|
||||
class LevelPackConfig : public gui::Menu {
|
||||
public:
|
||||
LevelPackConfig (std::string indexName, std::string groupName = "",
|
||||
bool forceGroupReasign = false);
|
||||
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
bool isUndoQuit();
|
||||
private:
|
||||
void updateLocationList();
|
||||
void switchToMetadataEdit();
|
||||
bool doChanges();
|
||||
|
||||
lev::Index *packIndex;
|
||||
lev::PersistentIndex *persIndex;
|
||||
bool isPersistent;
|
||||
bool isEditable;
|
||||
TextField *tf_packName;
|
||||
GroupButton *groupButton;
|
||||
int intialGroupPosition;
|
||||
VList *valueLeftVList;
|
||||
Label *titleValueLabel;
|
||||
TextField *titleTF;
|
||||
Label *ownerValueLabel;
|
||||
TextField *ownerTF;
|
||||
VList *valueMetaVList;
|
||||
LevelmodeButton *levelmode;
|
||||
Label *defLocationValueLabel;
|
||||
TextField *defLocationTF;
|
||||
Label *releaseValueLabel;
|
||||
TextField *releaseTF;
|
||||
Label *revisionValueLabel;
|
||||
TextField *revisionTF;
|
||||
Label *compatibilityValueLabel;
|
||||
TextField *compatibilityTF;
|
||||
Label *pre2Index;
|
||||
Label *pre1Index;
|
||||
Label *thisIndex;
|
||||
Label *post1Index;
|
||||
Label *post2Index;
|
||||
Widget *scrollUp;
|
||||
Widget *scrollDown;
|
||||
Label *errorLabel;
|
||||
Widget *but_metadata;
|
||||
Widget *but_up;
|
||||
Widget *but_down;
|
||||
Widget *but_edit;
|
||||
Widget *but_update;
|
||||
Widget *but_ignore;
|
||||
Widget *but_back;
|
||||
bool isReasignOnly;
|
||||
bool didEditMetaData;
|
||||
bool undo_quit;
|
||||
std::vector<std::string> locationList;
|
||||
int position; // new position of index in locationList that the user selected
|
||||
int oldPosition; // position of index when entering menu, -1 for new index
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
506
project/jni/application/enigma/src/gui/LevelPackMenu.cpp
Normal file
506
project/jni/application/enigma/src/gui/LevelPackMenu.cpp
Normal file
@@ -0,0 +1,506 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck, Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/LevelPackMenu.hh"
|
||||
#include "gui/LevelMenu.hh"
|
||||
#include "gui/LPGroupConfig.hh"
|
||||
#include "gui/LevelPackConfig.hh"
|
||||
#include "gui/SearchMenu.hh"
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "errors.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/PersistentIndex.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Level Pack Menu -------------------- */
|
||||
std::map<std::string, std::string> LevelPackMenu::groupLastSelectedIndex;
|
||||
std::map<std::string, int> LevelPackMenu::groupLastSelectedColumn;
|
||||
std::string LevelPackMenu::lastGroupName;
|
||||
int LevelPackMenu::firstDisplayedGroup = 0;
|
||||
|
||||
static const char *helptext[] = {
|
||||
N_("Left column:"), N_("Levelpack groups"),
|
||||
N_("Right columns:"), N_("Levelpacks of selected group"),
|
||||
N_("Left click:"), N_("Select group or levelpack"),
|
||||
N_("Right or control click:"), N_("Configure group or levelpack"),
|
||||
0
|
||||
};
|
||||
|
||||
LevelPackMenu::LevelPackMenu() : packsHList (NULL), groupsVList (NULL),
|
||||
scrollLeft (NULL), scrollRight (NULL), scrollUp (NULL),
|
||||
scrollDown (NULL), isLevelMenuSubmenu (false) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
vm = vminfo.videomode;
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
but_new = new StaticTextButton(N_("New Group"), this);
|
||||
but_search = new StaticTextButton(N_("Search"), this);
|
||||
but_level = new StaticTextButton(N_("Start Game"), this);
|
||||
but_main = new StaticTextButton(N_("Main Menu"), this);
|
||||
|
||||
commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
commandHList->add_back(but_new);
|
||||
commandHList->add_back(but_search);
|
||||
commandHList->add_back(but_level);
|
||||
commandHList->add_back(but_main);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
|
||||
}
|
||||
|
||||
void LevelPackMenu::setupMenu() {
|
||||
static struct SpacingConfig {
|
||||
int packcolumns, rows;
|
||||
int vmargin, vrow_row;
|
||||
int hmargin, hgroup_pack, hscrollbutton, hscroll_pack, hpack_pack;
|
||||
} param[video::VM_COUNT] = {
|
||||
{ // VM_640x480
|
||||
2, 9,
|
||||
15, 10,
|
||||
20, 36, 22, 10, 20
|
||||
},
|
||||
{ // VM_640x512
|
||||
2, 9,
|
||||
15, 10,
|
||||
20, 36, 22, 10, 20
|
||||
},
|
||||
{ // VM_800x600
|
||||
3, 11,
|
||||
15, 13,
|
||||
15, 36, 22, 10, 15
|
||||
},
|
||||
{ // VM_1024x768
|
||||
4, 15,
|
||||
15, 10,
|
||||
30, 36, 22, 12, 20
|
||||
}
|
||||
};
|
||||
|
||||
if (groupsVList != NULL) {
|
||||
groupsVList->clear();
|
||||
remove_child(groupsVList);
|
||||
delete groupsVList;
|
||||
groupsVList = NULL;
|
||||
scrollUp = NULL; // deleted with groupsVList
|
||||
scrollDown = NULL; // deleted with groupsVList
|
||||
}
|
||||
|
||||
if (packsHList != NULL) {
|
||||
packsHList->clear();
|
||||
remove_child(packsHList);
|
||||
delete packsHList;
|
||||
packsHList = NULL;
|
||||
}
|
||||
|
||||
if (scrollLeft != NULL) {
|
||||
remove_child(scrollLeft);
|
||||
delete scrollLeft;
|
||||
scrollLeft = NULL;
|
||||
}
|
||||
if (scrollRight != NULL) {
|
||||
remove_child(scrollRight);
|
||||
delete scrollRight;
|
||||
scrollRight = NULL;
|
||||
}
|
||||
|
||||
packButtons.clear();
|
||||
groupButtons.clear();
|
||||
|
||||
std::vector<std::string> groupNames = lev::Index::getGroupNames();
|
||||
int groupCount = groupNames.size();
|
||||
std::string curGroupName = lev::Index::getCurrentGroup();
|
||||
bool needUpScroll = false;
|
||||
bool needDownScroll = false;
|
||||
int numDisplayGroups = param[vm].rows;
|
||||
int usedGroupRows = (groupCount > numDisplayGroups) ? numDisplayGroups : groupCount;
|
||||
|
||||
// correct scroll attempts and screen resolution changes
|
||||
firstDisplayedGroup = ecl::Clamp<int>(firstDisplayedGroup, 0,
|
||||
(groupCount > numDisplayGroups) ? groupCount - numDisplayGroups : 0);
|
||||
needUpScroll = firstDisplayedGroup > 0;
|
||||
needDownScroll = firstDisplayedGroup < groupCount - numDisplayGroups;
|
||||
if (curGroupName != lastGroupName) {
|
||||
// group changed by indirect user action - ensure it is visible
|
||||
int curGroupPos = getGroupPosition(&groupNames, curGroupName);
|
||||
if (curGroupPos != -1) {
|
||||
if (curGroupPos <= firstDisplayedGroup ) {
|
||||
if (curGroupPos <= 1) {
|
||||
needUpScroll = false;
|
||||
firstDisplayedGroup = 0;
|
||||
} else {
|
||||
needUpScroll = true;
|
||||
firstDisplayedGroup = curGroupPos -1;
|
||||
}
|
||||
needDownScroll = firstDisplayedGroup < groupCount - numDisplayGroups;
|
||||
} else if (curGroupPos >= firstDisplayedGroup + numDisplayGroups - 1) {
|
||||
if (curGroupPos >= groupCount - 2) {
|
||||
needDownScroll = false;
|
||||
firstDisplayedGroup = groupCount - numDisplayGroups;
|
||||
} else {
|
||||
needDownScroll = true;
|
||||
firstDisplayedGroup = curGroupPos - numDisplayGroups + 2;
|
||||
}
|
||||
if (firstDisplayedGroup < 0)
|
||||
firstDisplayedGroup = 0;
|
||||
needUpScroll = firstDisplayedGroup > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
groupsVList = new VList;
|
||||
groupsVList->set_spacing(param[vm].vrow_row);
|
||||
groupsVList->set_alignment(HALIGN_LEFT, VALIGN_CENTER);
|
||||
groupsVList->set_default_size(160, 35);
|
||||
|
||||
for (int i = 0; i < usedGroupRows; i++) {
|
||||
if (i == 0 && needUpScroll) {
|
||||
scrollUp = new ImageButton("ic-up", "ic-up1", this);
|
||||
groupsVList->add_back(scrollUp);
|
||||
} else if (i == usedGroupRows -1 && needDownScroll) {
|
||||
scrollDown = new ImageButton("ic-down", "ic-down1", this);
|
||||
groupsVList->add_back(scrollDown);
|
||||
} else {
|
||||
TextButton * button = new UntranslatedStaticTextButton(
|
||||
groupNames[firstDisplayedGroup + i], this);;
|
||||
groupButtons.push_back(button);
|
||||
groupsVList->add_back(button);
|
||||
}
|
||||
}
|
||||
|
||||
this->add(groupsVList, Rect(param[vm].hmargin, param[vm].vmargin,
|
||||
160, param[vm].rows * 35 +
|
||||
(param[vm].rows - 1) * param[vm].vrow_row));
|
||||
|
||||
lastGroupName = curGroupName;
|
||||
std::vector<lev::Index *> * group = lev::Index::getGroup(curGroupName);
|
||||
ASSERT(group != NULL, XFrontend,"");
|
||||
unsigned packCount = group->size();
|
||||
|
||||
int posCurrentIndex = getIndexPosition(group, lev::Index::getCurrentIndex()->getName());
|
||||
int selectedColumn = lev::Index::getGroupSelectedColumn(curGroupName);
|
||||
int colCurrentIndex = 0;
|
||||
int nextPack = 0; // pack displayed at top of first display column
|
||||
|
||||
if (selectedColumn != INDEX_GROUP_COLUMN_UNKNOWN ||
|
||||
groupLastSelectedIndex.find(curGroupName) == groupLastSelectedIndex.end()) {
|
||||
colCurrentIndex = checkColumn(param[vm].rows, param[vm].packcolumns,
|
||||
packCount, posCurrentIndex, selectedColumn);
|
||||
nextPack = (posCurrentIndex / param[vm].rows - colCurrentIndex) * param[vm].rows;
|
||||
} else {
|
||||
// the user selected a new level pack and the column was not yet
|
||||
// calculated: we try to keep the display unchanged in respect of
|
||||
// of the last selected pack and if necessary scroll minimum amount
|
||||
// of columns
|
||||
int posLastIndex = getIndexPosition(group,groupLastSelectedIndex[curGroupName]);
|
||||
int colLastIndex = checkColumn(param[vm].rows, param[vm].packcolumns,
|
||||
packCount, posLastIndex, groupLastSelectedColumn[curGroupName]);
|
||||
nextPack = (posLastIndex / param[vm].rows - colLastIndex) * param[vm].rows;
|
||||
if (posCurrentIndex < nextPack) {
|
||||
// current index would be left of display - we need to scroll left
|
||||
nextPack -= (((nextPack - posCurrentIndex - 1)/param[vm].rows) + 1) *
|
||||
param[vm].rows;
|
||||
colCurrentIndex = 0;
|
||||
} else if (posCurrentIndex < nextPack + param[vm].rows * param[vm].packcolumns) {
|
||||
// current index is still visible - keep nextPack
|
||||
colCurrentIndex = (posCurrentIndex - nextPack) / param[vm].rows;
|
||||
} else {
|
||||
// current index would be right of display - we need to scroll right
|
||||
nextPack += (((posCurrentIndex - nextPack)/param[vm].rows) -
|
||||
(param[vm].packcolumns - 1)) * param[vm].rows;
|
||||
colCurrentIndex = param[vm].packcolumns - 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool needRightScroll = packCount > nextPack + param[vm].rows * param[vm].packcolumns;
|
||||
bool needLeftScroll = nextPack > 0;
|
||||
|
||||
lev::Index::setGroupSelectedColumn(curGroupName, colCurrentIndex);
|
||||
groupLastSelectedIndex[curGroupName] = lev::Index::getCurrentIndex()->getName();
|
||||
groupLastSelectedColumn[curGroupName] = colCurrentIndex;
|
||||
|
||||
packsHList = new HList;
|
||||
packsHList->set_spacing(param[vm].hpack_pack);
|
||||
packsHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
packsHList->set_default_size(160, param[vm].rows*35 +
|
||||
(param[vm].rows - 1) * param[vm].vrow_row);
|
||||
|
||||
for (int col = 0; col < param[vm].packcolumns; col++) {
|
||||
if (packCount - nextPack > 0) {
|
||||
VList * pl = new VList;
|
||||
pl->set_spacing (param[vm].vrow_row);
|
||||
// first column is centered - if it is full it is like top alignment:
|
||||
pl->set_alignment (HALIGN_LEFT, col == 0 ? VALIGN_CENTER : VALIGN_TOP);
|
||||
pl->set_default_size (160, 35);
|
||||
for (int row = 0; row < param[vm].rows; row++) {
|
||||
if (nextPack < packCount) {
|
||||
lev::Index *ind = (*group)[nextPack];
|
||||
TextButton * button = new UntranslatedStaticTextButton(ind->getName(), this);
|
||||
packButtons.push_back(button);
|
||||
pl->add_back(button);
|
||||
nextPack++;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
packsHList->add_back(pl);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
this->add(packsHList, Rect(param[vm].hmargin + 160 + param[vm].hgroup_pack +
|
||||
param[vm].hscrollbutton + param[vm].hscroll_pack,
|
||||
param[vm].vmargin,
|
||||
param[vm].packcolumns * 160 + (param[vm].packcolumns - 1) *
|
||||
param[vm].hpack_pack,
|
||||
param[vm].rows * 35 +
|
||||
(param[vm].rows - 1) * param[vm].vrow_row));
|
||||
|
||||
if (needLeftScroll) {
|
||||
scrollLeft = new ImageButton("ic-left", "ic-left1", this);
|
||||
this->add(scrollLeft, Rect(param[vm].hmargin + 160 + param[vm].hgroup_pack,
|
||||
param[vm].vmargin + param[vm].rows / 2 * (35 + param[vm].vrow_row),
|
||||
param[vm].hscrollbutton, 35));
|
||||
}
|
||||
|
||||
if (needRightScroll) {
|
||||
scrollRight = new ImageButton("ic-right", "ic-right1", this);
|
||||
this->add(scrollRight, Rect(param[vm].hmargin + 160 + param[vm].hgroup_pack +
|
||||
param[vm].hscrollbutton + 2 * param[vm].hscroll_pack +
|
||||
param[vm].packcolumns * 160 + (param[vm].packcolumns - 1) *
|
||||
param[vm].hpack_pack,
|
||||
param[vm].vmargin + param[vm].rows / 2 * (35 + param[vm].vrow_row),
|
||||
param[vm].hscrollbutton, 35));
|
||||
}
|
||||
}
|
||||
|
||||
void LevelPackMenu::manageLevelMenu() {
|
||||
bool finished = false;
|
||||
while (!finished) {
|
||||
{
|
||||
LevelMenu m;
|
||||
if (!m.manage() || m.isMainQuit()) {
|
||||
// ESC or Main button has been pressed in LevelMenu -
|
||||
// the user wants to return
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
if (!finished) {
|
||||
// the user left LevelMenu via LevelPack button
|
||||
this->isLevelMenuSubmenu = true;
|
||||
if (this->manage()) {
|
||||
// not ESC - the user pressed Main button
|
||||
finished = true;
|
||||
} else {
|
||||
// the user pressed ESC - return to LevelMenu
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelPackMenu::manage() {
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
return Menu::manage();
|
||||
}
|
||||
|
||||
bool LevelPackMenu::on_event (const SDL_Event &e) {
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
SDLKey keysym = e.key.keysym.sym;
|
||||
switch (keysym) {
|
||||
case SDLK_F1:
|
||||
displayHelp(helptext, 200);
|
||||
invalidate_all();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LevelPackMenu::on_action(Widget *w) {
|
||||
if (w == but_main) {
|
||||
Menu::quit();
|
||||
} else if (w == but_new) {
|
||||
LPGroupConfig m("");
|
||||
m.manage();
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} else if (w == but_level) {
|
||||
LevelMenu m;
|
||||
if (!m.manage() && isLevelMenuSubmenu || m.isMainQuit()) {
|
||||
// ESC in LevelMenu in case we are a submenu of LevelMenu or
|
||||
// Main button has been pressed in LevelMenu
|
||||
Menu::quit();
|
||||
}
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} else if (w == but_search) {
|
||||
SearchMenu ml;
|
||||
ml.manage();
|
||||
if (ml.isSearchQuit()) {
|
||||
// show search result levelpack
|
||||
LevelMenu ml;
|
||||
if (!ml.manage() && isLevelMenuSubmenu || ml.isMainQuit()) {
|
||||
// ESC in LevelMenu in cade we are a submenu of LevelMenu or
|
||||
// Main button has been pressed in LevelMenu
|
||||
Menu::quit();
|
||||
}
|
||||
}
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} else if (w == scrollUp) {
|
||||
firstDisplayedGroup--;
|
||||
reset_active_widget(); // we will delete it with setup
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} else if (w == scrollDown) {
|
||||
firstDisplayedGroup++;
|
||||
reset_active_widget(); // we will delete it with setup
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} else if (w->get_parent() == groupsVList){
|
||||
lev::Index::setCurrentGroup(dynamic_cast<TextButton *>(w)->get_text());
|
||||
if ((w->lastMouseButton() == SDL_BUTTON_RIGHT ||
|
||||
w->lastModifierKeys() & KMOD_CTRL) &&
|
||||
dynamic_cast<TextButton *>(w)->get_text() != INDEX_ALL_PACKS) {
|
||||
// configure group
|
||||
// INDEX_ALL_PACKS cannot be renamed, deleted, no packs can be created
|
||||
LPGroupConfig m(dynamic_cast<TextButton *>(w)->get_text());
|
||||
m.manage();
|
||||
lastGroupName = ""; // the group may have moved, force a recalc
|
||||
}
|
||||
reset_active_widget(); // we will delete it with setup
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} else if (w->get_parent()->get_parent() == packsHList){
|
||||
lev::Index::setCurrentIndex(dynamic_cast<TextButton *>(w)->get_text());
|
||||
if (w->lastMouseButton() == SDL_BUTTON_RIGHT ||
|
||||
w->lastModifierKeys() & KMOD_CTRL) {
|
||||
// configure levelpack index
|
||||
LevelPackConfig m(dynamic_cast<TextButton *>(w)->get_text());
|
||||
m.manage();
|
||||
} else {
|
||||
LevelMenu m;
|
||||
if (!m.manage() && isLevelMenuSubmenu || m.isMainQuit()) {
|
||||
// ESC in LevelMenu in case we are a submenu of LevelMenu or
|
||||
// Main button has been pressed in LevelMenu
|
||||
Menu::quit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
reset_active_widget(); // we will delete it with setup
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} else if (w == scrollLeft) {
|
||||
std::string curGroupName = lev::Index::getCurrentGroup();
|
||||
lev::Index::setGroupSelectedColumn(curGroupName,
|
||||
lev::Index::getGroupSelectedColumn(curGroupName) + 1);
|
||||
reset_active_widget(); // we will delete it with setup
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
} else if (w == scrollRight) {
|
||||
std::string curGroupName = lev::Index::getCurrentGroup();
|
||||
lev::Index::setGroupSelectedColumn(curGroupName,
|
||||
lev::Index::getGroupSelectedColumn(curGroupName) - 1);
|
||||
reset_active_widget(); // we will delete it with setup
|
||||
setupMenu();
|
||||
updateHighlight();
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
void LevelPackMenu::updateHighlight() {
|
||||
for (int i = 0; i < packButtons.size(); i++) {
|
||||
TextButton * button = packButtons[i];
|
||||
if (button->get_text() == lev::Index::getCurrentIndex()->getName())
|
||||
button->setHighlight(true);
|
||||
else
|
||||
button->setHighlight(false);
|
||||
}
|
||||
for (int i = 0; i < groupButtons.size(); i++) {
|
||||
TextButton * button = groupButtons[i];
|
||||
if (button->get_text() == lev::Index::getCurrentGroup())
|
||||
button->setHighlight(true);
|
||||
else
|
||||
button->setHighlight(false);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelPackMenu::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Level Pack Menu"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
int LevelPackMenu::getGroupPosition(std::vector<std::string> * groups, std::string groupName) {
|
||||
std::vector<std::string>::iterator it;
|
||||
int i = 0;
|
||||
for (it = groups->begin(); it != groups->end(); it++, i++) {
|
||||
if ((*it) == groupName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int LevelPackMenu::getIndexPosition(std::vector<lev::Index *> * group, std::string indexName) {
|
||||
std::vector<lev::Index *>::iterator it;
|
||||
int i = 0;
|
||||
for (it = group->begin(); it != group->end(); it++, i++) {
|
||||
if ((*it)->getName() == indexName) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int LevelPackMenu::checkColumn(int rows, int columns, int size,
|
||||
int position, int oldColumn) {
|
||||
int naturalColumn = position / rows;
|
||||
int numColumns = (size - 1) / rows + 1;
|
||||
if (oldColumn == INDEX_GROUP_COLUMN_UNKNOWN)
|
||||
return (naturalColumn > columns) ? columns - 1 : naturalColumn;
|
||||
else
|
||||
return ecl::Clamp<int>(oldColumn, naturalColumn -
|
||||
((numColumns > columns) ? (numColumns - columns) : 0),
|
||||
naturalColumn);
|
||||
}
|
||||
|
||||
|
||||
}} // namespace enigma::gui
|
||||
87
project/jni/application/enigma/src/gui/LevelPackMenu.hh
Normal file
87
project/jni/application/enigma/src/gui/LevelPackMenu.hh
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck, Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_LEVELPACKMENU_HH_INCLUDED
|
||||
#define GUI_LEVELPACKMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelPackMenu -------------------- */
|
||||
|
||||
/**
|
||||
* The levelpack selection menu.
|
||||
*
|
||||
* The used strategy for horizontal scrolling of the levelpack columns
|
||||
* is to avoid scrolling as long as the target levelpack is still visible.
|
||||
* The current levelpack may be scrolled out of visibility by using the
|
||||
* scoll buttons within this menu. But if the user changes the current
|
||||
* levelpack via indirect methods besides
|
||||
* using the levelpack menu, f.e. the jumpto command, we ensure that
|
||||
* the new current levelpack is visible when the menu is redisplayed.
|
||||
* If it is necessary to scroll we scroll only the minimum amount of columns
|
||||
* needed to display the current levelpack. Even on screen resolution changes
|
||||
* we try to keep the column of the current levelpack unchanged.
|
||||
*/
|
||||
class LevelPackMenu : public Menu {
|
||||
public:
|
||||
LevelPackMenu();
|
||||
void manageLevelMenu();
|
||||
virtual bool manage();
|
||||
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
|
||||
private:
|
||||
static std::map<std::string, std::string> groupLastSelectedIndex;
|
||||
static std::map<std::string, int> groupLastSelectedColumn;
|
||||
static std::string lastGroupName;
|
||||
static int firstDisplayedGroup;
|
||||
|
||||
video::VideoModes vm;
|
||||
std::vector<TextButton *> packButtons;
|
||||
std::vector<TextButton *> groupButtons;
|
||||
|
||||
HList *packsHList;
|
||||
ImageButton *scrollLeft;
|
||||
ImageButton *scrollRight;
|
||||
ImageButton *scrollUp;
|
||||
ImageButton *scrollDown;
|
||||
VList *groupsVList;
|
||||
HList *commandHList;
|
||||
Widget *but_search;
|
||||
Widget *but_new;
|
||||
Widget *but_level;
|
||||
Widget *but_main;
|
||||
|
||||
bool isLevelMenuSubmenu;
|
||||
|
||||
void setupMenu();
|
||||
void updateHighlight();
|
||||
int getGroupPosition(std::vector<std::string> * groups, std::string groupName);
|
||||
int getIndexPosition(std::vector<lev::Index *> * group, std::string indexName);
|
||||
int checkColumn(int rows, int columns, int size, int position, int oldColumn);
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
178
project/jni/application/enigma/src/gui/LevelPreviewCache.cpp
Normal file
178
project/jni/application/enigma/src/gui/LevelPreviewCache.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck, Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/LevelPreviewCache.hh"
|
||||
#include "ecl.hh"
|
||||
#include "file.hh"
|
||||
#include "game.hh"
|
||||
#include "main.hh"
|
||||
#include "video.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
#include "SDL.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelPreviewCache -------------------- */
|
||||
|
||||
LevelPreviewCache *LevelPreviewCache::theSingleton = 0;
|
||||
|
||||
LevelPreviewCache* LevelPreviewCache::instance() {
|
||||
if (theSingleton == 0) {
|
||||
theSingleton = new LevelPreviewCache();
|
||||
}
|
||||
return theSingleton;
|
||||
}
|
||||
|
||||
LevelPreviewCache::LevelPreviewCache() : cachedIndex (NULL) {
|
||||
}
|
||||
|
||||
void LevelPreviewCache::clear() {
|
||||
Log << "LevelPreviewCache clear\n";
|
||||
cache.clear();
|
||||
imgCache.clear();
|
||||
}
|
||||
|
||||
Surface *LevelPreviewCache::getPreview(lev::Proxy *levelProxy,
|
||||
bool allowGeneration, bool &didGenerate) {
|
||||
didGenerate = false;
|
||||
std::string mapIndex = levelProxy->getId() +
|
||||
ecl::strf("#%d", levelProxy->getReleaseVersion());
|
||||
// first look in cache
|
||||
PreviewMap::iterator i = cache.find(mapIndex);
|
||||
if (i != cache.end())
|
||||
return i->second;
|
||||
|
||||
// we have to cache a new preview - check if we should clear cache first
|
||||
if (cachedIndex == NULL) {
|
||||
// remember the index we are caching
|
||||
cachedIndex = lev::Index::getCurrentIndex();
|
||||
} else if (cachedIndex != lev::Index::getCurrentIndex()) {
|
||||
//the index changed - cache only previews from new index
|
||||
clear();
|
||||
cachedIndex = lev::Index::getCurrentIndex();
|
||||
}
|
||||
|
||||
std::string previewSubPath = makePreviewPath(levelProxy);
|
||||
Surface *surface = 0;
|
||||
|
||||
// load preview from file bundled with the level itself
|
||||
std::string absLevelPath ;
|
||||
std::auto_ptr<std::istream> isptr;
|
||||
ByteVec imageData;
|
||||
if(levelProxy->getNormPathType() == lev::Proxy::pt_resource &&
|
||||
app.resourceFS->findFile ("levels/" + levelProxy->getNormLevelPath() + ".png",
|
||||
absLevelPath, isptr)) {
|
||||
// load plain image file or zipped image
|
||||
if (isptr.get() != NULL) {
|
||||
// zipped file
|
||||
Readfile (*isptr, imageData);
|
||||
} else {
|
||||
// plain file
|
||||
basic_ifstream<char> ifs(absLevelPath.c_str(), ios::binary | ios::in);
|
||||
Readfile (ifs, imageData);
|
||||
}
|
||||
SDL_RWops *imageHandle = SDL_RWFromMem(&(imageData[0]), imageData.size());
|
||||
surface = ecl::LoadImage(imageHandle, 1);
|
||||
imgCache.store(previewSubPath, surface); // insert in imgCache
|
||||
}
|
||||
|
||||
// load preview from stored file if possible
|
||||
string previewFullPath;
|
||||
if (!surface && app.resourceFS->findFile(previewSubPath, previewFullPath))
|
||||
surface = imgCache.get(previewFullPath);
|
||||
|
||||
// generate new preview otherwise
|
||||
if (!surface && allowGeneration) {
|
||||
surface = newPreview(levelProxy);
|
||||
if (surface) {
|
||||
imgCache.store(previewSubPath, surface); // insert in imgCache
|
||||
savePreview(levelProxy, surface); // save on filesystem
|
||||
} else {
|
||||
surface = enigma::GetImage("error");
|
||||
}
|
||||
didGenerate = true;
|
||||
}
|
||||
|
||||
// update index
|
||||
if (surface)
|
||||
cache[mapIndex] = surface;
|
||||
return surface;
|
||||
}
|
||||
|
||||
ecl::Surface *LevelPreviewCache::newPreview (lev::Proxy *levelProxy) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
Surface *surface = 0;
|
||||
ecl::GC gc(video::BackBuffer());
|
||||
if (game::DrawLevelPreview (gc, levelProxy)) {
|
||||
surface = Resample (video::BackBuffer(),
|
||||
vminfo.gamearea, vminfo.thumbw, vminfo.thumbh);
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
Surface *LevelPreviewCache::updatePreview (lev::Proxy *levelProxy) {
|
||||
if (Surface *surface = newPreview (levelProxy)) {
|
||||
std::string idx = levelProxy->getId() +
|
||||
ecl::strf("#%d", levelProxy->getReleaseVersion());
|
||||
cache[idx] = surface;
|
||||
|
||||
string preview_name = makePreviewPath(levelProxy);
|
||||
imgCache.store (preview_name, surface); // insert in imgCache
|
||||
savePreview(levelProxy, surface); // save on filesystem
|
||||
return surface;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string LevelPreviewCache::makePreviewPath(lev::Proxy *levelProxy) {
|
||||
return "thumbs/" +
|
||||
levelProxy->getLocalSubstitutionLevelPath() +
|
||||
ecl::strf("#%d", levelProxy->getReleaseVersion()) + ".png";
|
||||
}
|
||||
|
||||
void LevelPreviewCache::savePreview(lev::Proxy *levelProxy, ecl::Surface *s) {
|
||||
std::string savePath = app.userImagePath + "/" + makePreviewPath(levelProxy);
|
||||
Log << "savePreview to " << savePath << "\n";
|
||||
// auto-create the directory if necessary
|
||||
string directory;
|
||||
if (ecl::split_path (savePath, &directory, 0) && !ecl::FolderExists(directory)) {
|
||||
ecl::FolderCreate (directory);
|
||||
}
|
||||
ecl::SavePNG(s, savePath);
|
||||
}
|
||||
|
||||
void LevelPreviewCache::makeSystemPreview(lev::Proxy *levelProxy, std::string systemDataPath) {
|
||||
std::string savePath = systemDataPath + "/levels/" + levelProxy->getNormLevelPath() + ".png";
|
||||
// auto-create the directory if necessary -- on an installed Enigma
|
||||
// distribution this is of course unnecessary, but you start Enigma
|
||||
// without prior installation. This is useful to get a directory with
|
||||
// just the previews.
|
||||
string directory;
|
||||
if (ecl::split_path (savePath, &directory, 0) && !ecl::FolderExists(directory)) {
|
||||
ecl::FolderCreate (directory);
|
||||
}
|
||||
ecl::Surface * s = newPreview(levelProxy);
|
||||
if (s != NULL)
|
||||
ecl::SavePNG(s, savePath);
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
91
project/jni/application/enigma/src/gui/LevelPreviewCache.hh
Normal file
91
project/jni/application/enigma/src/gui/LevelPreviewCache.hh
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_LEVELPREVIEWCACHE_HH_INCLUDED
|
||||
#define GUI_LEVELPREVIEWCACHE_HH_INCLUDED
|
||||
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include <map>
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/**
|
||||
* A singleton manager for level previews with autocaching.
|
||||
* Clients just need to know the level proxy to request a preview.
|
||||
* <p>
|
||||
* Previews will be loaded from levelpack bundles if provided. These
|
||||
* preview files have the same name as the levels themself but the
|
||||
* suffix ".png". They just sit aside the levels in the same directory
|
||||
* or in the same zip archive. Only local stored previews will be looked
|
||||
* for.<p>
|
||||
* If no bundled preview exists the preview will be loaded from prior
|
||||
* generated and saved instances. Previews will be looked up at the
|
||||
* resourceFS with play time generated previews stored at the userImagePath
|
||||
* and installation time generated previews at the system path. The previews
|
||||
* will be stored at "data/thumbs" with a subpath that reflectes the level
|
||||
* subpath with critical characters replaced for url and other special levels.
|
||||
* The level release number is attached to the previewname as "#n" to allow
|
||||
* different previews for different releases to exist in parallel.<p>
|
||||
*
|
||||
* If no stored preview exists a new one will be generated by loading the
|
||||
* level. The preview will be stored to the userImagePath for future use.<p>
|
||||
*
|
||||
* All loaded previews will be autocached. Futher requests will be served
|
||||
* by the cache. The cache will be autocleared when a change in the
|
||||
* current Index is detected.<p>
|
||||
*
|
||||
* TODO remove unused preview on filesystem
|
||||
* TODO autogenerate previews on install
|
||||
*/
|
||||
class LevelPreviewCache {
|
||||
public:
|
||||
static LevelPreviewCache *instance();
|
||||
static void makeSystemPreview(lev::Proxy *levelProxy, std::string systemDataPath);
|
||||
~LevelPreviewCache();
|
||||
|
||||
ecl::Surface *getPreview (lev::Proxy *levelProxy,
|
||||
bool allowGeneration, bool &didGenerate);
|
||||
ecl::Surface *updatePreview (lev::Proxy *levelProxy);
|
||||
void clear();
|
||||
protected:
|
||||
LevelPreviewCache();
|
||||
private:
|
||||
static LevelPreviewCache *theSingleton;
|
||||
|
||||
/**
|
||||
* A mapping of "levelId+levelRelease" to preview surfaces
|
||||
*/
|
||||
typedef std::map<std::string, ecl::Surface*> PreviewMap;
|
||||
|
||||
// ---------- Internal methods ----------
|
||||
|
||||
static ecl::Surface *newPreview (lev::Proxy *levelProxy);
|
||||
std::string makePreviewPath(lev::Proxy *levelProxy);
|
||||
void savePreview(lev::Proxy *levelProxy, ecl::Surface *s);
|
||||
|
||||
// ---------- Variables ----------
|
||||
|
||||
PreviewMap cache; // a second mapping to avoid searched on the filesystem
|
||||
enigma::ImageCache imgCache; // the owner of the preview surfaces -
|
||||
// cannot be used as mapping as this cache
|
||||
// uses the filepath as index and autoloads
|
||||
// files on "get"-access
|
||||
lev::Index *cachedIndex; // the index that is currently cached
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
489
project/jni/application/enigma/src/gui/LevelWidget.cpp
Normal file
489
project/jni/application/enigma/src/gui/LevelWidget.cpp
Normal file
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
* Copyright (C) 2006,2007 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/LevelWidget.hh"
|
||||
#include "gui/LevelMenu.hh"
|
||||
#include "gui/LevelInspector.hh"
|
||||
|
||||
#include "ecl.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "sound.hh"
|
||||
#include "StateManager.hh"
|
||||
#include "video.hh"
|
||||
#include "file.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include <cassert>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelWidget -------------------- */
|
||||
|
||||
LevelWidget::LevelWidget(bool withScoreIcons, bool withEditBorder) :
|
||||
displayScoreIcons (withScoreIcons), displayEditBorder (withEditBorder),
|
||||
width (0), height (0), m_areas(),
|
||||
listener(0), isInvalidateUptodate (true), lastUpdate (0)
|
||||
{
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
|
||||
buttonw = vminfo.thumbw + 20;
|
||||
buttonh = vminfo.thumbh + 28;
|
||||
curIndex = lev::Index::getCurrentIndex();
|
||||
iselected = curIndex->getCurrentPosition();
|
||||
ifirst = curIndex->getScreenFirstPosition();
|
||||
preview_cache = LevelPreviewCache::instance();
|
||||
scoreMgr = lev::ScoreManager::instance();
|
||||
img_link = enigma::GetImage("ic-link");
|
||||
img_copy = enigma::GetImage("ic-copy");
|
||||
img_feather = enigma::GetImage("ic-feather");
|
||||
img_easy = enigma::GetImage("completed-easy");
|
||||
img_hard = enigma::GetImage("completed");
|
||||
img_changed = enigma::GetImage("changed");
|
||||
img_unavailable = enigma::GetImage("unavailable");
|
||||
// img_unknown = enigma::GetImage("unknown");
|
||||
img_par = enigma::GetImage("par");
|
||||
img_wrEasy = enigma::GetImage("ic-wr-easy");
|
||||
img_wrDifficult = enigma::GetImage("ic-wr-difficult");
|
||||
img_border = enigma::GetImage("thumbborder");
|
||||
img_editborder = enigma::GetImage("editborder");
|
||||
}
|
||||
|
||||
void LevelWidget::syncFromIndexMgr() {
|
||||
if (curIndex != lev::Index::getCurrentIndex()) {
|
||||
curIndex = lev::Index::getCurrentIndex();
|
||||
iselected = curIndex->getCurrentPosition();
|
||||
ifirst = curIndex->getScreenFirstPosition();
|
||||
invalidate();
|
||||
sound::EmitSoundEvent ("menumove");
|
||||
} else if (iselected != curIndex->getCurrentPosition()) {
|
||||
sound::EmitSoundEvent ("menumove");
|
||||
}
|
||||
// repair ifirst on boot and screen resolution changes
|
||||
set_selected(curIndex->getScreenFirstPosition(),
|
||||
curIndex->getCurrentPosition());
|
||||
}
|
||||
|
||||
void LevelWidget::syncToIndexMgr() {
|
||||
curIndex->setCurrentPosition(iselected);
|
||||
curIndex->setScreenFirstPosition(ifirst);
|
||||
}
|
||||
|
||||
void LevelWidget::realize (const ecl::Rect &area_)
|
||||
{
|
||||
Widget::realize (area_);
|
||||
width = area_.w / buttonw;
|
||||
height = area_.h / buttonh;
|
||||
}
|
||||
|
||||
void LevelWidget::trigger_action() {
|
||||
if (listener) {
|
||||
listener->on_action(this);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelWidget::scroll_up (int nlines)
|
||||
{
|
||||
int newFirst = ifirst;
|
||||
int newSelected = iselected;
|
||||
for (; nlines; --nlines) {
|
||||
if (newFirst+width*height >= curIndex->size())
|
||||
break;
|
||||
newFirst += width;
|
||||
if (newSelected < newFirst)
|
||||
newSelected += width;
|
||||
}
|
||||
set_selected (newFirst, newSelected);
|
||||
}
|
||||
|
||||
void LevelWidget::scroll_down(int nlines)
|
||||
{
|
||||
int newFirst = ifirst;
|
||||
int newSelected = iselected;
|
||||
for (; nlines; --nlines) {
|
||||
if (newFirst == 0) {
|
||||
break;
|
||||
} else if (newFirst < width) {
|
||||
newFirst = 0;
|
||||
if (newSelected >= width*height)
|
||||
newSelected = width*height - 1;
|
||||
} else {
|
||||
newFirst -= width;
|
||||
if (newSelected >= newFirst+width*height)
|
||||
newSelected -= width;
|
||||
}
|
||||
}
|
||||
set_selected (newFirst, newSelected);
|
||||
}
|
||||
|
||||
void LevelWidget::page_up() {
|
||||
set_selected ((ifirst >= width*height ? ifirst - width*height : 0),
|
||||
(iselected >= width*height ? iselected - width*height : 0));
|
||||
syncToIndexMgr();
|
||||
}
|
||||
|
||||
void LevelWidget::page_down()
|
||||
{
|
||||
int s = lev::Index::getCurrentIndex()->size() - 1; // last position
|
||||
int lastPageFirst = (s >= width*height ? (s / width - height + 1) * width : 0);
|
||||
|
||||
// make sure last page is shown as a whole
|
||||
int first = std::min<int> (lastPageFirst, ifirst + width*height);
|
||||
// set_selected (first, s-1);
|
||||
set_selected (first, iselected + width*height);
|
||||
syncToIndexMgr();
|
||||
}
|
||||
|
||||
void LevelWidget::start() {
|
||||
set_selected(0,0);
|
||||
syncToIndexMgr();
|
||||
}
|
||||
|
||||
void LevelWidget::end() {
|
||||
int s = lev::Index::getCurrentIndex()->size() - 1; // last position
|
||||
int lastPageFirst = (s >= width*height ? (s / width - height + 1) * width : 0);
|
||||
set_selected(lastPageFirst, s);
|
||||
syncToIndexMgr();
|
||||
}
|
||||
|
||||
void LevelWidget::set_current (int newsel)
|
||||
{
|
||||
set_selected (ifirst, newsel);
|
||||
}
|
||||
|
||||
void LevelWidget::set_selected (int newfirst, int newsel)
|
||||
{
|
||||
int numlevels = curIndex->size();
|
||||
newsel = Clamp<int> (newsel, 0, numlevels-1);
|
||||
if (newsel < 0) newsel = 0;
|
||||
|
||||
if (newsel < newfirst)
|
||||
newfirst = (newsel/width)*width;
|
||||
if (newsel >= newfirst+width*height)
|
||||
newfirst = (newsel/width-height+1)*width;
|
||||
|
||||
newfirst = Clamp<int> (newfirst, 0, numlevels-1);
|
||||
if (newfirst < 0) newfirst = 0;
|
||||
|
||||
size_t oldsel = iselected;
|
||||
if (newfirst != ifirst) {
|
||||
ifirst = newfirst;
|
||||
iselected = newsel;
|
||||
|
||||
if (!m_areas.empty()) {
|
||||
sound::EmitSoundEvent ("menumove");
|
||||
if (oldsel != newsel)
|
||||
sound::EmitSoundEvent ("menuswitch");
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
else if (newsel != iselected) {
|
||||
iselected = newsel;
|
||||
|
||||
if (!m_areas.empty()) {
|
||||
sound::EmitSoundEvent ("menuswitch");
|
||||
invalidate_area(m_areas[oldsel-ifirst]); // old selection
|
||||
invalidate_area(m_areas[iselected-ifirst]); // new selection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelWidget::draw_level_preview (ecl::GC &gc, int x, int y,
|
||||
lev::Proxy *proxy, bool selected, bool isCross, bool locked,
|
||||
bool allowGeneration, bool &didGenerate) {
|
||||
// Draw button with level preview
|
||||
|
||||
Surface *img = preview_cache->getPreview(proxy, allowGeneration, didGenerate);
|
||||
if (img == NULL)
|
||||
return false;
|
||||
|
||||
if (selected) {
|
||||
blit (gc, x-4, y-4, displayEditBorder ? img_editborder : img_border);
|
||||
blit (gc, x, y, img);
|
||||
}
|
||||
else {
|
||||
img->set_alpha (127);
|
||||
blit (gc, x, y, img);
|
||||
img->set_alpha(255);
|
||||
}
|
||||
|
||||
// Shade unavailable levels
|
||||
if (locked)
|
||||
blit (gc, x, y, img_unavailable);
|
||||
|
||||
if (displayScoreIcons) {
|
||||
// Draw solved/changed icons on top of level preview
|
||||
// Easy/difficult mode and solved status:
|
||||
// None: Level not beaten - no easy mode available
|
||||
// Feather: Level not beaten - easy mode available
|
||||
// Feather + Gold: Level beaten in normal mode - easy available
|
||||
// Silver: Level beaten in easy mode (normal mode available)
|
||||
// Gold: Level beaten in normal mode - easy not availabe
|
||||
// Silver + Gold: Level beaten in all modes - easy available
|
||||
Surface *useAsEasy = NULL;
|
||||
Surface *useAsDifficult = NULL;
|
||||
if (proxy->hasEasymode()) {
|
||||
useAsEasy = img_feather;
|
||||
if (scoreMgr->isSolved(proxy, DIFFICULTY_EASY))
|
||||
useAsEasy = img_easy;
|
||||
}
|
||||
if (scoreMgr->isSolved(proxy, DIFFICULTY_HARD))
|
||||
useAsDifficult = img_hard;
|
||||
|
||||
if (app.state->getInt("Difficulty") == DIFFICULTY_HARD) {
|
||||
// draw golden medal over silber medal
|
||||
if (useAsEasy != NULL)
|
||||
blit (gc, x, y, useAsEasy);
|
||||
if (useAsDifficult != NULL)
|
||||
blit (gc, x+5, y, useAsDifficult);
|
||||
}
|
||||
else {
|
||||
// draw silver medal over golden medal
|
||||
if (useAsDifficult != NULL)
|
||||
blit (gc, x+5, y, useAsDifficult);
|
||||
if (useAsEasy != NULL)
|
||||
blit (gc, x, y, useAsEasy);
|
||||
}
|
||||
|
||||
// Add warning sign if level has been changed since player solved it
|
||||
if (scoreMgr->isOutdated(proxy, app.state->getInt("Difficulty")))
|
||||
blit (gc, x-3, y-3, img_changed);
|
||||
|
||||
// Add icon if worldrecord or par
|
||||
if (scoreMgr->bestScoreReached(proxy, app.state->getInt("Difficulty"))) {
|
||||
blit(gc, x+35, y+5,
|
||||
(app.state->getInt("Difficulty") != DIFFICULTY_HARD &&
|
||||
proxy->hasEasymode()) ? img_wrEasy : img_wrDifficult);
|
||||
} else if (scoreMgr->parScoreReached(proxy, app.state->getInt("Difficulty"))){
|
||||
blit(gc, x+30, y+12, img_par);
|
||||
}
|
||||
} else {
|
||||
// Draw solved/changed icons on top of level preview
|
||||
if (isCross)
|
||||
blit (gc, x+4, y+4, img_link);
|
||||
else
|
||||
blit (gc, x+4, y+4, img_copy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LevelWidget::draw (ecl::GC &gc, const ecl::Rect &r)
|
||||
{
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
const int imgw = vminfo.thumbw; // Size of the preview images
|
||||
const int imgh = vminfo.thumbh;
|
||||
|
||||
const int hgap = Max(0, (get_w() - width*buttonw) / (width));
|
||||
const int vgap = Max(0, (get_h() - height*buttonh)/ (height-1));
|
||||
|
||||
unsigned i=ifirst; // level index
|
||||
bool allowGeneration = true;
|
||||
|
||||
for (int y=0; y<height; y++)
|
||||
{
|
||||
for (int x=0; x<width; x++, i++)
|
||||
{
|
||||
if (i >= curIndex->size())
|
||||
goto done_painting;
|
||||
|
||||
int xpos = get_x() + hgap/2 + x*(buttonw + hgap);
|
||||
int ypos = get_y() + y*(buttonh + vgap);
|
||||
|
||||
Rect buttonarea(xpos, ypos, buttonw, buttonh);
|
||||
if (!(r.overlaps(buttonarea) || r.w == 0))
|
||||
continue; // r.w==0 if repainting whole screen
|
||||
|
||||
if( (i-ifirst) >= m_areas.size()) {
|
||||
m_areas.push_back(buttonarea);
|
||||
pending_redraws.push_back(false);
|
||||
} else {
|
||||
m_areas[(i-ifirst)] = buttonarea;
|
||||
}
|
||||
// Draw level preview
|
||||
lev::Proxy *levelProxy = curIndex->getProxy(i);
|
||||
int imgx = xpos+(buttonw-imgw)/2;
|
||||
int imgy = ypos + 4;
|
||||
if (levelProxy != NULL) {
|
||||
bool didGenerate;
|
||||
bool didDraw = draw_level_preview (gc, imgx, imgy, levelProxy,
|
||||
i == iselected, !curIndex->isSource(levelProxy),
|
||||
!curIndex->mayPlayLevel(i+1),
|
||||
allowGeneration, didGenerate);
|
||||
if (didGenerate) {
|
||||
// do not generate more than 1 preview from level source
|
||||
// per draw call
|
||||
allowGeneration = false;
|
||||
}
|
||||
if (didDraw) {
|
||||
pending_redraws[(i-ifirst)] = false;
|
||||
} else {
|
||||
// the button is not drawn - mark it to be drawn on
|
||||
// a future tick
|
||||
pending_redraws[(i-ifirst)] = true;
|
||||
isInvalidateUptodate = false;
|
||||
}
|
||||
}
|
||||
// Draw level name
|
||||
Font *smallfnt = enigma::GetFont("levelmenu");
|
||||
Font *altsmallfnt = enigma::GetFont("smallalternative");;
|
||||
std::string caption = levelProxy->getTitle();
|
||||
smallfnt->render (gc,
|
||||
xpos + buttonw/2 - ecl::Min(smallfnt->get_width(caption.c_str(), altsmallfnt)/2, (buttonw+hgap)/2),
|
||||
imgy + imgh + 2,
|
||||
caption, altsmallfnt, buttonw + hgap);
|
||||
}
|
||||
}
|
||||
done_painting:
|
||||
m_areas.resize (i-ifirst); // Remove unused areas (if any) from the list
|
||||
return;
|
||||
}
|
||||
|
||||
void LevelWidget::tick (double time) {
|
||||
if (!isInvalidateUptodate) {
|
||||
// invalidate just 1 button for redraw
|
||||
bool isFirst = true;
|
||||
for (int i = 0; i < pending_redraws.size(); i++) {
|
||||
if (pending_redraws[i] == true) {
|
||||
if (isFirst) {
|
||||
invalidate_area(m_areas[i]);
|
||||
isInvalidateUptodate = true;
|
||||
isFirst = false;
|
||||
} else {
|
||||
isInvalidateUptodate = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LevelWidget::on_event(const SDL_Event &e)
|
||||
{
|
||||
bool handled = Widget::on_event(e);
|
||||
|
||||
switch (e.type) {
|
||||
case SDL_MOUSEMOTION:
|
||||
if (get_area().contains(e.motion.x, e.motion.y)) {
|
||||
int newsel=iselected;
|
||||
for (unsigned i=0; i<m_areas.size(); ++i)
|
||||
if (m_areas[i].contains(e.motion.x, e.motion.y))
|
||||
{
|
||||
newsel = ifirst+i;
|
||||
break;
|
||||
}
|
||||
set_current(newsel);
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (get_area().contains(e.button.x, e.button.y))
|
||||
handled = handle_mousedown (&e);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
handled = handle_keydown (&e);
|
||||
break;
|
||||
}
|
||||
syncToIndexMgr();
|
||||
return handled;
|
||||
}
|
||||
|
||||
bool LevelWidget::handle_mousedown (const SDL_Event *e)
|
||||
{
|
||||
switch (e->button.button) {
|
||||
case SDL_BUTTON_LEFT:
|
||||
for (unsigned i=0; i<m_areas.size(); ++i)
|
||||
if (m_areas[i].contains(e->button.x, e->button.y))
|
||||
{
|
||||
sound::EmitSoundEvent ("menuok");
|
||||
iselected = ifirst+i;
|
||||
syncToIndexMgr();
|
||||
if (SDL_GetModState() & KMOD_CTRL && !(SDL_GetModState() & KMOD_SHIFT)) {
|
||||
// control key pressed - level inspector
|
||||
LevelInspector m(curIndex->getProxy(iselected));
|
||||
m.manage();
|
||||
get_parent()->draw_all();
|
||||
} else {
|
||||
// no control key - start level
|
||||
trigger_action();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
for (unsigned i=0; i<m_areas.size(); ++i)
|
||||
if (m_areas[i].contains(e->button.x, e->button.y))
|
||||
{
|
||||
sound::EmitSoundEvent ("menuok");
|
||||
iselected = ifirst+i;
|
||||
syncToIndexMgr();
|
||||
LevelInspector m(curIndex->getProxy(iselected));
|
||||
m.manage();
|
||||
get_parent()->draw_all();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 4: scroll_down(1); return true;
|
||||
case 5: scroll_up(1); return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LevelWidget::handle_keydown (const SDL_Event *e)
|
||||
{
|
||||
switch (e->key.keysym.sym) {
|
||||
|
||||
case SDLK_t:
|
||||
// Generate new level preview for current level
|
||||
preview_cache->updatePreview(curIndex->getProxy(iselected));
|
||||
invalidate();
|
||||
break;
|
||||
|
||||
case SDLK_LEFT:
|
||||
if (!(SDL_GetModState() & KMOD_ALT)) {
|
||||
set_current (iselected>1 ? iselected-1 : 0);
|
||||
break;
|
||||
} else
|
||||
return false;
|
||||
case SDLK_RIGHT:
|
||||
if (!(SDL_GetModState() & KMOD_ALT)) {
|
||||
set_current (iselected+1);
|
||||
break;
|
||||
} else
|
||||
return false;
|
||||
case SDLK_DOWN: set_current (iselected+width); break;
|
||||
case SDLK_UP: set_current (iselected>width ? iselected-width : 0); break;
|
||||
case SDLK_PAGEDOWN: page_down(); break;
|
||||
case SDLK_PAGEUP: page_up(); break;
|
||||
case SDLK_HOME: start(); break;
|
||||
case SDLK_END: end(); break;
|
||||
|
||||
case SDLK_RETURN:
|
||||
trigger_action();
|
||||
break;
|
||||
|
||||
default:
|
||||
return false; // key not handled
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
111
project/jni/application/enigma/src/gui/LevelWidget.hh
Normal file
111
project/jni/application/enigma/src/gui/LevelWidget.hh
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_LEVELWIDGET_HH_INCLUDED
|
||||
#define GUI_LEVELWIDGET_HH_INCLUDED
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
#include "gui/LevelPreviewCache.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- LevelWidget -------------------- */
|
||||
|
||||
class LevelMenu;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class LevelWidget : public Widget {
|
||||
public:
|
||||
LevelWidget(bool withScoreIcons = true, bool withEditBorder = false);
|
||||
|
||||
//---------- Widget interface ----------//
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
void tick (double time);
|
||||
|
||||
void set_listener(ActionListener *al) {
|
||||
listener = al;
|
||||
}
|
||||
void trigger_action();
|
||||
|
||||
virtual void realize (const ecl::Rect &r);
|
||||
|
||||
//---------- Cursor motion ----------//
|
||||
|
||||
void page_up();
|
||||
void page_down();
|
||||
void start();
|
||||
void end();
|
||||
|
||||
bool on_event(const SDL_Event &e);
|
||||
void syncFromIndexMgr(); // external change of currentIndex, currentLevel
|
||||
|
||||
private:
|
||||
//---------- Private functions ----------//
|
||||
void syncToIndexMgr();
|
||||
void set_current (int newsel);
|
||||
void scroll_up(int lines);
|
||||
void scroll_down(int lines);
|
||||
void set_selected (int newfirst, int newsel);
|
||||
bool draw_level_preview (ecl::GC &gc, int x, int y,
|
||||
lev::Proxy *proxy, bool selected, bool isCross, bool locked,
|
||||
bool allowGeneration, bool &didGenerate);
|
||||
|
||||
bool handle_keydown (const SDL_Event *e);
|
||||
bool handle_mousedown (const SDL_Event *e);
|
||||
|
||||
//---------- Variables ----------//
|
||||
bool displayScoreIcons;
|
||||
bool displayEditBorder;
|
||||
LevelPreviewCache *preview_cache;
|
||||
lev::ScoreManager *scoreMgr;
|
||||
lev::Index *curIndex;
|
||||
ActionListener *listener;
|
||||
|
||||
int ifirst; // Index of "upper left" level
|
||||
int iselected; // Index of selected level
|
||||
int width; // number of buttons in a row
|
||||
int height; // number of buttons in a column
|
||||
int buttonw; // pixelwidth of a button
|
||||
int buttonh; // pixelheight of a button
|
||||
std::vector<ecl::Rect> m_areas; // Screen areas occupied by level previews
|
||||
std::vector<bool> pending_redraws;
|
||||
bool isInvalidateUptodate;
|
||||
double lastUpdate;
|
||||
|
||||
// some image pointers for efficiency
|
||||
ecl::Surface *img_link;
|
||||
ecl::Surface *img_copy;
|
||||
ecl::Surface *img_feather;
|
||||
ecl::Surface *img_easy;
|
||||
ecl::Surface *img_hard;
|
||||
ecl::Surface *img_changed;
|
||||
ecl::Surface *img_unavailable;
|
||||
// Surface *img_unknown;
|
||||
ecl::Surface *img_par;
|
||||
ecl::Surface *img_wrEasy;
|
||||
ecl::Surface *img_wrDifficult;
|
||||
ecl::Surface *img_border;
|
||||
ecl::Surface *img_editborder;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
392
project/jni/application/enigma/src/gui/MainMenu.cpp
Normal file
392
project/jni/application/enigma/src/gui/MainMenu.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/MainMenu.hh"
|
||||
#include "gui/LevelMenu.hh"
|
||||
#include "gui/OptionsMenu.hh"
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "gui/InfoMenu.hh"
|
||||
#include "gui/LevelPackMenu.hh"
|
||||
#include "gui/LevelPreviewCache.hh"
|
||||
#include "display.hh"
|
||||
#include "ecl.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "world.hh"
|
||||
|
||||
#include "netgame.hh"
|
||||
#include "editor.hh"
|
||||
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Helper routines -------------------- */
|
||||
|
||||
// namespace
|
||||
// {
|
||||
/*! Change the video mode. Because this opens a new screen with a
|
||||
new resolution, the display engine must be re-initialized to
|
||||
load the appropriate models. */
|
||||
void ChangeVideoMode()
|
||||
{
|
||||
world::PrepareLevel(); // make sure no references to models remain
|
||||
video::ChangeVideoMode();
|
||||
LevelPreviewCache::instance()->clear();
|
||||
enigma::ClearImageCache();
|
||||
display::Shutdown();
|
||||
display::Init();
|
||||
}
|
||||
// }
|
||||
|
||||
|
||||
/* -------------------- NetworkMenu -------------------- */
|
||||
|
||||
NetworkMenu::NetworkMenu ()
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
|
||||
BuildVList b(this, Rect((vminfo->width - 150)/2,150,150,40), 5);
|
||||
m_startgame = b.add(new StaticTextButton(N_("Start Game"), this));
|
||||
m_joingame = b.add(new StaticTextButton(N_("Join Game"), this));
|
||||
m_back = b.add(new StaticTextButton(N_("Back"), this));
|
||||
}
|
||||
|
||||
NetworkMenu::~NetworkMenu ()
|
||||
{
|
||||
}
|
||||
|
||||
bool NetworkMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkMenu::on_action(gui::Widget *w)
|
||||
{
|
||||
if (w == m_startgame) {
|
||||
netgame::Start();
|
||||
}
|
||||
else if (w == m_joingame) {
|
||||
netgame::Join("localhost", 12345);
|
||||
}
|
||||
if (w == m_back)
|
||||
Menu::quit();
|
||||
}
|
||||
|
||||
void NetworkMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
video::SetCaption (("Enigma - Network Menu"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
|
||||
void NetworkMenu::tick(double dtime)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Main menu -------------------- */
|
||||
static const char *credit_text[] = {
|
||||
N_("Main developers of the 1.0 release:"),
|
||||
N_(" RONALD LAMPRECHT (lead)"),
|
||||
" RAOUL BOURQUIN",
|
||||
" ANDREAS LOCHMANN",
|
||||
" ",
|
||||
N_("Special Thanks To:"),
|
||||
N_(" DANIEL HECK (project founder)"),
|
||||
N_(" MEINOLF SCHNEIDER (game idea, level design)"),
|
||||
" ",
|
||||
N_("Please refer to the manual or the next pages for full credits."),
|
||||
" ",
|
||||
N_("Home Page: http://www.nongnu.org/enigma"),
|
||||
N_("Contact: enigma-devel@nongnu.org"),
|
||||
" ",
|
||||
N_("Enigma is free software and may be distributed under the"),
|
||||
N_("terms of the GNU General Public License, version 2."),
|
||||
" ",
|
||||
N_("Copyright (C) 2002-2007 Daniel Heck and contributors."),
|
||||
0,
|
||||
N_("Main developer of all releases:"),
|
||||
" ",
|
||||
" Raoul Bourquin (Level admin. & design, all over invaluable additions)",
|
||||
" Siegfried Fennig (Level design, graphics)",
|
||||
" Martin Hawlisch (Level design, graphics, programming)",
|
||||
" Daniel Heck (Main developer, graphics, documentation)",
|
||||
" Ronald Lamprecht (XML, Gui, portability, core prog., documentation)",
|
||||
" Andreas Lochmann (Programming, level admin. & design, documentation)",
|
||||
" Petr Machata (Level design, programming)",
|
||||
" Nat Pryce (Level design)",
|
||||
" Jacob Scott (Level design)",
|
||||
" Sven Siggelkow (Level design and special Oxyd expertise)",
|
||||
" Ralf Westram (Programming, level design)",
|
||||
0,
|
||||
N_("Special Thanks:"),
|
||||
" Johannes Fortmann (Mac OS X port, some programming, graphics)",
|
||||
" illmind (Forum mag-heut.net administration, Level design)",
|
||||
// waiting for licence to add the sounds
|
||||
// " \'Cellar of Rats\' (Sound effects)",
|
||||
" Jennifer Robertson (Graphics second generation)",
|
||||
" Jeremy Sawicki (Oxydlib)",
|
||||
" Erich Schubert (Debian/Ubuntu packages, level design)",
|
||||
" Lukas Schüller (Level design)",
|
||||
" Andrew \'Necros\' Sega (Menu music \'Pentagonal Dreams\')",
|
||||
" David W. Skinner (Many Sokoban Levels)",
|
||||
" Clifford J. Tasner (Music second generation, Proof reading)",
|
||||
0,
|
||||
N_("Contributors:"),
|
||||
" Roberto Bardin (Level design)",
|
||||
" Alain Busser (Level design, French translation, manual)",
|
||||
" Guy Busser (Level design)",
|
||||
" Richi Bützer (Level design)",
|
||||
" Capkoh (Level design)",
|
||||
" Christoph & Anita (Level design)",
|
||||
" Дремук Сергей - Serge Dremuk (Russian translation)",
|
||||
" Joseph Dunne (Level design)",
|
||||
" Xerxes M. Dynatos (Level design)",
|
||||
" Edward (Level design)",
|
||||
" Stephanie Fabian (Invaluable bug reports)",
|
||||
" Roberto García (Spanish translation)",
|
||||
" Andy Geldmacher (Level design)",
|
||||
" Edwin Groothuis (FreeBSD port)",
|
||||
" Immanuel Herrmann (Level design)",
|
||||
" Máté Lehel Juhász (Hungarian translation)",
|
||||
0,
|
||||
" Samuele Kaplun (Italian translation)",
|
||||
" Jens-Christian Korth (Level design)",
|
||||
" Manuel König (Level design, bug reports)",
|
||||
" Johannes Laire (Level design)",
|
||||
" Joona Laire (Level design)",
|
||||
" Markus Laire (Level design)",
|
||||
" Dominik Lehmann (Level design)",
|
||||
" Edward Leuf (Feedback, bug reports)",
|
||||
" Ingo van Lil (Feedback, bug reports)",
|
||||
" Frank van der Loo (Dutch translation)",
|
||||
" Sidney Markowitz (Mac OS X port)",
|
||||
" Barry & Lori Mead (Level design)",
|
||||
" Linda Mihalic (English proof reading)",
|
||||
" moonpearl (Level design)",
|
||||
" Krishnamurti L.L.V. Nunes (Portuguese translation)",
|
||||
" Daniel Nylander (Swedish translation)",
|
||||
0,
|
||||
" Andreas Persenius (Level design)",
|
||||
" Peter Santo (Level design)",
|
||||
" Tobias Schmidbauer (Windows installer and icon)",
|
||||
" Achim Settelmeier (RPM specfile)",
|
||||
" Jon Sneyers (Level design)",
|
||||
" Spaceman (Level design)",
|
||||
" Ulf Stegemann (Level design)",
|
||||
" Jürgen Sticht (Level design)",
|
||||
" Mikke Surakka (Finnish translation)",
|
||||
" Andrzej Szombierski (Level design)",
|
||||
" Tacvek (Lua 5.1 upgrade)",
|
||||
" Michael Terry (.desktop file)",
|
||||
" Ray Wick (Level design)",
|
||||
" Joe Wreschnig (Manual page)",
|
||||
" Юрий Жиромский - Yuriy Zhyromskiy (Russian Manual)",
|
||||
0,
|
||||
};
|
||||
|
||||
MainMenu::MainMenu()
|
||||
{
|
||||
build_menu();
|
||||
}
|
||||
|
||||
void MainMenu::build_menu()
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
|
||||
BuildVList b(this, Rect((vminfo->width - 150)/2,150,150,40), 5);
|
||||
m_startgame = b.add(new StaticTextButton(N_("Start Game"), this));
|
||||
m_levelpack = b.add(new StaticTextButton(N_("Level Pack"), this));
|
||||
#ifdef ENABLE_EXPERIMENTAL
|
||||
m_netgame = b.add (new StaticTextButton (N_("Network Game"), this));
|
||||
leveled = b.add(new StaticTextButton(N_("Editor"), this));
|
||||
#endif
|
||||
options = b.add(new StaticTextButton(N_("Options"), this));
|
||||
credits = b.add(new StaticTextButton(N_("Credits"), this));
|
||||
quit = b.add(new StaticTextButton(N_("Quit"), this));
|
||||
}
|
||||
|
||||
void MainMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
|
||||
video::SetCaption (("Enigma - Main Menu"));
|
||||
sound::PlayMusic (options::GetString("MenuMusicFile"));
|
||||
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
|
||||
Font *f = enigma::GetFont("levelmenu");
|
||||
Surface * logo(enigma::GetImage("enigma_logo3"));
|
||||
int x0=(vminfo->width - logo->width())/2;
|
||||
int y0=30;
|
||||
blit(gc, x0, y0, logo);
|
||||
f->render (gc, 5, vminfo->height - 20, app.getVersionInfo().c_str());
|
||||
}
|
||||
|
||||
bool MainMenu::on_event (const SDL_Event &e) {
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
SDLKey keysym = e.key.keysym.sym;
|
||||
switch (keysym) {
|
||||
case SDLK_F2:
|
||||
show_paths();
|
||||
invalidate_all();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainMenu::on_action(Widget *w)
|
||||
{
|
||||
if (w == m_startgame) {
|
||||
LevelPackMenu m;
|
||||
m.manageLevelMenu();
|
||||
invalidate_all();
|
||||
} else if (w == m_levelpack) {
|
||||
LevelPackMenu m;
|
||||
m.manage();
|
||||
invalidate_all();
|
||||
} else if (w == credits) {
|
||||
displayInfo(credit_text, 6);
|
||||
invalidate_all();
|
||||
} else if (w == options) {
|
||||
ShowOptionsMenu(0);
|
||||
|
||||
#ifdef ENABLE_EXPERIMENTAL
|
||||
} else if (w == m_netgame) {
|
||||
ShowNetworkMenu();
|
||||
} else if (w == leveled) {
|
||||
editor::Run();
|
||||
#endif
|
||||
} else if (w == quit) {
|
||||
Menu::quit();
|
||||
} else
|
||||
return;
|
||||
invalidate_all();
|
||||
}
|
||||
|
||||
void MainMenu::tick(double /* dtime */)
|
||||
{
|
||||
bool option_fullscreen = options::GetInt ("FullScreen") != 0;
|
||||
if (options::GetInt ("VideoMode") != video::GetVideoMode()
|
||||
|| option_fullscreen != video::IsFullScreen())
|
||||
{
|
||||
ChangeVideoMode();
|
||||
clear();
|
||||
reset_active_widget ();
|
||||
build_menu();
|
||||
invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
void MainMenu::show_paths() {
|
||||
const char *pathtext[25];
|
||||
std::string pathstrings[25];
|
||||
std::string work;
|
||||
Font *menufont = enigma::GetFont("menufont");
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
int width = vminfo->width - 80;
|
||||
int i = 0;
|
||||
|
||||
pathtext[i++] = N_("Preferences Path:");
|
||||
work = app.prefPath;
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("User Path:");
|
||||
work = app.userPath;
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("User Image Path:");
|
||||
work = app.userImagePath;
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("System Path:");
|
||||
work = app.systemFS->getDataPath();
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("Resource Paths:");
|
||||
work = app.resourceFS->getDataPath();
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = " ";
|
||||
pathtext[i++] = N_("L10n Path:");
|
||||
work = app.l10nPath;
|
||||
do {
|
||||
std::string::size_type breakPos = breakString(menufont, work,"/\\", width);
|
||||
pathstrings[i] = " " + work.substr(0,breakPos);
|
||||
pathtext[i] = pathstrings[i].c_str();
|
||||
work = work.substr(breakPos);
|
||||
i++;
|
||||
} while(!work.empty() );
|
||||
pathtext[i++] = 0;
|
||||
displayInfo(pathtext, 1);
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void ShowMainMenu() {
|
||||
MainMenu m;
|
||||
m.manage();
|
||||
}
|
||||
|
||||
void ShowNetworkMenu()
|
||||
{
|
||||
NetworkMenu m;
|
||||
m.manage();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
83
project/jni/application/enigma/src/gui/MainMenu.hh
Normal file
83
project/jni/application/enigma/src/gui/MainMenu.hh
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_MAINMENU_HH_INCLUDED
|
||||
#define GUI_MAINMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- MainMenu -------------------- */
|
||||
|
||||
class MainMenu : public Menu {
|
||||
public:
|
||||
MainMenu();
|
||||
private:
|
||||
// Menu interface
|
||||
void draw_background(ecl::GC &gc);
|
||||
void tick(double dtime);
|
||||
|
||||
// Widget interface
|
||||
virtual bool on_event(const SDL_Event &e);
|
||||
|
||||
// ActionListener interface.
|
||||
void on_action(Widget *w);
|
||||
|
||||
// Private methods.
|
||||
void show_paths();
|
||||
void build_menu();
|
||||
|
||||
// Variables.
|
||||
Widget *m_startgame;
|
||||
Widget *m_levelpack;
|
||||
Widget *m_netgame;
|
||||
Widget *leveled;
|
||||
Widget *manual;
|
||||
Widget *options;
|
||||
Widget *credits;
|
||||
Widget *quit;
|
||||
Widget *lpack;
|
||||
};
|
||||
|
||||
/* -------------------- NetworkMenu -------------------- */
|
||||
|
||||
class NetworkMenu : public gui::Menu {
|
||||
public:
|
||||
NetworkMenu ();
|
||||
~NetworkMenu ();
|
||||
private:
|
||||
// ActionListener interface.
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(gui::Widget *w);
|
||||
|
||||
// Menu interface.
|
||||
void draw_background(ecl::GC &gc);
|
||||
void tick(double dtime);
|
||||
|
||||
// Variables.
|
||||
gui::Widget *m_startgame;
|
||||
gui::Widget *m_joingame;
|
||||
gui::Widget *m_back;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
void ShowMainMenu();
|
||||
void ShowNetworkMenu();
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
213
project/jni/application/enigma/src/gui/Menu.cpp
Normal file
213
project/jni/application/enigma/src/gui/Menu.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "options.hh"
|
||||
#include "nls.hh"
|
||||
#include "ecl.hh"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
#define SCREEN ecl::Screen::get_instance()
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Menu -------------------- */
|
||||
|
||||
Menu::Menu()
|
||||
: active_widget(0), quitp(false), abortp(false) {
|
||||
}
|
||||
|
||||
void Menu::add(Widget *w) {
|
||||
Container::add_child(w);
|
||||
}
|
||||
|
||||
void Menu::add(Widget *w, ecl::Rect r) {
|
||||
w->move (r.x, r.y);
|
||||
w->resize (r.w, r.h);
|
||||
add(w);
|
||||
}
|
||||
|
||||
|
||||
void Menu::quit() {
|
||||
quitp=true;
|
||||
}
|
||||
|
||||
void Menu::abort() {
|
||||
abortp=true;
|
||||
}
|
||||
|
||||
bool Menu::manage() {
|
||||
quitp=abortp=false;
|
||||
SDL_Event e;
|
||||
Uint32 enterTickTime = SDL_GetTicks(); // protection against ESC D.o.S. attacks
|
||||
while (SDL_PollEvent(&e)) {} // clear event queue
|
||||
draw_all();
|
||||
while (!(quitp || abortp)) {
|
||||
SCREEN->flush_updates();
|
||||
while (SDL_PollEvent(&e)) {
|
||||
handle_event(e);
|
||||
}
|
||||
SDL_Delay(10);
|
||||
if(active_widget) active_widget->tick(0.01);
|
||||
tick (0.01);
|
||||
refresh();
|
||||
}
|
||||
sound::EmitSoundEvent ("menuexit");
|
||||
// protection against ESC D.o.S. attacks
|
||||
Uint32 menuTickDuration = SDL_GetTicks() - enterTickTime;
|
||||
Uint32 minMenuTickDuration = 300;
|
||||
if (menuTickDuration < minMenuTickDuration)
|
||||
SDL_Delay(minMenuTickDuration - menuTickDuration);
|
||||
while (SDL_PollEvent(&e)) {} // clear event queue
|
||||
return !abortp;
|
||||
}
|
||||
|
||||
void Menu::goto_adjacent_widget(int xdir, int ydir) {
|
||||
Widget *next_widget = 0;
|
||||
if (active_widget) {
|
||||
next_widget = find_adjacent_widget(active_widget, xdir, ydir);
|
||||
}
|
||||
else { // no active_widget yet
|
||||
if ((xdir+ydir)>0) { // take first
|
||||
next_widget = *begin();
|
||||
}
|
||||
else { // take last
|
||||
iterator e = end();
|
||||
for (iterator i = begin(); i != e; ++i) {
|
||||
next_widget = *i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next_widget) {
|
||||
switch_active_widget(next_widget);
|
||||
}
|
||||
else { // no more widgets into that direction found
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::handle_event(const SDL_Event &e)
|
||||
{
|
||||
if (e.type == SDL_KEYDOWN &&
|
||||
e.key.keysym.sym == SDLK_RETURN &&
|
||||
e.key.keysym.mod & KMOD_ALT)
|
||||
{
|
||||
video::ToggleFullscreen();
|
||||
return;
|
||||
}
|
||||
|
||||
if (on_event(e))
|
||||
return;
|
||||
|
||||
switch (e.type) {
|
||||
case SDL_QUIT:
|
||||
abort();
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
track_active_widget( e.motion.x, e.motion.y );
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if (!active_widget || !active_widget->on_event(e)) {
|
||||
// if not handled by active_widget
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
abort();
|
||||
break;
|
||||
case SDLK_DOWN: goto_adjacent_widget( 0, 1); break;
|
||||
case SDLK_UP: goto_adjacent_widget( 0, -1); break;
|
||||
case SDLK_RIGHT: goto_adjacent_widget( 1, 0); break;
|
||||
case SDLK_LEFT: goto_adjacent_widget(-1, 0); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
track_active_widget( e.button.x, e.button.y );
|
||||
if (active_widget) active_widget->on_event(e);
|
||||
break;
|
||||
case SDL_VIDEOEXPOSE:
|
||||
draw_all();
|
||||
break;
|
||||
default:
|
||||
if (active_widget) active_widget->on_event(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::switch_active_widget(Widget *to_activate) {
|
||||
if (to_activate != active_widget) {
|
||||
if (active_widget)
|
||||
active_widget->deactivate();
|
||||
if (to_activate)
|
||||
to_activate->activate();
|
||||
active_widget = to_activate;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::track_active_widget( int x, int y ) {
|
||||
switch_active_widget(find_widget(x, y));
|
||||
}
|
||||
|
||||
|
||||
void Menu::center() {
|
||||
if (m_widgets.size() > 0) {
|
||||
using std::min;
|
||||
using std::max;
|
||||
|
||||
Rect a = m_widgets[0]->get_area();
|
||||
for (unsigned i=1; i<m_widgets.size(); ++i)
|
||||
{
|
||||
Rect r = m_widgets[i]->get_area();
|
||||
a.x = min(r.x, a.x);
|
||||
a.y = min(r.y, a.y);
|
||||
a.w += max(0, r.x+r.w-a.x-a.w);
|
||||
a.h += max(0, r.y+r.h-a.y-a.h);
|
||||
}
|
||||
Rect c=ecl::center(SCREEN->size(), a);
|
||||
int dx = c.x-a.x;
|
||||
int dy = c.y-a.y;
|
||||
|
||||
for (unsigned i=0; i<m_widgets.size(); ++i) {
|
||||
Rect r = m_widgets[i]->get_area();
|
||||
r.x += dx;
|
||||
r.y += dy;
|
||||
|
||||
m_widgets[i]->move (r.x, r.y);
|
||||
m_widgets[i]->resize (r.w, r.h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::draw (ecl::GC &gc, const ecl::Rect &r)
|
||||
{
|
||||
clip(gc, r);
|
||||
draw_background(gc);
|
||||
Container::draw(gc,r);
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
111
project/jni/application/enigma/src/gui/Menu.hh
Normal file
111
project/jni/application/enigma/src/gui/Menu.hh
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_MENU_HH_INCLUDED
|
||||
#define GUI_MENU_HH_INCLUDED
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
#include "gui/Menu.hh"
|
||||
#include "ecl_fwd.hh"
|
||||
#include "ecl_geom.hh"
|
||||
#include "SDL.h"
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- Menu -------------------- */
|
||||
|
||||
class Menu : public Container {
|
||||
public:
|
||||
Menu();
|
||||
|
||||
//! true: ok, false: menu aborted by user
|
||||
virtual bool manage();
|
||||
|
||||
void add(Widget *w);
|
||||
void add(Widget *w, ecl::Rect r);
|
||||
void center();
|
||||
|
||||
void draw (ecl::GC &gc, const ecl::Rect &r);
|
||||
|
||||
virtual void quit();
|
||||
void abort();
|
||||
|
||||
protected:
|
||||
void reset_active_widget()
|
||||
{ active_widget = 0; }
|
||||
|
||||
// Menu interface.
|
||||
virtual void draw_background(ecl::GC &/*gc*/) {}
|
||||
|
||||
private:
|
||||
void handle_event(const SDL_Event &e);
|
||||
|
||||
void switch_active_widget(Widget *to_activate);
|
||||
void track_active_widget( int x, int y ); // used by mouse
|
||||
void goto_adjacent_widget(int xdir, int ydir); // used by keyboard
|
||||
|
||||
// Variables.
|
||||
Widget *active_widget;
|
||||
bool quitp, abortp;
|
||||
};
|
||||
|
||||
class BuildVList {
|
||||
ecl::Rect r;
|
||||
Menu *container;
|
||||
int skip;
|
||||
public:
|
||||
BuildVList(Menu *cc, const ecl::Rect &rr, int s)
|
||||
: r(rr), container(cc), skip(s)
|
||||
{}
|
||||
|
||||
Widget *add(Widget *w) {
|
||||
container->add(w, r);
|
||||
r.y += r.h+skip;
|
||||
return w;
|
||||
}
|
||||
|
||||
ecl::Rect pos() const { return r; }
|
||||
};
|
||||
|
||||
class BuildHList {
|
||||
ecl::Rect r;
|
||||
Menu *container;
|
||||
int skip;
|
||||
public:
|
||||
BuildHList(Menu *cc, const ecl::Rect &rr, int s)
|
||||
: r(rr), container(cc), skip(s)
|
||||
{}
|
||||
|
||||
Widget * add(Widget *w) {
|
||||
container->add(w, r);
|
||||
r.x += r.w+skip;
|
||||
return w;
|
||||
}
|
||||
Widget *add (Widget *w, int width) {
|
||||
ecl::Rect rr(r.x, r.y, width, r.h);
|
||||
container->add(w, rr);
|
||||
r.x += width + skip;
|
||||
return w;
|
||||
}
|
||||
|
||||
ecl::Rect pos() const { return r; }
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
85
project/jni/application/enigma/src/gui/MonospacedLabel.cpp
Normal file
85
project/jni/application/enigma/src/gui/MonospacedLabel.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "gui/MonospacedLabel.hh"
|
||||
#include "ecl.hh"
|
||||
#include "nls.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
MonospacedLabel::MonospacedLabel (const std::string &text, char widthSample,
|
||||
std::string monospaceCharacters, HAlignment halign, VAlignment valign) :
|
||||
Label (text, halign, valign), sampleChar (widthSample),
|
||||
monoChars (monospaceCharacters) {
|
||||
}
|
||||
|
||||
void MonospacedLabel::draw (ecl::GC &gc, const ecl::Rect &) {
|
||||
Font *f = m_font;
|
||||
int w, h;
|
||||
naturalsize (w, h);
|
||||
|
||||
int x = get_x(), y=get_y();
|
||||
switch (m_halign) {
|
||||
case HALIGN_LEFT: break;
|
||||
case HALIGN_RIGHT: x += get_w() - w; break;
|
||||
case HALIGN_CENTER: x += (get_w()-w)/2; break;
|
||||
}
|
||||
switch (m_valign) {
|
||||
case VALIGN_TOP: break;
|
||||
case VALIGN_BOTTOM: y += get_h() - h; break;
|
||||
case VALIGN_CENTER: y += (get_h()-h)/2; break;
|
||||
}
|
||||
// translate if not an empty string
|
||||
const char * translation = _(m_text.c_str());
|
||||
int len = strlen(translation);
|
||||
int monoWidth = m_font->get_width(sampleChar);
|
||||
char c[] = " ";
|
||||
for (int i = 0; i<len; i++) {
|
||||
c[0] = translation[i];
|
||||
if (monoChars.empty() || monoChars.find_first_of(c[0]) !=
|
||||
std::string::npos) {
|
||||
int charWidth = m_font->get_width(c[0]);
|
||||
// centere char into monoWodth
|
||||
f->render (gc, x + (monoWidth-charWidth)/2, y, c);
|
||||
x += monoWidth;
|
||||
} else {
|
||||
f->render (gc, x, y, c);
|
||||
x += m_font->get_width(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonospacedLabel::naturalsize (int &w, int &h) const {
|
||||
h = m_font->get_height();
|
||||
w = 0;
|
||||
const char * translation = _(m_text.c_str());
|
||||
int len = strlen(translation);
|
||||
int monoWidth = m_font->get_width(sampleChar);
|
||||
for (int i = 0; i<len; i++) {
|
||||
if (monoChars.empty() || monoChars.find_first_of(translation[i]) !=
|
||||
std::string::npos) {
|
||||
w += monoWidth;
|
||||
} else {
|
||||
w += m_font->get_width(translation[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}} // namespace enigma::lev
|
||||
57
project/jni/application/enigma/src/gui/MonospacedLabel.hh
Normal file
57
project/jni/application/enigma/src/gui/MonospacedLabel.hh
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GUI_MONOSPACEDLABEL_HH_INCLUDED
|
||||
#define GUI_MONOSPACEDLABEL_HH_INCLUDED
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/**
|
||||
* A text label that uses the same width for each character even for
|
||||
* proportional fonts. Character positions of the label text is predictable
|
||||
* and alignment of several labels is thus possible. Usefull for output of
|
||||
* formatted numbers like score values.<p>
|
||||
* Not all characters have to be monospaced. The set of characters that
|
||||
* should have a constant width can be limited f.e. to the numbers 0-9.
|
||||
*/
|
||||
class MonospacedLabel : public Label {
|
||||
public:
|
||||
/**
|
||||
* The standard constructor.
|
||||
* @arg text The constant output text.
|
||||
* @arg widthSample The character that defines the width. Default is 'm'.
|
||||
* @arg monospaceCharacters The set of monospace characters. An empty
|
||||
* string means all characters. Example "0123456789".
|
||||
* @arg halign
|
||||
* @arg valign
|
||||
*/
|
||||
MonospacedLabel (const std::string &text="", char widthSample = 'm',
|
||||
std::string monospaceCharacters = "",
|
||||
HAlignment halign=HALIGN_CENTER, VAlignment valign=VALIGN_CENTER);
|
||||
|
||||
// Widget interface
|
||||
virtual void draw (ecl::GC &gc, const ecl::Rect &r);
|
||||
virtual void naturalsize (int &w, int &h) const;
|
||||
protected:
|
||||
char sampleChar;
|
||||
std::string monoChars;
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
477
project/jni/application/enigma/src/gui/OptionsMenu.cpp
Normal file
477
project/jni/application/enigma/src/gui/OptionsMenu.cpp
Normal file
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/OptionsMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
#include "LocalToXML.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "options.hh"
|
||||
#include "oxyd.hh"
|
||||
#include "sound.hh"
|
||||
#include "Utf8ToXML.hh"
|
||||
#include "video.hh"
|
||||
#include "XMLtoLocal.hh"
|
||||
#include "XMLtoUtf8.hh"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/* -------------------- Buttons for Options -------------------- */
|
||||
|
||||
class MouseSpeedButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return ecl::round_nearest<int>(options::GetMouseSpeed());
|
||||
}
|
||||
void set_value(int value) {
|
||||
options::SetMouseSpeed (value);
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
MouseSpeedButton()
|
||||
: ValueButton(options::MIN_MouseSpeed, options::MAX_MouseSpeed)
|
||||
{ init(); }
|
||||
};
|
||||
|
||||
class SoundVolumeButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return round_nearest<int>(options::GetDouble("SoundVolume")*10.0);
|
||||
}
|
||||
void set_value(int value) {
|
||||
options::SetOption("SoundVolume", value/10.0);
|
||||
options::UpdateVolume();
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
if (value == 0) {
|
||||
return _("muted");
|
||||
}
|
||||
else {
|
||||
return strf("%d", value);
|
||||
}
|
||||
}
|
||||
public:
|
||||
SoundVolumeButton() : ValueButton(0, 10) { init(); }
|
||||
};
|
||||
|
||||
class MusicVolumeButton : public ValueButton {
|
||||
int get_value() const {
|
||||
return round_nearest<int> (options::GetDouble("MusicVolume")*10.0);
|
||||
}
|
||||
void set_value(int value) {
|
||||
options::SetOption("MusicVolume", value/10.0);
|
||||
options::UpdateVolume();
|
||||
}
|
||||
|
||||
string get_text(int value) const {
|
||||
if (value == 0)
|
||||
return _("muted");
|
||||
else
|
||||
return strf("%d", value);
|
||||
}
|
||||
public:
|
||||
MusicVolumeButton() : ValueButton(0, 10) { init(); }
|
||||
};
|
||||
|
||||
class InGameMusicButton : public BoolOptionButton {
|
||||
void on_action(Widget *) {
|
||||
if (toggle())
|
||||
sound::PlayMusic (options::GetString("LevelMusicFile"));
|
||||
else
|
||||
sound::StopMusic (options::GetString("LevelMusicFile"));
|
||||
}
|
||||
public:
|
||||
InGameMusicButton() :
|
||||
BoolOptionButton("InGameMusic", N_("Music in game"), N_("No music in game"), this)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct SkipSolvedButton : public BoolOptionButton {
|
||||
SkipSolvedButton() : BoolOptionButton("SkipSolvedLevels", N_("Yes"), N_("No"), this) {}
|
||||
};
|
||||
|
||||
struct TimeHuntButton : public BoolOptionButton {
|
||||
TimeHuntButton() : BoolOptionButton("TimeHunting", N_("Yes"), N_("No"), this) {}
|
||||
};
|
||||
|
||||
struct RatingsUpdateButton : public BoolOptionButton {
|
||||
RatingsUpdateButton() : BoolOptionButton("RatingsAutoUpdate", N_("Auto"), N_("Never"), this) {}
|
||||
};
|
||||
|
||||
class VideoModeButton : public TextButton {
|
||||
|
||||
video::VideoModes get_mode() const {
|
||||
int mode = Clamp(options::GetInt("VideoMode"), 0, int(video::VM_COUNT));
|
||||
return static_cast<video::VideoModes>(mode);
|
||||
}
|
||||
string get_text() const {
|
||||
return GetInfo(get_mode())->name;
|
||||
}
|
||||
void on_action(Widget *) {
|
||||
int mode = get_mode();
|
||||
|
||||
// cycle at most once through all available video modes
|
||||
do {
|
||||
mode += 1;
|
||||
if (mode >= video::VM_COUNT)
|
||||
mode = 0;
|
||||
|
||||
const video::VMInfo *vminfo = GetInfo (static_cast<video::VideoModes>(mode));
|
||||
if (vminfo->available) {
|
||||
options::SetOption("VideoMode", mode);
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
} while (mode != get_mode());
|
||||
}
|
||||
public:
|
||||
VideoModeButton() : TextButton(this) { }
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- SoundSetButton -------------------- */
|
||||
|
||||
SoundSetButton::SoundSetButton() : ValueButton(0, 1) {
|
||||
int numAvail = sound::GetOptionSoundSetCount();
|
||||
setMaxValue(numAvail - 1);
|
||||
init();
|
||||
}
|
||||
|
||||
int SoundSetButton::get_value() const {
|
||||
return sound::GetOptionSoundSet();
|
||||
}
|
||||
|
||||
void SoundSetButton::set_value(int value) {
|
||||
sound::SetOptionSoundSet(value);
|
||||
}
|
||||
|
||||
string SoundSetButton::get_text(int value) const {
|
||||
return _(sound::GetOptionSoundSetText(value).c_str());
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- StereoButton -------------------- */
|
||||
|
||||
StereoButton::StereoButton() : ValueButton(-1, 1)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
int StereoButton::get_value() const
|
||||
{
|
||||
double separation = options::GetDouble("StereoSeparation");
|
||||
if (separation == 0)
|
||||
return 0;
|
||||
else
|
||||
return (separation > 0) ? 1 : -1;
|
||||
}
|
||||
void StereoButton::set_value(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
options::SetOption("StereoSeparation", 0.0);
|
||||
else if (value > 0)
|
||||
options::SetOption("StereoSeparation", 10.0);
|
||||
else
|
||||
options::SetOption("StereoSeparation", -10.0);
|
||||
}
|
||||
|
||||
string StereoButton::get_text(int value) const
|
||||
{
|
||||
switch (value) {
|
||||
case -1: return _("reversed");
|
||||
case 0: return _("mono");
|
||||
case 1: return _("normal");
|
||||
}
|
||||
assert(0);
|
||||
return string();
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- FullscreenButton -------------------- */
|
||||
|
||||
FullscreenButton::FullscreenButton()
|
||||
: BoolOptionButton("FullScreen", N_("Yes"), N_("No"), this)
|
||||
{
|
||||
}
|
||||
|
||||
/* -------------------- LanguageButton -------------------- */
|
||||
|
||||
struct Language {
|
||||
const char *name;
|
||||
const char *localename;
|
||||
};
|
||||
|
||||
Language languages[] = {
|
||||
{ "default", "" },
|
||||
{ "Deutsch", "de_DE" },
|
||||
{ "English", "en_EN" },
|
||||
{ "Español", "es_ES" },
|
||||
{ "Français", "fr_FR" },
|
||||
{ "Italiano", "it_IT" },
|
||||
{ "Nederlands", "nl_NL" },
|
||||
{ "Svenska", "sv_SE" },
|
||||
{ "Русский", "ru_RU" },
|
||||
{ "Magyar", "hu_HU" },
|
||||
{ "Português", "pt_BR" },
|
||||
{ "Suomi", "fi_FI" },
|
||||
};
|
||||
|
||||
int LanguageButton::get_value() const
|
||||
{
|
||||
string localename; // = ecl::DefaultMessageLocale ();
|
||||
options::GetOption ("Language", localename);
|
||||
|
||||
int lang = 0; // unknown language
|
||||
for (size_t i=0; i<NUMENTRIES(languages); ++i) {
|
||||
if (localename == languages[i].localename)
|
||||
lang = int(i);
|
||||
}
|
||||
return lang;
|
||||
}
|
||||
|
||||
void LanguageButton::set_value(int value)
|
||||
{
|
||||
options::SetOption ("Language", languages[value].localename);
|
||||
|
||||
if ( not inInit) {
|
||||
// change language only on user action
|
||||
app.setLanguage(languages[value].localename);
|
||||
myListener->on_action(this);
|
||||
}
|
||||
}
|
||||
|
||||
string LanguageButton::get_text(int value) const
|
||||
{
|
||||
if (value == -1)
|
||||
return _("unknown");
|
||||
else
|
||||
return languages[value].name;
|
||||
}
|
||||
|
||||
LanguageButton::LanguageButton (ActionListener *al)
|
||||
: ValueButton(0, NUMENTRIES(languages)-1), myListener(al)
|
||||
{
|
||||
inInit = true;
|
||||
init();
|
||||
inInit = false;
|
||||
}
|
||||
|
||||
/* -------------------- GammaButton -------------------- */
|
||||
|
||||
|
||||
GammaButton::GammaButton()
|
||||
: ValueButton(1, 10)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void GammaButton::set_value(int value)
|
||||
{
|
||||
double gamma = double(value) / 5.0;
|
||||
options::SetOption ("Gamma", gamma);
|
||||
video::UpdateGamma();
|
||||
}
|
||||
|
||||
int GammaButton::get_value() const
|
||||
{
|
||||
double gamma = options::GetDouble ("Gamma");
|
||||
int value = round_down<int>(gamma * 5.0);
|
||||
return value;
|
||||
}
|
||||
|
||||
string GammaButton::get_text(int value) const
|
||||
{
|
||||
return ecl::strf ("%d", value-5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Options Menu -------------------- */
|
||||
|
||||
OptionsMenu::OptionsMenu(ecl::Surface *background_)
|
||||
: back(new StaticTextButton(N_("Back"), this)),
|
||||
fullscreen(new FullscreenButton),
|
||||
m_restartinfo (new Label("")),
|
||||
background(background_),
|
||||
previous_caption(video::GetCaption())
|
||||
{
|
||||
const int spacing = 5;
|
||||
const int big_spacing = 60;
|
||||
const int label_width = 180;
|
||||
const int but_width = 100;
|
||||
const int but_height = 30;
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
int hmargin = vminfo->width < 660 ? 10 : (vminfo->width < 900 ? 20 : 80);
|
||||
int midspacing = vminfo->width - 2*hmargin - 2*but_width - 2*label_width;
|
||||
|
||||
BuildVList leftlabels (this, Rect(-label_width, 0, label_width, but_height), spacing);
|
||||
BuildVList left (this, Rect(0, 0, but_width, but_height), spacing);
|
||||
BuildVList rightlabels (this, Rect(but_width+midspacing, 0, label_width, but_height), spacing);
|
||||
BuildVList right(this, Rect(but_width+midspacing+label_width, 0, but_width, but_height), spacing);
|
||||
leftlabels.add (new Label(N_("Language: "), HALIGN_RIGHT));
|
||||
leftlabels.add (new Label(N_("Fullscreen: "), HALIGN_RIGHT));
|
||||
leftlabels.add (new Label(N_("Video mode: "), HALIGN_RIGHT));
|
||||
leftlabels.add (new Label(N_("Gamma correction: "), HALIGN_RIGHT));
|
||||
leftlabels.add (new Label(N_("Mouse speed: "), HALIGN_RIGHT));
|
||||
|
||||
language = new LanguageButton(this);
|
||||
left.add (language);
|
||||
left.add (fullscreen);
|
||||
left.add (new VideoModeButton);
|
||||
left.add (new GammaButton);
|
||||
left.add (new MouseSpeedButton);
|
||||
|
||||
rightlabels.add (new Label(N_("Sound volume: "), HALIGN_RIGHT));
|
||||
rightlabels.add (new Label(N_("Sound set: "), HALIGN_RIGHT));
|
||||
rightlabels.add (new Label(N_("Music volume: "), HALIGN_RIGHT));
|
||||
rightlabels.add (new Label(N_("Stereo: "), HALIGN_RIGHT));
|
||||
rightlabels.add (new Label(N_("Ratings update: "), HALIGN_RIGHT));
|
||||
|
||||
right.add (new SoundVolumeButton);
|
||||
right.add (new SoundSetButton);
|
||||
right.add (new MusicVolumeButton);
|
||||
// right.add (new InGameMusicButton);Über
|
||||
right.add (new StereoButton);
|
||||
right.add (new RatingsUpdateButton);
|
||||
|
||||
Rect l = left.pos();
|
||||
Rect r = right.pos();
|
||||
|
||||
BuildVList bottomlabels (this, Rect(-label_width, Max(l.y, r.y), label_width, but_height), spacing);
|
||||
BuildVList bottom (this, Rect(0, Max(l.y, r.y), vminfo->width - 2*hmargin - label_width, but_height), spacing);
|
||||
bottomlabels.add (new Label(N_("User name: "), HALIGN_RIGHT));
|
||||
bottomlabels.add (new Label(N_("User path: "), HALIGN_RIGHT));
|
||||
bottomlabels.add (new Label(N_("User image path: "), HALIGN_RIGHT));
|
||||
userNameTF = new TextField(app.state->getString("UserName"));
|
||||
userNameTF->setMaxChars(20);
|
||||
userNameTF->setInvalidChars("+");
|
||||
bottom.add (userNameTF);
|
||||
userPathTF = new TextField(XMLtoUtf8(LocalToXML(app.userPath.c_str()).x_str()).c_str());
|
||||
bottom.add (userPathTF);
|
||||
userImagePathTF = new TextField(XMLtoUtf8(LocalToXML(app.userImagePath.c_str()).x_str()).c_str());
|
||||
bottom.add (userImagePathTF);
|
||||
|
||||
// add (m_restartinfo, Rect (l.x, l.y + 15, 400, 20));
|
||||
// m_restartinfo->set_alignment (HALIGN_LEFT);
|
||||
// update_info();
|
||||
|
||||
Rect b = bottom.pos();
|
||||
l.x = (l.x+r.x)/2;
|
||||
l.y = b.y+big_spacing;
|
||||
|
||||
add(back, l);
|
||||
}
|
||||
|
||||
OptionsMenu::~OptionsMenu() {
|
||||
video::SetCaption(previous_caption.c_str());
|
||||
}
|
||||
|
||||
// void OptionsMenu::update_info()
|
||||
// {
|
||||
// if (options::MustRestart)
|
||||
// m_restartinfo->set_text (
|
||||
// N_("Please restart Enigma to activate your changes!"));
|
||||
// else
|
||||
// m_restartinfo->set_text ("");
|
||||
// }
|
||||
|
||||
void OptionsMenu::quit() {
|
||||
std::string tfUserPathLocal = XMLtoLocal(Utf8ToXML(userPathTF->getText().c_str()).x_str()).c_str();
|
||||
std::string tfUserImageLocal = XMLtoLocal(Utf8ToXML(userImagePathTF->getText().c_str()).x_str()).c_str();
|
||||
if ((app.state->getString("UserName") != userNameTF->getText())
|
||||
|| (app.userPath != tfUserPathLocal ) || (app.userImagePath != tfUserImageLocal)) {
|
||||
// ensure that enigma.score is saved with new Username or to new location
|
||||
lev::ScoreManager::instance()->markModified();
|
||||
}
|
||||
// strip off leading and trailing whitespace from user name
|
||||
std::string userName = userNameTF->getText();
|
||||
std::string::size_type firstChar = userName.find_first_not_of(" ");
|
||||
std::string::size_type lastChar = userName.find_last_not_of(" ");
|
||||
if (firstChar != std::string::npos)
|
||||
app.state->setProperty("UserName", userName.substr(firstChar, lastChar - firstChar + 1));
|
||||
else
|
||||
app.state->setProperty("UserName", std::string(""));
|
||||
app.setUserPath(tfUserPathLocal.c_str());
|
||||
app.setUserImagePath(tfUserImageLocal.c_str());
|
||||
Menu::quit();
|
||||
}
|
||||
|
||||
bool OptionsMenu::on_event (const SDL_Event &e)
|
||||
{
|
||||
bool handled=false;
|
||||
if (e.type == SDL_MOUSEBUTTONDOWN
|
||||
&& e.button.button == SDL_BUTTON_RIGHT)
|
||||
{
|
||||
quit();
|
||||
handled = true;
|
||||
}
|
||||
else if (e.type == SDL_KEYUP) {
|
||||
if ((e.key.keysym.sym==SDLK_RETURN) &&
|
||||
(e.key.keysym.mod & KMOD_ALT))
|
||||
{
|
||||
// update state of FullscreenButton :
|
||||
fullscreen->invalidate();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
void OptionsMenu::on_action(Widget *w)
|
||||
{
|
||||
if (w == back)
|
||||
quit();
|
||||
else if (w == language)
|
||||
// language changed - retranslate and redraw everything
|
||||
invalidate_all();
|
||||
}
|
||||
|
||||
void OptionsMenu::tick (double)
|
||||
{
|
||||
// update_info();
|
||||
}
|
||||
|
||||
void OptionsMenu::draw_background(ecl::GC &gc)
|
||||
{
|
||||
video::SetCaption(("Enigma - Options Menu"));
|
||||
// blit(gc, 0,0, enigma::GetImage("menu_bg"));
|
||||
blit(gc, 0,0, background);
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void ShowOptionsMenu(Surface *background) {
|
||||
if (background == 0)
|
||||
background = enigma::GetImage("menu_bg", ".jpg");
|
||||
OptionsMenu m(background);
|
||||
m.center();
|
||||
m.manage();
|
||||
}
|
||||
|
||||
}} // namespace enigma::gui
|
||||
|
||||
104
project/jni/application/enigma/src/gui/OptionsMenu.hh
Normal file
104
project/jni/application/enigma/src/gui/OptionsMenu.hh
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004,2005,2006 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef GUI_OPTIONSMENU_HH_INCLUDED
|
||||
#define GUI_OPTIONSMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
/* -------------------- OptionsMenu -------------------- */
|
||||
|
||||
class OptionsMenu : public Menu {
|
||||
public:
|
||||
OptionsMenu(ecl::Surface *background_);
|
||||
~OptionsMenu();
|
||||
virtual void quit();
|
||||
private:
|
||||
void update_info();
|
||||
|
||||
// ActionListener interface.
|
||||
bool on_event (const SDL_Event &e);
|
||||
void on_action(gui::Widget *w);
|
||||
|
||||
// Menu interface.
|
||||
void draw_background(ecl::GC &gc);
|
||||
void tick(double dtime);
|
||||
|
||||
// Variables.
|
||||
gui::Widget *back, *fullscreen, *language;
|
||||
gui::TextField *userNameTF;
|
||||
gui::TextField *userPathTF;
|
||||
gui::TextField *userImagePathTF;
|
||||
gui::Label *m_restartinfo;
|
||||
ecl::Surface *background;
|
||||
std::string previous_caption;
|
||||
};
|
||||
|
||||
/* -------------------- Options Buttons -------------------- */
|
||||
|
||||
struct FullscreenButton : public BoolOptionButton {
|
||||
FullscreenButton();
|
||||
};
|
||||
|
||||
|
||||
class StereoButton : public ValueButton {
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
public:
|
||||
StereoButton();
|
||||
};
|
||||
|
||||
|
||||
class SoundSetButton : public ValueButton {
|
||||
public:
|
||||
SoundSetButton();
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
};
|
||||
|
||||
class LanguageButton : public ValueButton {
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
bool inInit;
|
||||
ActionListener *myListener;
|
||||
public:
|
||||
// second user action listener: first one is misused by ValueButton
|
||||
LanguageButton (ActionListener *al = 0);
|
||||
|
||||
};
|
||||
|
||||
class GammaButton : public ValueButton {
|
||||
int get_value() const;
|
||||
void set_value(int value);
|
||||
std::string get_text(int value) const;
|
||||
public:
|
||||
GammaButton ();
|
||||
|
||||
};
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void ShowOptionsMenu(ecl::Surface *background);
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
109
project/jni/application/enigma/src/gui/ScreenshotViewer.cpp
Normal file
109
project/jni/application/enigma/src/gui/ScreenshotViewer.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/ScreenshotViewer.hh"
|
||||
#include "gui/HelpMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "main.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
static const char *helptext[] = {
|
||||
N_("Escape:"), N_("Back"),
|
||||
"F1:", N_("Show this help"),
|
||||
N_("Page Up:"), N_("Show previous screenshot"),
|
||||
N_("Page Down:"), N_("Show next screenshot"),
|
||||
0
|
||||
};
|
||||
|
||||
ScreenshotViewer::ScreenshotViewer(lev::Proxy *aLevel) :
|
||||
levelProxy (aLevel), shotNumber (0) {
|
||||
}
|
||||
|
||||
ScreenshotViewer::~ScreenshotViewer() {
|
||||
}
|
||||
|
||||
bool ScreenshotViewer::on_event (const SDL_Event &e) {
|
||||
switch (e.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (e.button.button == SDL_BUTTON_RIGHT) {
|
||||
Menu::quit();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
SDLKey keysym = e.key.keysym.sym;
|
||||
switch (keysym) {
|
||||
case SDLK_PAGEUP:
|
||||
if (shotNumber > 0 )
|
||||
--shotNumber;
|
||||
invalidate_all();
|
||||
return true;
|
||||
case SDLK_PAGEDOWN:
|
||||
shotNumber++;
|
||||
invalidate_all();
|
||||
return true;
|
||||
// eat up widget activation keys - we have no widgets
|
||||
case SDLK_DOWN:
|
||||
case SDLK_UP:
|
||||
case SDLK_RIGHT:
|
||||
case SDLK_LEFT:
|
||||
return true;
|
||||
case SDLK_F1:
|
||||
displayHelp(helptext, 200);
|
||||
invalidate_all();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScreenshotViewer::draw_background (ecl::GC &gc) {
|
||||
std::string filename = "screenshots/" +
|
||||
levelProxy->getLocalSubstitutionLevelPath() +
|
||||
(shotNumber > 0 ? ecl::strf("#%d", shotNumber) : "") + ".png";
|
||||
std::string fullPath;
|
||||
if (app.resourceFS->findFile(filename, fullPath)) {
|
||||
const video::VMInfo *vminfo = video::GetInfo();
|
||||
ecl::Surface * image = ecl::LoadImage(fullPath.c_str());
|
||||
if (image->width() == vminfo->width && image->height() == vminfo->height) {
|
||||
blit(gc, 0,0, image);
|
||||
} else {
|
||||
ecl::Surface * imageZoomed = image->zoom(vminfo->width, vminfo->height);
|
||||
blit(gc, 0,0, imageZoomed);
|
||||
delete imageZoomed;
|
||||
}
|
||||
delete image;
|
||||
} else {
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
Font *f = enigma::GetFont("menufont");
|
||||
f->render (gc, 30, 60, _("No screenshot available:"));
|
||||
f->render (gc, 30, 100, filename.c_str());
|
||||
}
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
49
project/jni/application/enigma/src/gui/ScreenshotViewer.hh
Normal file
49
project/jni/application/enigma/src/gui/ScreenshotViewer.hh
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GUI_SCREENSHOTVIEWER_HH_INCLUDED
|
||||
#define GUI_SCREENSHOTVIEWER_HH_INCLUDED
|
||||
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/**
|
||||
* TODO delete CTRL-D with confirmation panel - rename of following shots?
|
||||
* TODO shift up, down for reorder/rename of shots
|
||||
*/
|
||||
class ScreenshotViewer : public gui::Menu {
|
||||
public:
|
||||
ScreenshotViewer (lev::Proxy *aLevel);
|
||||
~ScreenshotViewer ();
|
||||
|
||||
// Widget interface
|
||||
virtual bool on_event (const SDL_Event &e);
|
||||
protected:
|
||||
// Menu interface.
|
||||
virtual void draw_background (ecl::GC &gc);
|
||||
private:
|
||||
lev::Proxy *levelProxy;
|
||||
std::string basePath;
|
||||
int shotNumber;
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
91
project/jni/application/enigma/src/gui/SearchMenu.cpp
Normal file
91
project/jni/application/enigma/src/gui/SearchMenu.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/SearchMenu.hh"
|
||||
#include "ecl.hh"
|
||||
#include "enigma.hh"
|
||||
#include "errors.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
#include "nls.hh"
|
||||
#include "video.hh"
|
||||
|
||||
#include "main.hh"
|
||||
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
SearchMenu::SearchMenu() : didSearch (false) {
|
||||
const video::VMInfo &vminfo = *video::GetInfo();
|
||||
ecl::Font *menufont = enigma::GetFont("menufont");
|
||||
|
||||
Label * shallowTitle = new Label(N_("Shallow Search:"), HALIGN_LEFT);
|
||||
// TRANSLATORS: the translation can have double size of the english text
|
||||
std::string helpText = _("case independent search in title, author, filename");
|
||||
std::string workString = helpText;
|
||||
std::string::size_type breakPos = breakString(menufont, workString,
|
||||
" ", 380);
|
||||
Label * shallowHelp1 = new UntranslatedLabel(workString.substr(0,breakPos), HALIGN_LEFT);
|
||||
Label * shallowHelp2 = new UntranslatedLabel(workString.substr(breakPos), HALIGN_LEFT);
|
||||
shallowSearch = new TextField("", this);
|
||||
|
||||
this->add(shallowTitle, Rect(vminfo.width/2 - 190, vminfo.height/2 - 100, 380, 35));
|
||||
this->add(shallowHelp1, Rect(vminfo.width/2 - 190, vminfo.height/2 - 40, 380, 25));
|
||||
this->add(shallowHelp2, Rect(vminfo.width/2 - 190, vminfo.height/2 - 10, 380, 25));
|
||||
this->add(shallowSearch, Rect(vminfo.width/2 - 190, vminfo.height/2 + 55, 380, 35));
|
||||
|
||||
// Create buttons - positioning identical to Levelmenu
|
||||
Label * dummy1 = new Label();
|
||||
Label * dummy2 = new Label();
|
||||
but_ignore = new StaticTextButton(N_("Undo"), this);
|
||||
but_search = new StaticTextButton(N_("Search"), this);
|
||||
|
||||
HList * commandHList = new HList;
|
||||
commandHList->set_spacing(10);
|
||||
commandHList->set_alignment(HALIGN_CENTER, VALIGN_TOP);
|
||||
commandHList->set_default_size(140, 35);
|
||||
commandHList->add_back(dummy1);
|
||||
commandHList->add_back(dummy2);
|
||||
commandHList->add_back(but_ignore);
|
||||
commandHList->add_back(but_search);
|
||||
this->add(commandHList, Rect(10, vminfo.height-50, vminfo.width-20, 35));
|
||||
}
|
||||
|
||||
bool SearchMenu::isSearchQuit() {
|
||||
return didSearch;
|
||||
}
|
||||
|
||||
void SearchMenu::on_action(Widget *w) {
|
||||
if (w == but_search ||
|
||||
(w == shallowSearch && shallowSearch->wasLastActionReturn())) {
|
||||
lev::Index::setCurrentIndex(lev::Proxy::search(shallowSearch->getText()));
|
||||
didSearch = true;
|
||||
Menu::quit();
|
||||
} else if (w == but_ignore) {
|
||||
Menu::quit();
|
||||
}
|
||||
}
|
||||
|
||||
void SearchMenu::draw_background(ecl::GC &gc) {
|
||||
video::SetCaption(("Enigma - Search Menu"));
|
||||
blit(gc, 0,0, enigma::GetImage("menu_bg", ".jpg"));
|
||||
}
|
||||
}} // namespace enigma::gui
|
||||
43
project/jni/application/enigma/src/gui/SearchMenu.hh
Normal file
43
project/jni/application/enigma/src/gui/SearchMenu.hh
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GUI_SEARCHMENU_HH_INCLUDED
|
||||
#define GUI_SEARCHMENU_HH_INCLUDED
|
||||
|
||||
#include "gui/Menu.hh"
|
||||
#include "gui/TextField.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
class SearchMenu : public gui::Menu {
|
||||
public:
|
||||
SearchMenu ();
|
||||
|
||||
void on_action(Widget *w);
|
||||
void draw_background(ecl::GC &gc);
|
||||
bool isSearchQuit();
|
||||
|
||||
private:
|
||||
TextField *shallowSearch;
|
||||
Widget *but_ignore;
|
||||
Widget *but_search;
|
||||
bool didSearch;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
281
project/jni/application/enigma/src/gui/TextField.cpp
Normal file
281
project/jni/application/enigma/src/gui/TextField.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "main.hh"
|
||||
#include "gui/widgets.hh"
|
||||
#include "gui/TextField.hh"
|
||||
#include "ecl_utf.hh"
|
||||
#include "enigma.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "options.hh"
|
||||
#include "nls.hh"
|
||||
#include "ecl.hh"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
using namespace enigma::gui;
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
#define SCREEN ecl::Screen::get_instance()
|
||||
|
||||
ecl::Font *TextField::menufont = 0;
|
||||
|
||||
TextField::TextField(const std::string &t, ActionListener *al) : cursorTime(0),
|
||||
showCursor(true), isLastActionReturn (false), invalidChars(""),
|
||||
isLimitedToValidChars(false), maxChars(-1) {
|
||||
if (menufont == 0) {
|
||||
menufont = enigma::GetFont("menufont");
|
||||
}
|
||||
set_listener(al);
|
||||
textPreCursor = t;
|
||||
ecl::utf8CharSizes(textPreCursor, charSizesPreCursor);
|
||||
textPostCursor= "";
|
||||
}
|
||||
|
||||
void TextField::set_text(const std::string &t) {
|
||||
textPreCursor = t;
|
||||
charSizesPreCursor.clear();
|
||||
ecl::utf8CharSizes(textPreCursor, charSizesPreCursor);
|
||||
textPostCursor= "";
|
||||
charSizesPostCursor.clear();
|
||||
}
|
||||
|
||||
std::string TextField::getText() {
|
||||
string total = textPreCursor;
|
||||
total += textPostCursor;
|
||||
return total;
|
||||
}
|
||||
|
||||
void TextField::setInvalidChars(std::string forbiddenChars) {
|
||||
invalidChars = forbiddenChars;
|
||||
}
|
||||
|
||||
void TextField::setMaxChars(int max) {
|
||||
maxChars = max;
|
||||
}
|
||||
bool TextField::wasLastActionReturn() {
|
||||
return isLastActionReturn;
|
||||
}
|
||||
|
||||
void TextField::tick (double dtime) {
|
||||
cursorTime += dtime;
|
||||
if (cursorTime > 0.5) {
|
||||
cursorTime = 0.0;
|
||||
showCursor = !showCursor;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void TextField::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
Button::draw(gc,r);
|
||||
Font *f = menufont;
|
||||
int h = f->get_height();
|
||||
int w_pre = f->get_width(textPreCursor.c_str());
|
||||
int w_post = f->get_width(textPostCursor.c_str());
|
||||
int w_cursor = m_activep ? 1 : 0;
|
||||
int x = get_x() + (get_w()- w_pre - w_post - w_cursor )/2;
|
||||
int y = get_y() + (get_h()-h)/2;
|
||||
|
||||
// cursor always visible
|
||||
if (x + w_pre < get_x() + 5)
|
||||
// cursor would be left of textfield - shift centered text right
|
||||
x = get_x() + 5 - w_pre;
|
||||
|
||||
if (x + w_pre > get_x() + get_w() - 5)
|
||||
// cursor would be right of textfiled - shift centered text left
|
||||
x = get_x() + get_w() - 5 - w_pre;
|
||||
|
||||
f->render (gc, x, y, textPreCursor.c_str());
|
||||
|
||||
x += w_pre;
|
||||
if (m_activep) {
|
||||
if (showCursor) {
|
||||
set_color(gc, 200,200,200);
|
||||
vline(gc, x, y, h);
|
||||
}
|
||||
x += w_cursor;
|
||||
}
|
||||
|
||||
f->render (gc, x, y, textPostCursor.c_str());
|
||||
|
||||
}
|
||||
|
||||
bool TextField::on_event(const SDL_Event &e) {
|
||||
bool handeled = false;
|
||||
bool modified = false;
|
||||
|
||||
switch (e.type) {
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
// set cursor
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_RETURN:
|
||||
handeled = true;
|
||||
isLastActionReturn = true;
|
||||
invoke_listener();
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
if(textPostCursor.size() > 0) {
|
||||
int size = charSizesPostCursor.back();
|
||||
charSizesPostCursor.pop_back();
|
||||
charSizesPreCursor.push_back(size);
|
||||
textPreCursor.append(textPostCursor, 0, size);
|
||||
textPostCursor.erase(0, size);
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
if(textPreCursor.size() > 0) {
|
||||
int size = charSizesPreCursor.back();
|
||||
charSizesPreCursor.pop_back();
|
||||
charSizesPostCursor.push_back(size);
|
||||
textPostCursor.insert(0, textPreCursor.substr(textPreCursor.size() - size));
|
||||
textPreCursor.erase(textPreCursor.size() - size);
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_INSERT:
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_HOME:
|
||||
if(textPreCursor.size() > 0) {
|
||||
int i;
|
||||
int preChars = charSizesPreCursor.size();
|
||||
for (i = 0; i < preChars; i++) {
|
||||
int size = charSizesPreCursor.back();
|
||||
charSizesPreCursor.pop_back();
|
||||
charSizesPostCursor.push_back(size);
|
||||
}
|
||||
textPostCursor.insert(0, textPreCursor);
|
||||
textPreCursor.clear();
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_END:
|
||||
if(textPostCursor.size() > 0) {
|
||||
int size;
|
||||
int i;
|
||||
int postChars = charSizesPostCursor.size();
|
||||
for (i = 0; i < postChars; i++) {
|
||||
size = charSizesPostCursor.back();
|
||||
charSizesPostCursor.pop_back();
|
||||
charSizesPreCursor.push_back(size);
|
||||
}
|
||||
textPreCursor.append(textPostCursor);
|
||||
textPostCursor.clear();
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
break;
|
||||
case SDLK_DELETE:
|
||||
if(textPostCursor.size() > 0) {
|
||||
int size = charSizesPostCursor.back();
|
||||
textPostCursor.erase(0, size);
|
||||
charSizesPostCursor.pop_back();
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
modified = true;
|
||||
break;
|
||||
case SDLK_BACKSPACE:
|
||||
if(textPreCursor.size() > 0) {
|
||||
int size = charSizesPreCursor.back();
|
||||
textPreCursor.erase(textPreCursor.size() - size);
|
||||
charSizesPreCursor.pop_back();
|
||||
}
|
||||
invalidate();
|
||||
handeled = true;
|
||||
modified = true;
|
||||
break;
|
||||
case SDLK_ESCAPE:
|
||||
case SDLK_DOWN:
|
||||
case SDLK_UP:
|
||||
// menu active widget movements
|
||||
break;
|
||||
default:
|
||||
// get char
|
||||
if (e.key.keysym.unicode != 0 ) {
|
||||
UTF16 realChar;
|
||||
if (e.key.keysym.unicode >= 0x20 &&
|
||||
(e.key.keysym.unicode < 0x80 || // key pad
|
||||
e.key.keysym.sym < 0x80)) { // windows umlaute
|
||||
// the unicode is correct in these cases
|
||||
realChar = e.key.keysym.unicode;
|
||||
}
|
||||
else if (e.key.keysym.unicode >= 0x80 &&
|
||||
e.key.keysym.sym < 0x100) {
|
||||
// Linux: bad unicode but sym is ISO-8859-1
|
||||
|
||||
// incomplete workaround - runs only for some lower
|
||||
// case umlauts
|
||||
// we would need to handle shift key in language
|
||||
// dependent manner -- or fix SDL Linux
|
||||
realChar = e.key.keysym.sym;
|
||||
}
|
||||
else {
|
||||
// chars like ctrl-a - ctrl-z
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
break;
|
||||
}
|
||||
if ((maxChars >= 0 && (charSizesPreCursor.size() + charSizesPostCursor.size()) >= maxChars) ||
|
||||
realChar < 0x100 && invalidChars.find((char)realChar) != std::string::npos) {
|
||||
// string too long or invalid char
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
break;
|
||||
}
|
||||
unsigned char utf8Char[4];
|
||||
UTF16 const * utf16Ptr = (UTF16 *)&realChar;
|
||||
UTF8 * utf8Ptr = utf8Char;
|
||||
ConversionResult result;
|
||||
result = ConvertUTF16toUTF8 (&utf16Ptr, utf16Ptr + 1,
|
||||
&utf8Ptr, utf8Char + 4, strictConversion);
|
||||
*utf8Ptr = 0;
|
||||
textPreCursor += (const char *)utf8Char;
|
||||
charSizesPreCursor.push_back(utf8Ptr - utf8Char);
|
||||
|
||||
invalidate();
|
||||
handeled = true;
|
||||
modified = true;
|
||||
break;
|
||||
}
|
||||
if (e.key.keysym.sym < 300 || e.key.keysym.sym > 314 ){
|
||||
// chars like PageUp, F1 but not key state modifier
|
||||
// like shift, alt,...
|
||||
sound::EmitSoundEvent ("menustop");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (modified) {
|
||||
isLastActionReturn = false;
|
||||
invoke_listener();
|
||||
}
|
||||
return handeled;
|
||||
}
|
||||
|
||||
96
project/jni/application/enigma/src/gui/TextField.hh
Normal file
96
project/jni/application/enigma/src/gui/TextField.hh
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GUI_TF_HH_INCLUDED
|
||||
#define GUI_TF_HH_INCLUDED
|
||||
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
/**
|
||||
* Gui widget for simple text insertion. Cursor keys, backspace and delete,
|
||||
* home and end are supported. As a widget it handels utf-8 strings. But
|
||||
* in contrast to other widget there is of course no gettext l10n translation.
|
||||
* This widget is designed to be part of a menu.
|
||||
* <par>
|
||||
* ToDo: supply full Linux umlaut support;
|
||||
* add hook for external or subclass char insertion validation
|
||||
* (NumberField, ...);
|
||||
* move mouse cursor out of Textfield without deselection
|
||||
*/
|
||||
class TextField : public Button {
|
||||
public:
|
||||
/**
|
||||
* Creates a boarderd text input field.
|
||||
* @param t preset utf-8 input string
|
||||
* @param al currently unused
|
||||
*/
|
||||
TextField(const std::string &t = "", ActionListener *al=0);
|
||||
|
||||
/**
|
||||
* resets the input string.
|
||||
* @param t new utf-8 input string
|
||||
*/
|
||||
void set_text(const std::string &t);
|
||||
|
||||
/**
|
||||
* returns the inserted text
|
||||
* @return the utf-8 coded string
|
||||
*/
|
||||
std::string getText();
|
||||
|
||||
void setInvalidChars(std::string forbiddenChars); // currently limited to 1st coding page
|
||||
void setMaxChars(int max);
|
||||
bool wasLastActionReturn();
|
||||
|
||||
// Widget interface.
|
||||
virtual void tick (double dtime);
|
||||
virtual bool on_event(const SDL_Event &/*e*/);
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
|
||||
protected:
|
||||
double cursorTime;
|
||||
bool showCursor;
|
||||
|
||||
private:
|
||||
std::string textPreCursor;
|
||||
std::string textPostCursor;
|
||||
/**
|
||||
* a byte vector describing for each utf-8 character the number of
|
||||
* occupied bytes in the string.
|
||||
*/
|
||||
std::vector<unsigned char> charSizesPreCursor;
|
||||
|
||||
/**
|
||||
* a byte vector describing for each utf-8 character the number of
|
||||
* occupied bytes in the string. This vector is in reverse order to
|
||||
* the string itself!!
|
||||
*/
|
||||
std::vector<unsigned char> charSizesPostCursor;
|
||||
bool isLimitedToValidChars;
|
||||
std::string validChars;
|
||||
std::string invalidChars;
|
||||
int maxChars;
|
||||
bool isLastActionReturn;
|
||||
static ecl::Font *menufont;
|
||||
};
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
943
project/jni/application/enigma/src/gui/widgets.cpp
Normal file
943
project/jni/application/enigma/src/gui/widgets.cpp
Normal file
@@ -0,0 +1,943 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/widgets.hh"
|
||||
#include "enigma.hh"
|
||||
#include "sound.hh"
|
||||
#include "video.hh"
|
||||
#include "options.hh"
|
||||
#include "nls.hh"
|
||||
#include "ecl.hh"
|
||||
#include "ecl_font.hh"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <climits>
|
||||
|
||||
using namespace enigma::gui;
|
||||
using namespace ecl;
|
||||
using namespace std;
|
||||
|
||||
#define SCREEN ecl::Screen::get_instance()
|
||||
|
||||
/* -------------------- Widget -------------------- */
|
||||
|
||||
Widget::Widget(Container *parent)
|
||||
: area(), m_parent(parent), m_listener(0)
|
||||
{}
|
||||
|
||||
void Widget::invalidate() {
|
||||
if (m_parent)
|
||||
m_parent->invalidate_area(get_area());
|
||||
}
|
||||
void Widget::invalidate_area(const ecl::Rect& r) {
|
||||
if (m_parent)
|
||||
m_parent->invalidate_area(r);
|
||||
}
|
||||
|
||||
void Widget::reconfigure()
|
||||
{
|
||||
if (m_parent)
|
||||
m_parent->reconfigure_child(this);
|
||||
}
|
||||
|
||||
void Widget::invoke_listener() {
|
||||
if (m_listener)
|
||||
m_listener->on_action(this);
|
||||
}
|
||||
|
||||
void Widget::move(int x, int y) {
|
||||
area.x = x; area.y = y;
|
||||
}
|
||||
|
||||
void Widget::resize (int w, int h) {
|
||||
area.w = w; area.h = h;
|
||||
}
|
||||
|
||||
bool Widget::on_event(const SDL_Event &e) {
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
modifierKeys = e.key.keysym.mod;
|
||||
mouseButton = SDL_BUTTON_LEFT;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
modifierKeys = SDL_GetModState();
|
||||
mouseButton = e.button.button;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------- Image -------------------- */
|
||||
|
||||
void Image::draw (ecl::GC &gc, const ecl::Rect &/*r*/) {
|
||||
// if (ecl::Surface *s = enigma::GetImage(imgname.c_str()))
|
||||
// blit(gc, get_x(), get_y(), s);
|
||||
if (ecl::Surface *s = enigma::GetImage(imgname.c_str())) {
|
||||
int w=s->width();
|
||||
int h=s->height();
|
||||
int x = get_x() + (get_w()-w)/2;
|
||||
int y = get_y() + (get_h()-h)/2;
|
||||
blit(gc, x, y, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- AreaManager -------------------- */
|
||||
|
||||
AreaManager::AreaManager(Container *c)
|
||||
: top_container(c)
|
||||
{
|
||||
assert(top_container->get_parent() == 0); // otherwise it's not the top_container
|
||||
}
|
||||
|
||||
void AreaManager::invalidate_area(const ecl::Rect &r) {
|
||||
dirtyrects.add(r);
|
||||
}
|
||||
|
||||
void AreaManager::invalidate_all() {
|
||||
dirtyrects.clear();
|
||||
dirtyrects.push_back(SCREEN->size());
|
||||
}
|
||||
|
||||
void AreaManager::refresh() {
|
||||
if (!dirtyrects.empty()) {
|
||||
video::HideMouse();
|
||||
GC gc(SCREEN->get_surface());
|
||||
for (RectList::iterator i = dirtyrects.begin(); i!=dirtyrects.end(); ++i) {
|
||||
top_container->draw(gc, *i);
|
||||
SCREEN->update_rect(*i);
|
||||
}
|
||||
video::ShowMouse();
|
||||
dirtyrects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------- Container -------------------- */
|
||||
|
||||
Container::Container()
|
||||
: managed_by(0)
|
||||
{
|
||||
}
|
||||
Container::~Container() {
|
||||
clear();
|
||||
delete managed_by;
|
||||
}
|
||||
|
||||
AreaManager *Container::getAreaManager() {
|
||||
if (Container *p = get_parent()) {
|
||||
assert(!managed_by);
|
||||
return p->getAreaManager();
|
||||
}
|
||||
|
||||
if (!managed_by) {
|
||||
managed_by = new AreaManager(this);
|
||||
}
|
||||
return managed_by;
|
||||
}
|
||||
|
||||
void Container::invalidate_area(const ecl::Rect &r) { getAreaManager()->invalidate_area(r); }
|
||||
void Container::invalidate_all() { getAreaManager()->invalidate_all(); }
|
||||
void Container::refresh() { getAreaManager()->refresh(); }
|
||||
|
||||
void Container::clear() {
|
||||
delete_sequence(m_widgets.begin(), m_widgets.end());
|
||||
m_widgets.clear();
|
||||
}
|
||||
|
||||
void Container::add_child (Widget *w) {
|
||||
if (w && w != this) {
|
||||
m_widgets.push_back(w);
|
||||
w->set_parent(this);
|
||||
// w->move (get_x() + w->get_x(),
|
||||
// get_y() + w->get_y());
|
||||
}
|
||||
}
|
||||
|
||||
void Container::remove_child (Widget *w) {
|
||||
for (iterator it = begin(); it != end(); it++) {
|
||||
if (*it == w) {
|
||||
m_widgets.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Container::exchange_child (Widget *oldChild, Widget *newChild) {
|
||||
for (int i = 0; i < m_widgets.size(); i++) {
|
||||
if (m_widgets[i] == oldChild) {
|
||||
m_widgets[i] = newChild;
|
||||
newChild->set_parent(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Container::draw (ecl::GC& gc, const ecl::Rect &r) {
|
||||
for (iterator i=begin(); i!=end(); ++i) {
|
||||
Widget *w = *i;
|
||||
Rect rr = intersect(r, w->get_area());
|
||||
clip(gc, rr);
|
||||
w->draw(gc,rr);
|
||||
}
|
||||
}
|
||||
|
||||
void Container::draw_all() {
|
||||
invalidate_all();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void Container::reconfigure_child (Widget *)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Widget * Container::find_widget(int x, int y) {
|
||||
for (iterator i=begin(); i!=end(); ++i) {
|
||||
Widget *w = *i;
|
||||
if (w->get_area().contains(x,y)) {
|
||||
Container *c = dynamic_cast<Container *> (w);
|
||||
if (c) {
|
||||
w = c->find_widget (x, y);
|
||||
return w ? w : c;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Widget * Container::find_adjacent_widget(Widget *from, int x, int y) {
|
||||
// valid values for x/y : 1/0, -1/0, 0/1, 0/-1
|
||||
assert(from && x>=-1 && x<=1 && y>=-1 && y<=1 && abs(x+y) == 1);
|
||||
|
||||
if (!from) return 0;
|
||||
|
||||
int best_distance = INT_MAX;
|
||||
Widget *best_widget = 0;
|
||||
ecl::Rect farea = from->get_area();
|
||||
|
||||
for (iterator i=begin(); i!=end(); ++i) {
|
||||
Widget *w = *i;
|
||||
ecl::Rect warea = w->get_area();
|
||||
bool adjacent = true;
|
||||
int distance = 0;
|
||||
|
||||
if (x) { // check for y-overlap
|
||||
if (farea.y>(warea.y+warea.h-1) || warea.y>(farea.y+farea.h-1)) {
|
||||
adjacent = false;
|
||||
}
|
||||
else {
|
||||
distance = (warea.x-farea.x)*x;
|
||||
}
|
||||
}
|
||||
else { // check for x-overlap
|
||||
if (farea.x>(warea.x+warea.h-1) || warea.x>(farea.x+farea.h-1)) {
|
||||
adjacent = false;
|
||||
}
|
||||
else {
|
||||
distance = (warea.y-farea.y)*y;
|
||||
}
|
||||
}
|
||||
|
||||
if (adjacent && distance>0 && distance<best_distance) {
|
||||
best_distance = distance;
|
||||
best_widget = w;
|
||||
}
|
||||
}
|
||||
|
||||
return best_widget;
|
||||
}
|
||||
|
||||
void Container::move (int x, int y) {
|
||||
Rect a = get_area();
|
||||
a.x = x;
|
||||
a.y = y;
|
||||
this->set_area (a);
|
||||
|
||||
int dx = x-get_x();
|
||||
int dy = y-get_y();
|
||||
|
||||
for (iterator i=begin(); i!=end(); ++i) {
|
||||
Widget *w = *i;
|
||||
w->move(dx + w->get_x(), dy+w->get_y());
|
||||
}
|
||||
}
|
||||
|
||||
ecl::Rect Container::boundingbox() {
|
||||
if (!m_widgets.empty()) {
|
||||
iterator i=begin();
|
||||
Rect bbox=(*i)->get_area();
|
||||
for (++i; i!=end(); ++i)
|
||||
bbox = ecl::boundingbox(bbox, (*i)->get_area());
|
||||
return bbox;
|
||||
} else
|
||||
return get_area();
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- List -------------------- */
|
||||
|
||||
List::List (int spacing)
|
||||
: m_spacing(spacing),
|
||||
has_default_size (false),
|
||||
defaultw (0),
|
||||
defaulth (0),
|
||||
m_halign (HALIGN_LEFT),
|
||||
m_valign (VALIGN_TOP)
|
||||
{}
|
||||
|
||||
void List::remove_child (Widget *w) {
|
||||
Container::remove_child(w);
|
||||
recalc();
|
||||
}
|
||||
|
||||
void List::exchange_child(Widget *oldChild, Widget *newChild) {
|
||||
Container::exchange_child(oldChild, newChild);
|
||||
recalc();
|
||||
}
|
||||
|
||||
void List::set_spacing (int pixels)
|
||||
{
|
||||
m_spacing = pixels;
|
||||
}
|
||||
|
||||
int List::get_spacing () const
|
||||
{
|
||||
return m_spacing;
|
||||
}
|
||||
|
||||
int List::calc_minimum_height() const
|
||||
{
|
||||
int sum=0;
|
||||
const WidgetList &wl = m_widgets;
|
||||
if (!wl.empty()) {
|
||||
sum = (wl.size() - 1) * m_spacing;
|
||||
for (WidgetList::const_iterator i=wl.begin(); i!=wl.end(); ++i) {
|
||||
int nw, nh;
|
||||
get_size (*i, nw, nh);
|
||||
sum += nh;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int List::calc_minimum_width () const
|
||||
{
|
||||
int sum=0;
|
||||
const WidgetList &wl = m_widgets;
|
||||
if (!wl.empty()) {
|
||||
sum = (wl.size() - 1) * m_spacing;
|
||||
for (WidgetList::const_iterator i=wl.begin(); i!=wl.end(); ++i) {
|
||||
int nw, nh;
|
||||
get_size (*i, nw, nh);
|
||||
sum += nw;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void List::set_default_size (int w, int h)
|
||||
{
|
||||
has_default_size = true;
|
||||
defaultw = w;
|
||||
defaulth = h;
|
||||
}
|
||||
|
||||
|
||||
void List::get_size (const Widget *widget, int &w, int &h) const
|
||||
{
|
||||
if (has_default_size)
|
||||
w = defaultw, h = defaulth;
|
||||
else
|
||||
widget->naturalsize (w, h);
|
||||
}
|
||||
|
||||
void List::resize (int w, int h)
|
||||
{
|
||||
Container::resize (w, h);
|
||||
recalc();
|
||||
}
|
||||
|
||||
void List::move (int x, int y)
|
||||
{
|
||||
Container::move (x, y);
|
||||
// recalc();
|
||||
}
|
||||
|
||||
void List::reconfigure_child (Widget *w)
|
||||
{
|
||||
Container::reconfigure_child (w);
|
||||
recalc();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void List::add_back (Widget *w, ExpansionMode m)
|
||||
{
|
||||
add_child (w);
|
||||
m_expansionmodes.push_back (m);
|
||||
recalc();
|
||||
}
|
||||
|
||||
void List::set_alignment (HAlignment halign, VAlignment valign)
|
||||
{
|
||||
if (halign != m_halign || valign != m_valign) {
|
||||
m_halign = halign;
|
||||
m_valign = valign;
|
||||
recalc();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- HList -------------------- */
|
||||
|
||||
void HList::recalc()
|
||||
{
|
||||
int targetw = this->get_w(); // The available space
|
||||
int naturalw= calc_minimum_width();
|
||||
int excessw = targetw - naturalw;
|
||||
|
||||
int num_expand = std::count (m_expansionmodes.begin(),
|
||||
m_expansionmodes.end(),
|
||||
List::EXPAND);
|
||||
|
||||
WidgetList::iterator i = m_widgets.begin(),
|
||||
end = m_widgets.end();
|
||||
int x = get_x(), y = get_y();
|
||||
size_t j = 0;
|
||||
|
||||
if (num_expand == 0 && excessw > 0) {
|
||||
switch (m_halign) {
|
||||
case HALIGN_CENTER:
|
||||
x += excessw / 2;
|
||||
excessw = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i != end; ++i, ++j) {
|
||||
int w, h;
|
||||
List::get_size (*i, w, h);
|
||||
|
||||
if (excessw > 0 && m_expansionmodes[j] == List::EXPAND) {
|
||||
w += excessw / num_expand;
|
||||
excessw -= excessw / num_expand;
|
||||
num_expand -= 1;
|
||||
}
|
||||
(*i)->move (x, y);
|
||||
(*i)->resize (w, get_h());
|
||||
x += w + get_spacing();
|
||||
}
|
||||
}
|
||||
|
||||
bool HList::fits() {
|
||||
int targetw = this->get_w(); // The available space
|
||||
int naturalw= calc_minimum_width();
|
||||
return targetw >= naturalw;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- VList -------------------- */
|
||||
|
||||
void VList::recalc()
|
||||
{
|
||||
int targeth = this->get_h(); // The available space
|
||||
int naturalh= calc_minimum_height();
|
||||
int excessh = targeth - naturalh;
|
||||
|
||||
int num_expand = std::count (m_expansionmodes.begin(),
|
||||
m_expansionmodes.end(),
|
||||
List::EXPAND);
|
||||
|
||||
WidgetList::iterator i = m_widgets.begin(),
|
||||
end = m_widgets.end();
|
||||
int x = get_x(), y = get_y();
|
||||
size_t j = 0;
|
||||
|
||||
if (num_expand == 0 && excessh > 0) {
|
||||
switch (m_valign) {
|
||||
case VALIGN_CENTER:
|
||||
y += excessh / 2;
|
||||
excessh = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i != end; ++i, ++j) {
|
||||
int w, h;
|
||||
List::get_size (*i, w, h);
|
||||
|
||||
if (excessh > 0 && m_expansionmodes[j] == List::EXPAND) {
|
||||
h += excessh / num_expand;
|
||||
excessh -= excessh / num_expand;
|
||||
num_expand -= 1;
|
||||
}
|
||||
(*i)->move (x, y);
|
||||
(*i)->resize (get_w(), h);
|
||||
y += h + get_spacing();
|
||||
}
|
||||
}
|
||||
|
||||
bool VList::fits() {
|
||||
int targeth = this->get_h(); // The available space
|
||||
int naturalh= calc_minimum_height();
|
||||
return targeth >= naturalh;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Label -------------------- */
|
||||
|
||||
Label::Label (const std::string &text,
|
||||
HAlignment halign,
|
||||
VAlignment valign)
|
||||
: m_text (text),
|
||||
m_font(enigma::GetFont("menufont")),
|
||||
m_halign(halign),
|
||||
m_valign(valign)
|
||||
{}
|
||||
|
||||
|
||||
void Label::set_text (const std::string &text) {
|
||||
if (text != m_text) {
|
||||
m_text = text;
|
||||
reconfigure();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
string Label::get_text() const {
|
||||
return _(m_text.c_str());
|
||||
}
|
||||
|
||||
string Label::getText() const {
|
||||
return m_text;
|
||||
}
|
||||
|
||||
void Label::set_font (ecl::Font *font) {
|
||||
if (m_font != font) {
|
||||
m_font = font;
|
||||
reconfigure();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
bool Label::text_fits(double area_fraction) {
|
||||
int w, h;
|
||||
naturalsize (w, h);
|
||||
return w <= get_w()*area_fraction;
|
||||
}
|
||||
|
||||
void Label::draw (ecl::GC &gc, const ecl::Rect &)
|
||||
{
|
||||
Font *f = m_font;
|
||||
int w, h;
|
||||
naturalsize (w, h);
|
||||
|
||||
int x = get_x(), y=get_y();
|
||||
switch (m_halign) {
|
||||
case HALIGN_LEFT: break;
|
||||
case HALIGN_RIGHT: x += get_w() - w; break;
|
||||
case HALIGN_CENTER: x += (get_w()-w)/2; break;
|
||||
}
|
||||
switch (m_valign) {
|
||||
case VALIGN_TOP: break;
|
||||
case VALIGN_BOTTOM: y += get_h() - h; break;
|
||||
case VALIGN_CENTER: y += (get_h()-h)/2; break;
|
||||
}
|
||||
// translate if not an empty string
|
||||
f->render (gc, x, y, m_text == "" ? "" : get_text().c_str());
|
||||
}
|
||||
|
||||
void Label::set_alignment (HAlignment halign, VAlignment valign) {
|
||||
if (halign != m_halign || valign != m_valign) {
|
||||
m_halign = halign;
|
||||
m_valign = valign;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void Label::naturalsize (int &w, int &h) const
|
||||
{
|
||||
h = m_font->get_height();
|
||||
// width of translation if not an empty string
|
||||
w = m_font->get_width (m_text == "" ? "" : get_text().c_str());
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- UntranslatedLabel -------------------- */
|
||||
|
||||
UntranslatedLabel::UntranslatedLabel (const std::string &text,
|
||||
HAlignment halign, VAlignment valign) : Label(text, halign, valign) {
|
||||
}
|
||||
|
||||
string UntranslatedLabel::get_text() const {
|
||||
return Label::m_text;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Button -------------------- */
|
||||
|
||||
Button::Button() : m_activep (false), highlight (false) {
|
||||
}
|
||||
|
||||
void Button::activate()
|
||||
{
|
||||
sound::EmitSoundEvent ("menuswitch");
|
||||
m_activep = true;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Button::deactivate() {
|
||||
m_activep = false;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void Button::setHighlight(bool shouldHighlight) {
|
||||
highlight = shouldHighlight;
|
||||
invalidate();
|
||||
}
|
||||
bool Button::isHighlight() {
|
||||
return highlight;
|
||||
}
|
||||
|
||||
void Button::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
const int borderw = 4;
|
||||
|
||||
ecl::Surface *s = enigma::GetImage (m_activep ? "buttonhl" : "button");
|
||||
|
||||
if (s) { // Ugly, but hey, it works
|
||||
Rect srcrect (0,0,borderw, borderw);
|
||||
Rect area = get_area();
|
||||
|
||||
// background
|
||||
if (highlight)
|
||||
set_color (gc, 70, 70, 70);
|
||||
else
|
||||
set_color (gc, 0,0,0);
|
||||
box (gc, smaller(area, borderw));
|
||||
|
||||
set_color (gc, 0,0,0);
|
||||
// corners
|
||||
blit (gc, area.x, area.y, s, srcrect);
|
||||
srcrect.x += s->width()-borderw;
|
||||
blit (gc, area.x+area.w-borderw, area.y, s, srcrect);
|
||||
srcrect.x = 0;
|
||||
srcrect.y += s->height()-borderw;
|
||||
blit (gc, area.x, area.y+area.h-borderw, s, srcrect);
|
||||
srcrect.x += s->width()-borderw;
|
||||
blit (gc, area.x+area.w-borderw, area.y+area.h-borderw, s, srcrect);
|
||||
|
||||
// horizontal borders
|
||||
{
|
||||
int tilew = s->width() - 2*borderw;
|
||||
int ntiles = (area.w - 2*borderw) / tilew;
|
||||
int x = area.x + borderw;
|
||||
for (int i=0; i<ntiles; ++i) {
|
||||
blit (gc, x, area.y, s, Rect (borderw, 0, tilew, borderw));
|
||||
blit (gc, x, area.y+area.h-borderw, s,
|
||||
Rect (borderw, s->height()-borderw, tilew, borderw));
|
||||
x += tilew;
|
||||
}
|
||||
int restw = (area.w - 2*borderw) - tilew*ntiles;
|
||||
blit (gc, x, area.y, s, Rect (borderw, 0, restw, borderw));
|
||||
blit (gc, x, area.y+area.h-borderw, s,
|
||||
Rect (borderw, s->height()-borderw, restw, borderw));
|
||||
}
|
||||
// vertical borders
|
||||
{
|
||||
int tileh = s->height() - 2*borderw;
|
||||
int ntiles = (area.h - 2*borderw) / tileh;
|
||||
int y = area.y + borderw;
|
||||
for (int i=0; i<ntiles; ++i) {
|
||||
blit (gc, area.x, y, s, Rect (0, borderw, borderw, tileh));
|
||||
blit (gc, area.x+area.w-borderw, y, s,
|
||||
Rect (s->width()-borderw, borderw, borderw, tileh));
|
||||
y += tileh;
|
||||
}
|
||||
int resth = (area.h - 2*borderw) - tileh*ntiles;
|
||||
blit (gc, area.x, y, s, Rect (0, borderw, borderw, resth));
|
||||
blit (gc, area.x+area.w-borderw, y, s,
|
||||
Rect (s->width()-borderw, borderw, borderw, resth));
|
||||
}
|
||||
}
|
||||
else {
|
||||
set_color (gc, 0,0,0);
|
||||
box (gc, r);
|
||||
set_color (gc, 160,160,160);
|
||||
frame (gc, r);
|
||||
frame (gc, smaller(r, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- PushButton -------------------- */
|
||||
|
||||
PushButton::PushButton() : m_pressedp (false) {
|
||||
}
|
||||
|
||||
bool PushButton::on_event(const SDL_Event &e) {
|
||||
Widget::on_event(e);
|
||||
bool was_pressed = m_pressedp;
|
||||
|
||||
switch (e.type) {
|
||||
case SDL_KEYDOWN:
|
||||
if (e.key.keysym.sym != SDLK_RETURN &&
|
||||
e.key.keysym.sym != SDLK_SPACE) break;
|
||||
// fall-through
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
m_pressedp = true;
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
if (e.key.keysym.sym != SDLK_RETURN &&
|
||||
e.key.keysym.sym != SDLK_SPACE &&
|
||||
e.key.keysym.sym != SDLK_PAGEDOWN &&
|
||||
e.key.keysym.sym != SDLK_PAGEUP) break;
|
||||
lastUpSym = e.key.keysym.sym;
|
||||
lastUpBotton = 0;
|
||||
m_pressedp = false;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
lastUpSym = SDLK_UNKNOWN;
|
||||
lastUpBotton = e.button.button;
|
||||
m_pressedp = false;
|
||||
break;
|
||||
}
|
||||
|
||||
bool changed = (was_pressed != m_pressedp);
|
||||
if (changed) {
|
||||
invalidate();
|
||||
if (!m_pressedp) {
|
||||
if (soundOk())
|
||||
sound::EmitSoundEvent("menuok");
|
||||
invoke_listener();
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void PushButton::deactivate() {
|
||||
m_pressedp = false;
|
||||
lastUpSym = SDLK_UNKNOWN;
|
||||
lastUpBotton = 0;
|
||||
invalidate();
|
||||
Button::deactivate();
|
||||
}
|
||||
|
||||
SDLKey PushButton::getLastUpSym() {
|
||||
return lastUpSym;
|
||||
}
|
||||
|
||||
Uint8 PushButton::getLastUpButton() {
|
||||
return lastUpBotton;
|
||||
}
|
||||
|
||||
bool PushButton::soundOk() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------- TextButton -------------------- */
|
||||
|
||||
ecl::Font *TextButton::menufont = 0;
|
||||
ecl::Font *TextButton::menufont_pressed = 0;
|
||||
|
||||
TextButton::TextButton(ActionListener *al) {
|
||||
if (menufont == 0) {
|
||||
menufont = enigma::GetFont("menufont");
|
||||
menufont_pressed = enigma::GetFont("menufontsel");
|
||||
}
|
||||
set_listener(al);
|
||||
}
|
||||
|
||||
void TextButton::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
Button::draw(gc,r);
|
||||
Font *f = is_pressed() ? menufont_pressed : menufont;
|
||||
string text = get_text();
|
||||
int h = f->get_height();
|
||||
int w = f->get_width(text.c_str());
|
||||
int x = get_x() + (get_w()-w)/2;
|
||||
int y = get_y() + (get_h()-h)/2;
|
||||
|
||||
f->render (gc, x, y, text.c_str());
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- StaticTextButton -------------------- */
|
||||
|
||||
StaticTextButton::StaticTextButton(const string &t, ActionListener *al)
|
||||
: TextButton(al),
|
||||
text(t)
|
||||
{
|
||||
}
|
||||
|
||||
void StaticTextButton::set_text(const std::string &t) {
|
||||
if (t != text) {
|
||||
text = t;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
string StaticTextButton::get_text() const {
|
||||
return _(text.c_str()); // translate
|
||||
}
|
||||
|
||||
/* -------------------- UntranslatedStaticTextButton -------------------- */
|
||||
|
||||
UntranslatedStaticTextButton::UntranslatedStaticTextButton(const string &t,
|
||||
ActionListener *al)
|
||||
: StaticTextButton(t, al)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
string UntranslatedStaticTextButton::get_text() const {
|
||||
return StaticTextButton::text;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Buttons for Options -------------------- */
|
||||
|
||||
BoolOptionButton::BoolOptionButton(const char *option_name,
|
||||
const string& true_text, const string& false_text,
|
||||
ActionListener *al)
|
||||
: TextButton(al),
|
||||
optionName(option_name),
|
||||
trueText(true_text),
|
||||
falseText(false_text)
|
||||
{
|
||||
}
|
||||
|
||||
bool BoolOptionButton::toggle() {
|
||||
bool newval = !enigma_options::GetBool(optionName);
|
||||
enigma_options::SetOption(optionName, newval);
|
||||
invalidate();
|
||||
return newval;
|
||||
}
|
||||
|
||||
void BoolOptionButton::on_action(Widget *) {
|
||||
toggle();
|
||||
}
|
||||
|
||||
string BoolOptionButton::get_text() const {
|
||||
return enigma_options::GetBool(optionName) ? _(trueText.c_str()) : _(falseText.c_str());
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- ValueButton -------------------- */
|
||||
|
||||
ValueButton::ValueButton(int min_value_, int max_value_)
|
||||
: TextButton(this),
|
||||
min_value(min_value_),
|
||||
max_value(max_value_)
|
||||
{
|
||||
}
|
||||
|
||||
void ValueButton::setMaxValue(int max) {
|
||||
max_value = max;
|
||||
}
|
||||
|
||||
void ValueButton::init() {
|
||||
update_value(-1, get_value()); // fixes wrong values (e.g. from .enimarc)
|
||||
}
|
||||
|
||||
bool ValueButton::inc_value(int offset) {
|
||||
int old_value = get_value();
|
||||
return update_value(old_value, old_value+offset);
|
||||
}
|
||||
|
||||
string ValueButton::get_text() const {
|
||||
return get_text(get_value());
|
||||
}
|
||||
|
||||
bool ValueButton::update_value(int old_value, int new_value) {
|
||||
new_value = Clamp(new_value, min_value, max_value);
|
||||
if (new_value != old_value) {
|
||||
set_value(new_value);
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ValueButton::on_action(Widget *) {
|
||||
int incr = 1;
|
||||
bool stop = false;
|
||||
if (getLastUpSym() == SDLK_PAGEDOWN || getLastUpButton() == SDL_BUTTON_RIGHT ||
|
||||
getLastUpButton() == 5) { // wheel down
|
||||
incr = -1;
|
||||
}
|
||||
if (getLastUpSym() == SDLK_PAGEDOWN || getLastUpSym() == SDLK_PAGEUP ||
|
||||
getLastUpButton() == SDL_BUTTON_RIGHT ||
|
||||
getLastUpButton() == 4 || getLastUpButton() == 5) {
|
||||
stop = true;
|
||||
}
|
||||
if (inc_value(incr)) {
|
||||
sound::EmitSoundEvent("menuswitch");
|
||||
} else {
|
||||
if (stop) {
|
||||
sound::EmitSoundEvent("menustop");
|
||||
} else {
|
||||
sound::EmitSoundEvent("menuswitch");
|
||||
if (incr == 1)
|
||||
update_value(get_value(), min_value);
|
||||
else
|
||||
update_value(get_value(), max_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ValueButton::soundOk() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- ImageButton -------------------- */
|
||||
|
||||
ImageButton::ImageButton(const string &unselected,
|
||||
const string &selected,
|
||||
ActionListener *al)
|
||||
: fname_sel(selected), fname_unsel(unselected)
|
||||
{
|
||||
set_listener(al);
|
||||
}
|
||||
|
||||
void ImageButton::set_images(const string &unselected, const string &selected) {
|
||||
fname_sel = selected;
|
||||
fname_unsel = unselected;
|
||||
}
|
||||
|
||||
void ImageButton::draw(ecl::GC &gc, const ecl::Rect &r) {
|
||||
Button::draw(gc, r);
|
||||
string &fname = is_pressed() ? fname_sel : fname_unsel;
|
||||
|
||||
if (Surface *s = enigma::GetImage(fname.c_str())) {
|
||||
int w=s->width();
|
||||
int h=s->height();
|
||||
int x = get_x() + (get_w()-w)/2;
|
||||
int y = get_y() + (get_h()-h)/2;
|
||||
blit(gc, x, y, s);
|
||||
}
|
||||
}
|
||||
465
project/jni/application/enigma/src/gui/widgets.hh
Normal file
465
project/jni/application/enigma/src/gui/widgets.hh
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef WIDGETS_HH_INCLUDED
|
||||
#define WIDGETS_HH_INCLUDED
|
||||
|
||||
#include "ecl_fwd.hh"
|
||||
#include "ecl_geom.hh"
|
||||
#include "SDL.h"
|
||||
|
||||
namespace enigma { namespace gui {
|
||||
|
||||
|
||||
/* -------------------- Alignment -------------------- */
|
||||
|
||||
enum HAlignment {
|
||||
HALIGN_LEFT,
|
||||
HALIGN_CENTER,
|
||||
HALIGN_RIGHT
|
||||
};
|
||||
|
||||
enum VAlignment {
|
||||
VALIGN_TOP,
|
||||
VALIGN_CENTER,
|
||||
VALIGN_BOTTOM
|
||||
};
|
||||
|
||||
/* -------------------- Events & Event Handlers -------------------- */
|
||||
class Widget;
|
||||
|
||||
class ActionListener {
|
||||
public:
|
||||
virtual ~ActionListener() {}
|
||||
virtual void on_action(Widget *) {};
|
||||
};
|
||||
|
||||
/* -------------------- GUI Widgets -------------------- */
|
||||
|
||||
class Container;
|
||||
|
||||
class Widget : public ActionListener {
|
||||
public:
|
||||
|
||||
/* ---------- Widget interface ---------- */
|
||||
virtual void draw (ecl::GC &gc, const ecl::Rect &r) = 0;
|
||||
virtual void activate() {}
|
||||
virtual void deactivate() {}
|
||||
|
||||
virtual void realize (const ecl::Rect &r) {
|
||||
set_area (r);
|
||||
}
|
||||
|
||||
virtual bool on_event(const SDL_Event &/*e*/);
|
||||
Uint8 lastMouseButton() {return mouseButton;}
|
||||
SDLMod lastModifierKeys() { return modifierKeys; }
|
||||
|
||||
|
||||
virtual void move (int x, int y);
|
||||
virtual void resize (int w, int h);
|
||||
|
||||
virtual void naturalsize (int &w, int &h) const {
|
||||
w = h = 5;
|
||||
}
|
||||
|
||||
/* ---------- Accessors ---------- */
|
||||
void set_size(int w, int h) {area.w = w; area.h = h;}
|
||||
|
||||
ecl::Rect get_area() const { return area; }
|
||||
void set_area(const ecl::Rect &r) { area = r; }
|
||||
int get_x() const { return area.x; }
|
||||
int get_y() const { return area.y; }
|
||||
int get_w() const { return area.w; }
|
||||
int get_h() const { return area.h; }
|
||||
|
||||
void set_parent(Container *parent) { m_parent = parent; }
|
||||
Container *get_parent () const { return m_parent; }
|
||||
|
||||
void set_listener(ActionListener *al) {
|
||||
m_listener = al;
|
||||
}
|
||||
|
||||
void invalidate();
|
||||
virtual void tick (double /*dtime*/) {}
|
||||
|
||||
protected:
|
||||
Widget(Container *parent=0);
|
||||
|
||||
/* ---------- Functions ---------- */
|
||||
void reconfigure();
|
||||
void invalidate_area(const ecl::Rect &r);
|
||||
void invoke_listener();
|
||||
|
||||
private:
|
||||
ecl::Rect area;
|
||||
Container *m_parent;
|
||||
ActionListener *m_listener;
|
||||
SDLMod modifierKeys;
|
||||
Uint8 mouseButton;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* -------------------- EmptyWidget -------------------- */
|
||||
class EmptyWidget : public Widget {
|
||||
public:
|
||||
EmptyWidget () : Widget ()
|
||||
{}
|
||||
|
||||
virtual void draw (ecl::GC &gc, const ecl::Rect &r)
|
||||
{}
|
||||
|
||||
virtual void naturalsize (int &w, int &h) const {
|
||||
w = h = 0;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
/* -------------------- AreaManager -------------------- */
|
||||
|
||||
class AreaManaged {
|
||||
public:
|
||||
virtual ~AreaManaged() {}
|
||||
|
||||
virtual void invalidate_area(const ecl::Rect &r) = 0;
|
||||
virtual void invalidate_all() = 0;
|
||||
virtual void refresh() = 0;
|
||||
};
|
||||
|
||||
// The AreaManager perform refreshes of invalidated regions.
|
||||
// It gets attached to the top-level Container during the first invalidation
|
||||
// or refresh request.
|
||||
class AreaManager : public AreaManaged {
|
||||
public:
|
||||
AreaManager(Container *managed);
|
||||
|
||||
void invalidate_area(const ecl::Rect &r);
|
||||
void invalidate_all();
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
ecl::RectList dirtyrects;
|
||||
Container *top_container;
|
||||
};
|
||||
|
||||
/* -------------------- Container -------------------- */
|
||||
|
||||
class Container : public Widget, public AreaManaged {
|
||||
public:
|
||||
Container();
|
||||
~Container();
|
||||
|
||||
void add_child (Widget *w);
|
||||
virtual void remove_child (Widget *w);
|
||||
virtual void exchange_child (Widget *oldChild, Widget *newChild);
|
||||
virtual void reconfigure_child (Widget *w);
|
||||
|
||||
Widget *find_widget(int x, int y);
|
||||
Widget *find_adjacent_widget(Widget *from, int x, int y);
|
||||
|
||||
void clear();
|
||||
void draw_all();
|
||||
|
||||
// Widget interface.
|
||||
void draw (ecl::GC& gc, const ecl::Rect &r);
|
||||
void move (int x, int y);
|
||||
|
||||
// AreaManaged interface.
|
||||
void invalidate_area(const ecl::Rect &r);
|
||||
void invalidate_all();
|
||||
void refresh();
|
||||
|
||||
protected:
|
||||
typedef std::vector<Widget *> WidgetList;
|
||||
typedef WidgetList::iterator iterator;
|
||||
|
||||
iterator begin() { return m_widgets.begin(); }
|
||||
iterator end() { return m_widgets.end(); }
|
||||
WidgetList m_widgets;
|
||||
|
||||
private:
|
||||
ecl::Rect boundingbox();
|
||||
|
||||
AreaManager *getAreaManager();
|
||||
AreaManager *managed_by;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- List, HList, VList -------------------- */
|
||||
|
||||
class List : public Container {
|
||||
public:
|
||||
void set_spacing (int pixels);
|
||||
|
||||
enum ExpansionMode {
|
||||
EXPAND,
|
||||
TIGHT
|
||||
};
|
||||
|
||||
void add_back (Widget *w, ExpansionMode m = List::TIGHT);
|
||||
virtual void remove_child (Widget *w);
|
||||
virtual void exchange_child (Widget *oldChild, Widget *newChild);
|
||||
|
||||
void set_default_size (int w, int h);
|
||||
void set_alignment (HAlignment halign, VAlignment valign);
|
||||
virtual bool fits() = 0;
|
||||
|
||||
protected:
|
||||
List(int spacing=5);
|
||||
|
||||
int calc_minimum_height () const;
|
||||
int calc_minimum_width () const;
|
||||
|
||||
int get_spacing () const;
|
||||
|
||||
void get_size (const Widget *widget, int &w, int &h) const;
|
||||
|
||||
// ---------- Widget interface ----------
|
||||
virtual void move (int x, int y);
|
||||
virtual void resize(int w, int h);
|
||||
|
||||
// ---------- List interface ----------
|
||||
virtual void recalc() = 0;
|
||||
|
||||
// ---------- Container interface ----------
|
||||
virtual void reconfigure_child (Widget *w);
|
||||
|
||||
|
||||
protected:
|
||||
std::vector<ExpansionMode> m_expansionmodes;
|
||||
|
||||
private:
|
||||
int m_spacing; // # of pixels between container items
|
||||
bool has_default_size;
|
||||
int defaultw, defaulth;
|
||||
protected:
|
||||
HAlignment m_halign;
|
||||
VAlignment m_valign;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class HList : public List {
|
||||
public:
|
||||
HList() : List() {}
|
||||
virtual bool fits();
|
||||
|
||||
private:
|
||||
// List interface
|
||||
virtual void recalc();
|
||||
};
|
||||
|
||||
class VList : public List {
|
||||
public:
|
||||
VList() : List() {}
|
||||
virtual bool fits();
|
||||
|
||||
private:
|
||||
// List interface
|
||||
virtual void recalc();
|
||||
|
||||
};
|
||||
|
||||
/* -------------------- Image -------------------- */
|
||||
|
||||
class Image : public Widget {
|
||||
public:
|
||||
Image (const std::string &iname) : imgname(iname) {}
|
||||
void draw (ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
std::string imgname;
|
||||
};
|
||||
|
||||
/* -------------------- Label -------------------- */
|
||||
|
||||
class Label : public Widget {
|
||||
public:
|
||||
Label (const std::string &text="",
|
||||
HAlignment halign=HALIGN_CENTER,
|
||||
VAlignment valign=VALIGN_CENTER);
|
||||
|
||||
// Widget interface
|
||||
virtual void draw (ecl::GC &gc, const ecl::Rect &r);
|
||||
virtual void naturalsize (int &w, int &h) const;
|
||||
|
||||
// Methods
|
||||
void set_text (const std::string &text);
|
||||
virtual std::string get_text() const; // translated
|
||||
std::string getText() const;
|
||||
void set_font (ecl::Font *font);
|
||||
void set_alignment (HAlignment halign, VAlignment valign=VALIGN_CENTER);
|
||||
bool text_fits(double area_fraction = 1.0);
|
||||
protected:
|
||||
// Variables.
|
||||
std::string m_text;
|
||||
ecl::Font *m_font;
|
||||
HAlignment m_halign;
|
||||
VAlignment m_valign;
|
||||
};
|
||||
|
||||
/* -------------------- UntranslatedLabel -------------------- */
|
||||
|
||||
class UntranslatedLabel : public Label {
|
||||
public:
|
||||
UntranslatedLabel(const std::string &text="",
|
||||
HAlignment halign=HALIGN_CENTER,
|
||||
VAlignment valign=VALIGN_CENTER);
|
||||
|
||||
// TextButton interface.
|
||||
virtual std::string get_text() const;
|
||||
};
|
||||
|
||||
/* -------------------- Button -------------------- */
|
||||
|
||||
class Button : public Widget {
|
||||
public:
|
||||
void setHighlight(bool shouldHighlight);
|
||||
bool isHighlight();
|
||||
protected:
|
||||
Button();
|
||||
|
||||
// Widget interface.
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
void activate();
|
||||
void deactivate();
|
||||
bool m_activep;
|
||||
bool highlight;
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- PushButton -------------------- */
|
||||
|
||||
class PushButton : public Button {
|
||||
public:
|
||||
PushButton();
|
||||
|
||||
bool is_pressed() { return m_pressedp; }
|
||||
|
||||
protected:
|
||||
bool on_event(const SDL_Event &e);
|
||||
void deactivate();
|
||||
SDLKey getLastUpSym();
|
||||
Uint8 getLastUpButton();
|
||||
virtual bool soundOk();
|
||||
private:
|
||||
bool m_pressedp;
|
||||
SDLKey lastUpSym;
|
||||
Uint8 lastUpBotton;
|
||||
};
|
||||
|
||||
/* -------------------- TextButton -------------------- */
|
||||
|
||||
class TextButton : public PushButton {
|
||||
public:
|
||||
TextButton(ActionListener *al=0);
|
||||
virtual std::string get_text() const = 0;
|
||||
|
||||
private:
|
||||
// Widget interface.
|
||||
void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
|
||||
// Variables.
|
||||
static ecl::Font *menufont, *menufont_pressed;
|
||||
};
|
||||
|
||||
/* -------------------- StaticTextButton -------------------- */
|
||||
|
||||
class StaticTextButton : public TextButton {
|
||||
public:
|
||||
StaticTextButton(const std::string &t, ActionListener *al=0);
|
||||
virtual void set_text(const std::string &t);
|
||||
|
||||
// TextButton interface.
|
||||
std::string get_text() const;
|
||||
|
||||
protected:
|
||||
// Variables.
|
||||
std::string text;
|
||||
};
|
||||
|
||||
/* -------------------- UntranslatedStaticTextButton -------------------- */
|
||||
|
||||
class UntranslatedStaticTextButton : public StaticTextButton {
|
||||
public:
|
||||
UntranslatedStaticTextButton(const std::string &t, ActionListener *al=0);
|
||||
|
||||
// TextButton interface.
|
||||
std::string get_text() const;
|
||||
};
|
||||
|
||||
/* -------------------- BoolOptionButton -------------------- */
|
||||
class BoolOptionButton : public TextButton {
|
||||
public:
|
||||
BoolOptionButton(const char *option_name,
|
||||
const std::string& true_text,
|
||||
const std::string& false_text,
|
||||
ActionListener *al = 0);
|
||||
|
||||
bool toggle(); // returns new value
|
||||
void on_action(Widget *);
|
||||
|
||||
// TextButton interface.
|
||||
std::string get_text() const;
|
||||
|
||||
private:
|
||||
const char *optionName;
|
||||
std::string trueText;
|
||||
std::string falseText;
|
||||
};
|
||||
|
||||
/* -------------------- ValueButton -------------------- */
|
||||
class ValueButton: public TextButton {
|
||||
public:
|
||||
ValueButton(int min_value_, int max_value_);
|
||||
|
||||
virtual int get_value() const = 0;
|
||||
virtual void set_value(int value) = 0;
|
||||
void setMaxValue(int max);
|
||||
|
||||
bool inc_value(int offset);
|
||||
|
||||
// TextButton interface.
|
||||
virtual std::string get_text() const;
|
||||
|
||||
// Widget interface.
|
||||
virtual void on_action(Widget *w);
|
||||
protected:
|
||||
void init(); // called in ctor of derived
|
||||
virtual bool soundOk();
|
||||
private:
|
||||
int min_value;
|
||||
int max_value;
|
||||
|
||||
bool update_value(int old_value, int new_value);
|
||||
virtual std::string get_text(int value) const = 0;
|
||||
};
|
||||
|
||||
/* -------------------- ImageButton -------------------- */
|
||||
|
||||
class ImageButton : public PushButton {
|
||||
public:
|
||||
ImageButton(const std::string &unselected,
|
||||
const std::string &selected,
|
||||
ActionListener *al = 0);
|
||||
void set_images(const std::string &unselected, const std::string &selected);
|
||||
// Widget interface.
|
||||
virtual void draw(ecl::GC &gc, const ecl::Rect &r);
|
||||
private:
|
||||
std::string fname_sel, fname_unsel;
|
||||
};
|
||||
|
||||
}} // namespace enigma::gui
|
||||
#endif
|
||||
3701
project/jni/application/enigma/src/items.cpp
Normal file
3701
project/jni/application/enigma/src/items.cpp
Normal file
File diff suppressed because it is too large
Load Diff
259
project/jni/application/enigma/src/items.hh
Normal file
259
project/jni/application/enigma/src/items.hh
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef ITEMS_HH_INCLUDED
|
||||
#define ITEMS_HH_INCLUDED
|
||||
|
||||
#include "objects_decl.hh"
|
||||
|
||||
namespace world
|
||||
{
|
||||
enum ItemID {
|
||||
it_INVALID = -1,
|
||||
it_FIRST = 0,
|
||||
it_none = 0,
|
||||
it_1pkillstone,
|
||||
it_2pkillstone,
|
||||
it_abyss,
|
||||
it_bag,
|
||||
it_banana,
|
||||
it_blackbomb,
|
||||
it_blackbomb_burning,
|
||||
it_blocker,
|
||||
it_booze,
|
||||
it_brake,
|
||||
it_bridge_oxyd,
|
||||
it_bridge_oxyd_active,
|
||||
it_booze_broken,
|
||||
it_brush,
|
||||
it_burnable,
|
||||
it_burnable_fireproof,
|
||||
it_burnable_ignited,
|
||||
it_burnable_burning,
|
||||
it_burnable_ash,
|
||||
it_burnable_oil,
|
||||
it_changefloor,
|
||||
it_cherry,
|
||||
it_cherry_crushed,
|
||||
it_coffee,
|
||||
it_coin1,
|
||||
it_coin2,
|
||||
it_coin4,
|
||||
it_crack0,
|
||||
it_crack1,
|
||||
it_crack2,
|
||||
it_crack3,
|
||||
it_cross,
|
||||
it_death,
|
||||
it_debris,
|
||||
it_document,
|
||||
it_drop,
|
||||
it_dynamite,
|
||||
it_dummy,
|
||||
it_easykeepstone,
|
||||
it_easykillstone,
|
||||
it_explosion1,
|
||||
it_explosion2,
|
||||
it_explosion3,
|
||||
it_extinguisher,
|
||||
it_extinguisher_medium,
|
||||
it_extinguisher_empty,
|
||||
it_extralife,
|
||||
it_flagblack,
|
||||
it_flagwhite,
|
||||
it_floppy,
|
||||
it_glasses,
|
||||
it_glasses_broken,
|
||||
it_hammer,
|
||||
it_hill,
|
||||
it_hollow,
|
||||
it_hstrip,
|
||||
it_inversesensor,
|
||||
it_key_a,
|
||||
it_key_b,
|
||||
it_key_c,
|
||||
it_landmine,
|
||||
it_laserbeam,
|
||||
it_magicwand,
|
||||
it_magnet_off,
|
||||
it_magnet_on,
|
||||
it_odometer,
|
||||
it_oxyd5f,
|
||||
it_pencil,
|
||||
it_pin,
|
||||
it_pipe_e, it_pipe_w, it_pipe_s, it_pipe_n,
|
||||
it_pipe_es, it_pipe_ne, it_pipe_sw, it_pipe_wn,
|
||||
it_pipe_h, it_pipe_v,
|
||||
it_puller_n,
|
||||
it_puller_e,
|
||||
it_puller_s,
|
||||
it_puller_w,
|
||||
it_ring,
|
||||
it_rubberband,
|
||||
it_seed,
|
||||
it_seed_nowood,
|
||||
it_seed_volcano,
|
||||
it_sensor,
|
||||
it_shogun_s,
|
||||
it_shogun_m,
|
||||
it_shogun_l,
|
||||
it_signalfilter0,
|
||||
it_signalfilter1,
|
||||
it_spade,
|
||||
it_spoon,
|
||||
it_spring1,
|
||||
it_spring2,
|
||||
it_springboard,
|
||||
it_squashed,
|
||||
it_surprise,
|
||||
it_sword,
|
||||
it_tinyhill,
|
||||
it_tinyhollow,
|
||||
it_trigger,
|
||||
it_umbrella,
|
||||
it_vortex_open,
|
||||
it_vortex_closed,
|
||||
it_vstrip,
|
||||
it_weight,
|
||||
it_whitebomb,
|
||||
it_wormhole_off,
|
||||
it_wormhole_on,
|
||||
it_wrench,
|
||||
it_yinyang,
|
||||
it_LAST,
|
||||
it_COUNT
|
||||
};
|
||||
|
||||
/*! What may happen to an item _after_ it was activated? */
|
||||
enum ItemAction {
|
||||
ITEM_DROP, //!< Drop it to the floor
|
||||
ITEM_KILL, //!< Remove it from the inventory and dispose it
|
||||
ITEM_KEEP, //!< Keep it in the inventory; do nothing further
|
||||
};
|
||||
|
||||
enum ItemFlags {
|
||||
itf_none = 0,
|
||||
itf_static = 1, //!< Cannot be picked up
|
||||
itf_indestructible = 2, //!< Cannot be destroyed by explosions etc.
|
||||
itf_animation = 4, //!< Use set_anim() instead of set_model()
|
||||
itf_invisible = 8, //!< Item has no visible model
|
||||
itf_inflammable = 16, //!< Burns when hit by laser beam
|
||||
itf_norespawn = 32, //!< Don't respawn balls on top of this item
|
||||
itf_fireproof = 64, //!< This item can't burn by fire
|
||||
};
|
||||
|
||||
struct ItemTraits {
|
||||
const char *name; //!< Name of the item, e.g., "it-hammer"
|
||||
ItemID id;
|
||||
int flags; //!< Combination of ItemFlags
|
||||
float radius; //!< Radius, 0.0 = default
|
||||
};
|
||||
|
||||
class Item : public GridObject {
|
||||
public:
|
||||
Item();
|
||||
|
||||
/* ---------- Public methods ---------- */
|
||||
void kill();
|
||||
void replace (ItemID id);
|
||||
|
||||
/* ---------- Virtual functions ---------- */
|
||||
const char *get_kind() const;
|
||||
void init_model();
|
||||
void on_laserhit(Direction);
|
||||
|
||||
/* ---------- Item interface ---------- */
|
||||
|
||||
virtual Item *clone() = 0;
|
||||
|
||||
virtual const ItemTraits &get_traits() const = 0;
|
||||
|
||||
/*! Return true if item completely covers the floor. In this
|
||||
case the Floor::actor_contact() will not be called
|
||||
automatically; this must be done from `Item::actor_hit' (if
|
||||
at all). */
|
||||
virtual bool covers_floor(ecl::V2 pos) const { return false; }
|
||||
|
||||
/*! Return the force an item exerts on actor `a'. This is
|
||||
used by sloped and hills for force fields that are local to
|
||||
the current field. For global force fields you have to
|
||||
register a ForceField in the world. */
|
||||
virtual void add_force(Actor *a, ecl::V2 &f);
|
||||
|
||||
virtual bool can_drop_at (GridPos p);
|
||||
|
||||
virtual void drop (Actor *a, GridPos p);
|
||||
|
||||
/*! Called when item is dropped by actor `a' */
|
||||
virtual void on_drop(Actor *a);
|
||||
|
||||
/*! Called when item is picked up by actor `a' */
|
||||
virtual void on_pickup(Actor *a);
|
||||
|
||||
/*! Called when stone above item changes. */
|
||||
virtual void stone_change(Stone *st);
|
||||
|
||||
/*! Called when item is ``hit'' by a moving stone. */
|
||||
virtual void on_stonehit(Stone *st);
|
||||
|
||||
/*! Called when item is ``hit'' by an actor. Return true if
|
||||
the item should be picked up. */
|
||||
virtual bool actor_hit(Actor *a);
|
||||
|
||||
/*! The model used for displaying this item in an
|
||||
inventory. */
|
||||
virtual string get_inventory_model();
|
||||
|
||||
/* Called when item is activated by the owner of `a'. */
|
||||
virtual ItemAction activate(Actor* a, GridPos p);
|
||||
protected:
|
||||
// GridObject interface
|
||||
virtual void set_model (const std::string &mname) {
|
||||
display::SetModel(GridLoc(GRID_ITEMS, get_pos()), mname);
|
||||
}
|
||||
|
||||
virtual display::Model *get_model () {
|
||||
return display::GetModel(GridLoc(GRID_ITEMS, get_pos()));
|
||||
}
|
||||
|
||||
virtual void kill_model (GridPos p) {
|
||||
display::KillModel (GridLoc (GRID_ITEMS, p));
|
||||
}
|
||||
// replace template method hook
|
||||
virtual void setup_successor(Item *newitem) {}
|
||||
};
|
||||
|
||||
/* -------------------- Inline functions -------------------- */
|
||||
|
||||
/*! Return unique item type identifier. */
|
||||
inline ItemID get_id (Item *it) {
|
||||
if (it)
|
||||
return it->get_traits().id;
|
||||
return it_none;
|
||||
}
|
||||
|
||||
inline bool has_flags (Item *it, ItemFlags flags) {
|
||||
return (it->get_traits().flags & flags) == flags;
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
|
||||
void InitItems();
|
||||
}
|
||||
|
||||
#endif
|
||||
797
project/jni/application/enigma/src/laser.cpp
Normal file
797
project/jni/application/enigma/src/laser.cpp
Normal file
@@ -0,0 +1,797 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#include "laser.hh"
|
||||
#include "sound.hh"
|
||||
#include "stones_internal.hh"
|
||||
#include "server.hh"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
using namespace world;
|
||||
using namespace lasers;
|
||||
|
||||
using stones::maybe_push_stone;
|
||||
using ecl::V2;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/* -------------------- LaserBeam -------------------- */
|
||||
|
||||
class LaserBeam : public Item, public LaserEmitter {
|
||||
public:
|
||||
static void emit_from(GridPos p, Direction d);
|
||||
static void kill_all();
|
||||
static void all_emitted();
|
||||
|
||||
// LaserEmitter interface
|
||||
DirectionBits emission_directions() const { return directions; }
|
||||
static ItemTraits traits;
|
||||
|
||||
const ItemTraits &get_traits() const {
|
||||
return traits;
|
||||
}
|
||||
private:
|
||||
LaserBeam(Direction dir) {
|
||||
directions = to_bits(dir);
|
||||
}
|
||||
|
||||
// Item interface.
|
||||
void on_laserhit(Direction dir);
|
||||
void on_creation (GridPos p);
|
||||
void init_model();
|
||||
bool actor_hit(Actor *actor);
|
||||
|
||||
Item *clone() {
|
||||
// new LaserBeams may only created inside `emit_from'.
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
void dispose();
|
||||
|
||||
// Variables
|
||||
DirectionBits directions;
|
||||
|
||||
static vector<LaserBeam*> instances;
|
||||
static map<GridPos, int> old_laser_positions;
|
||||
};
|
||||
ItemTraits LaserBeam::traits = {"it-laserbeam", it_laserbeam,
|
||||
itf_static | itf_indestructible, 0.0 };
|
||||
|
||||
|
||||
/* -------------------- Laser Stones -------------------- */
|
||||
|
||||
/** \page st-laser Laser Stone
|
||||
|
||||
These stones emit a laser beam in a specified direction when
|
||||
activated. They are the only objects in the game that can act as
|
||||
primary light sources (mirrors can also emit light but they require
|
||||
an incoming beam).
|
||||
|
||||
\subsection lasera Attributes
|
||||
|
||||
- \b on: 1 if laser in active, 0 if not
|
||||
- \b dir: the Direction in which light is emitted
|
||||
(NORTH, EAST, SOUTH, WEST)
|
||||
|
||||
\subsection laserm Messages
|
||||
|
||||
- \b on, \b off, \b onoff: as usual
|
||||
|
||||
\subsection lasersa See also
|
||||
|
||||
\ref st-pmirror, \ref st-3mirror
|
||||
|
||||
*/
|
||||
class LaserStone : public LaserEmitter, public stones::OnOffStone {
|
||||
public:
|
||||
LaserStone (Direction dir=EAST);
|
||||
static void reemit_all();
|
||||
|
||||
private:
|
||||
|
||||
// INSTANCELISTOBJ(LaserStone);
|
||||
|
||||
// We can't use this macro here: g++ can't handle multiple inheritance
|
||||
// and covariant return types at the same time ("sorry, not
|
||||
// implemented: ..." first time I ever saw this error message :-)
|
||||
|
||||
typedef std::vector<LaserStone*> InstanceList;
|
||||
static InstanceList instances;
|
||||
Stone *clone() {
|
||||
LaserStone *o = new LaserStone(*this);
|
||||
instances.push_back(o);
|
||||
return o;
|
||||
}
|
||||
void dispose() {
|
||||
instances.erase(find(instances.begin(), instances.end(), this));
|
||||
delete this;
|
||||
}
|
||||
|
||||
// LaserEmitter interface
|
||||
DirectionBits emission_directions() const;
|
||||
|
||||
// OnOffStone interface.
|
||||
void notify_onoff(bool on);
|
||||
|
||||
// Private methods.
|
||||
void emit_light();
|
||||
Direction get_dir() const {return Direction(int_attrib("dir"));}
|
||||
|
||||
// Stone interface.
|
||||
void on_creation (GridPos p);
|
||||
void init_model();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- PhotoCell -------------------- */
|
||||
|
||||
vector<void*> PhotoCell::instances;
|
||||
|
||||
PhotoCell::~PhotoCell()
|
||||
{
|
||||
photo_deactivate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function notifies all instances of PhotoCell that a
|
||||
* recalculation of the laser beams is about to begin by calling
|
||||
* on_recalc_start() for each instance.
|
||||
*/
|
||||
void PhotoCell::notify_start()
|
||||
{
|
||||
for(unsigned i=0; i<instances.size(); ++i)
|
||||
{
|
||||
PhotoCell *pc = (PhotoCell*) instances[i];
|
||||
pc->on_recalc_start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function notifies all instances of PhotoCell that the engine
|
||||
* has finished recalculating the laser beams by calling
|
||||
* on_recalc_finish() for each instance.
|
||||
*/
|
||||
void PhotoCell::notify_finish()
|
||||
{
|
||||
for(unsigned i=0; i<instances.size(); ++i)
|
||||
{
|
||||
PhotoCell *pc = (PhotoCell*) instances[i];
|
||||
pc->on_recalc_finish();
|
||||
}
|
||||
}
|
||||
|
||||
void PhotoCell::photo_activate()
|
||||
{
|
||||
vector<void*>::iterator i = std::find(instances.begin(), instances.end(), this);
|
||||
if (i != instances.end())
|
||||
assert (0 || "Photocell activated twice\n");
|
||||
else
|
||||
instances.push_back (this);
|
||||
}
|
||||
|
||||
void PhotoCell::photo_deactivate()
|
||||
{
|
||||
vector<void*>::iterator i;
|
||||
i = std::find (instances.begin(), instances.end(), this);
|
||||
if (i != instances.end())
|
||||
instances.erase(i);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- PhotoStone -------------------- */
|
||||
|
||||
PhotoStone::PhotoStone(const char *kind) : Stone(kind)
|
||||
{
|
||||
illuminated = false;
|
||||
}
|
||||
|
||||
void PhotoStone::on_recalc_start()
|
||||
{}
|
||||
|
||||
void PhotoStone::on_recalc_finish()
|
||||
{
|
||||
GridPos p = get_pos();
|
||||
bool illu = (LightFrom(p, NORTH) || LightFrom(p, EAST)
|
||||
|| LightFrom(p, WEST) || LightFrom(p, SOUTH));
|
||||
|
||||
if (illu != illuminated) {
|
||||
if (illu) notify_laseron();
|
||||
else notify_laseroff();
|
||||
illuminated = illu;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- LaserBeam -------------------- */
|
||||
|
||||
// The implementation of laser beams is a little tricky because, in
|
||||
// spite of being implemented as Items, lasers aren't localized and
|
||||
// changes to any part of the beam can affect the beam elsewhere. A
|
||||
// `change' may be anything from moving a stone in or out of the beam,
|
||||
// rotating or moving one of the mirrors, to making a stone in the
|
||||
// beam transparent.
|
||||
//
|
||||
// Here are a couple of facts about laser beams in Enigma:
|
||||
//
|
||||
// - Laser beams are static. Once calculated they do not change until
|
||||
// they are completely recalculated
|
||||
//
|
||||
// - LaserBeam::emit_from() is the only way to emit laser beams. A new
|
||||
// beam will propagate automatically and stops only if it comes
|
||||
// across an item or a stone that returns `false' from
|
||||
// Stone::is_transparent().
|
||||
//
|
||||
// - `on_laserhit()' is called for objects in the beam *whenever*
|
||||
// the beam is recalculated. For objects that need to be notified
|
||||
// when the laser goes on or off, use the `PhotoStone'
|
||||
// mixin.
|
||||
|
||||
vector<LaserBeam*> LaserBeam::instances;
|
||||
map<GridPos, int> LaserBeam::old_laser_positions;
|
||||
|
||||
void LaserBeam::init_model()
|
||||
{
|
||||
if (directions & (EASTBIT | WESTBIT)) {
|
||||
if (directions & (NORTHBIT | SOUTHBIT))
|
||||
set_model("it-laserhv");
|
||||
else
|
||||
set_model("it-laserh");
|
||||
}
|
||||
else if (directions & (NORTHBIT | SOUTHBIT))
|
||||
set_model("it-laserv");
|
||||
}
|
||||
|
||||
void LaserBeam::on_laserhit(Direction dir)
|
||||
{
|
||||
DirectionBits dirbit = to_bits(dir);
|
||||
if (!(directions & dirbit)) {
|
||||
// `dir' not in `directions' ?
|
||||
directions = DirectionBits(directions | dirbit);
|
||||
emit_from(get_pos(), dir);
|
||||
init_model();
|
||||
}
|
||||
}
|
||||
|
||||
void LaserBeam::on_creation (GridPos p)
|
||||
{
|
||||
if (directions & EASTBIT) emit_from(p, EAST);
|
||||
if (directions & WESTBIT) emit_from(p, WEST);
|
||||
if (directions &NORTHBIT) emit_from(p, NORTH);
|
||||
if (directions &SOUTHBIT) emit_from(p, SOUTH);
|
||||
init_model();
|
||||
}
|
||||
|
||||
void LaserBeam::emit_from(GridPos p, Direction dir)
|
||||
{
|
||||
bool may_pass = true;
|
||||
|
||||
p.move(dir);
|
||||
if (Stone *st = GetStone(p)) {
|
||||
may_pass = st->is_transparent (dir);
|
||||
st->on_laserhit (dir);
|
||||
}
|
||||
|
||||
if (may_pass) {
|
||||
if (Item *it = GetItem(p))
|
||||
it->on_laserhit (dir);
|
||||
else {
|
||||
LaserBeam *lb = new LaserBeam (dir);
|
||||
SetItem(p, lb);
|
||||
instances.push_back(lb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LaserBeam::actor_hit(Actor *actor)
|
||||
{
|
||||
double r = get_radius(actor);
|
||||
V2 p = actor->get_pos();
|
||||
GridPos gp = get_pos();
|
||||
|
||||
// distance of actor from center of the grid
|
||||
double dx = fabs(p[0] - gp.x - 0.5) - r;
|
||||
double dy = fabs(p[1] - gp.y - 0.5) - r;
|
||||
|
||||
if ((directions & (EASTBIT | WESTBIT) && dy<-0.1) ||
|
||||
(directions & (NORTHBIT | SOUTHBIT)) && dx<-0.1)
|
||||
{
|
||||
SendMessage(actor, "laserhit");
|
||||
}
|
||||
|
||||
return false; // laser beams can't be picked up
|
||||
}
|
||||
|
||||
void LaserBeam::kill_all()
|
||||
{
|
||||
assert(old_laser_positions.empty());
|
||||
|
||||
while (!instances.empty())
|
||||
{
|
||||
LaserBeam *lb = instances[0];
|
||||
GridPos pos = lb->get_pos();
|
||||
|
||||
old_laser_positions[pos] = static_cast<int>(lb->directions);
|
||||
world::KillItem(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void LaserBeam::all_emitted()
|
||||
{
|
||||
vector<LaserBeam*>::const_iterator end = instances.end();
|
||||
map<GridPos, int>::iterator none = old_laser_positions.end();
|
||||
|
||||
double x = 0, y = 0;
|
||||
int count = 0;
|
||||
|
||||
for (vector<LaserBeam*>::const_iterator i = instances.begin(); i != end; ++i) {
|
||||
LaserBeam *lb = *i;
|
||||
GridPos pos = lb->get_pos();
|
||||
map<GridPos, int>::iterator found = old_laser_positions.find(pos);
|
||||
|
||||
if (found != none) {
|
||||
// a beam was at the current position (during last kill_all())
|
||||
DirectionBits old_dir = static_cast<DirectionBits>(found->second);
|
||||
|
||||
if ((old_dir&lb->directions) != lb->directions) {
|
||||
// a beam has been added here
|
||||
x += pos.x;
|
||||
y += pos.y;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// store newly created LaserBeams
|
||||
x += pos.x;
|
||||
y += pos.y;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if (count) {
|
||||
sound::EmitSoundEvent ("laseron", ecl::V2(x/count+.5, y/count+.5),
|
||||
getVolume("laseron", NULL));
|
||||
}
|
||||
|
||||
old_laser_positions.clear();
|
||||
}
|
||||
|
||||
void LaserBeam::dispose()
|
||||
{
|
||||
instances.erase(std::find(instances.begin(), instances.end(), this));
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------
|
||||
// Laser stone
|
||||
//----------------------------------------
|
||||
LaserStone::InstanceList LaserStone::instances;
|
||||
|
||||
LaserStone::LaserStone (Direction dir)
|
||||
: OnOffStone("st-laser")
|
||||
{
|
||||
set_attrib("dir", Value(dir));
|
||||
}
|
||||
|
||||
DirectionBits
|
||||
LaserStone::emission_directions() const
|
||||
{
|
||||
if (is_on()) {
|
||||
return to_bits(get_dir());
|
||||
}
|
||||
return NODIRBIT;
|
||||
}
|
||||
|
||||
|
||||
void LaserStone::reemit_all()
|
||||
{
|
||||
for (unsigned i=0; i<instances.size(); ++i)
|
||||
{
|
||||
LaserStone *ls = (LaserStone*) instances[i];
|
||||
ls->emit_light();
|
||||
}
|
||||
}
|
||||
|
||||
void LaserStone::notify_onoff(bool /*on*/)
|
||||
{
|
||||
RecalcLight();
|
||||
}
|
||||
|
||||
void LaserStone::emit_light()
|
||||
{
|
||||
if (is_on())
|
||||
LaserBeam::emit_from(get_pos(), get_dir());
|
||||
}
|
||||
|
||||
void LaserStone::on_creation (GridPos p)
|
||||
{
|
||||
if (is_on())
|
||||
RecalcLight();
|
||||
Stone::on_creation(p);
|
||||
}
|
||||
|
||||
void LaserStone::init_model()
|
||||
{
|
||||
string mname = is_on() ? "st-laseron" : "st-laser";
|
||||
mname += to_suffix(get_dir());
|
||||
set_model(mname);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- MirrorStone -------------------- */
|
||||
namespace
|
||||
{
|
||||
class MirrorStone
|
||||
: public Stone, public LaserEmitter, public PhotoCell
|
||||
{
|
||||
protected:
|
||||
MirrorStone(const char *name, bool movable=false, bool transparent=false);
|
||||
|
||||
bool is_transparent() const { return int_attrib("transparent") != 0; }
|
||||
bool is_movable() const { return int_attrib("movable") != 0; }
|
||||
|
||||
void set_orientation(int o) { set_attrib("orientation", o); }
|
||||
int get_orientation() { return int_attrib("orientation"); }
|
||||
|
||||
void emit_light(Direction dir) {
|
||||
if (!has_dir(outdirs, dir))
|
||||
{
|
||||
outdirs = DirectionBits(outdirs | to_bits(dir));
|
||||
LaserBeam::emit_from(get_pos(), dir);
|
||||
}
|
||||
}
|
||||
|
||||
void init_model();
|
||||
private:
|
||||
// Object interface.
|
||||
virtual Value message(const string &m, const Value &);
|
||||
|
||||
// LaserEmitter interface
|
||||
DirectionBits emission_directions() const {
|
||||
return outdirs;
|
||||
}
|
||||
|
||||
// PhotoCell interface
|
||||
void on_recalc_start() { outdirs = NODIRBIT; }
|
||||
void on_recalc_finish() {}
|
||||
|
||||
// Stone interface
|
||||
void actor_hit(const world::StoneContact &sc);
|
||||
void on_creation (GridPos p);
|
||||
void on_removal (GridPos p);
|
||||
bool is_transparent(Direction) const { return is_transparent(); }
|
||||
|
||||
// Private methods
|
||||
void rotate_right();
|
||||
|
||||
// Variables
|
||||
DirectionBits outdirs;
|
||||
};
|
||||
}
|
||||
|
||||
MirrorStone::MirrorStone(const char *name, bool movable, bool transparent)
|
||||
: Stone(name), outdirs(NODIRBIT)
|
||||
{
|
||||
set_attrib("transparent", transparent);
|
||||
set_attrib("movable", movable);
|
||||
set_attrib("orientation", Value(1));
|
||||
}
|
||||
|
||||
void MirrorStone::init_model() {
|
||||
string mname = get_kind();
|
||||
mname += is_movable() ? "-m" : "-s";
|
||||
mname += is_transparent() ? "t" : "o";
|
||||
mname += char('0' + get_orientation());
|
||||
set_model(mname);
|
||||
}
|
||||
|
||||
Value MirrorStone::message(const string &m, const Value &val) {
|
||||
if (m == "trigger" || m=="turn") {
|
||||
rotate_right();
|
||||
}
|
||||
else if (m == "signal") {
|
||||
if (to_double(val) != 0) {
|
||||
rotate_right();
|
||||
}
|
||||
}
|
||||
else if (m == "mirror-north") {
|
||||
set_orientation(3);
|
||||
init_model();
|
||||
MaybeRecalcLight(get_pos());
|
||||
}
|
||||
else if (m == "mirror-east") {
|
||||
set_orientation(4);
|
||||
init_model();
|
||||
MaybeRecalcLight(get_pos());
|
||||
}
|
||||
else if (m == "mirror-south") {
|
||||
set_orientation(1);
|
||||
init_model();
|
||||
MaybeRecalcLight(get_pos());
|
||||
}
|
||||
else if (m == "mirror-west") {
|
||||
set_orientation(2);
|
||||
init_model();
|
||||
MaybeRecalcLight(get_pos());
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
void MirrorStone::actor_hit(const world::StoneContact &sc)
|
||||
{
|
||||
if (is_movable())
|
||||
maybe_push_stone(sc);
|
||||
rotate_right();
|
||||
}
|
||||
|
||||
void MirrorStone::on_creation (GridPos p)
|
||||
{
|
||||
photo_activate();
|
||||
Stone::on_creation(p);
|
||||
}
|
||||
|
||||
void MirrorStone::on_removal(GridPos p)
|
||||
{
|
||||
photo_deactivate();
|
||||
Stone::on_removal(p);
|
||||
}
|
||||
|
||||
void MirrorStone::rotate_right()
|
||||
{
|
||||
set_orientation(1+(get_orientation() % 4));
|
||||
init_model();
|
||||
MaybeRecalcLight(get_pos());
|
||||
sound_event ("mirrorturn");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------- Plane Mirror -------------------- */
|
||||
namespace
|
||||
{
|
||||
class PlaneMirror : public MirrorStone {
|
||||
CLONEOBJ(PlaneMirror);
|
||||
public:
|
||||
PlaneMirror(char orientation='/', bool movable=false, bool transparent=false)
|
||||
: MirrorStone("st-pmirror", movable, transparent)
|
||||
{
|
||||
SetOrientation(orientation);
|
||||
}
|
||||
private:
|
||||
void SetOrientation(char o) {
|
||||
const char *a = " -\\|/";
|
||||
MirrorStone::set_orientation(int (strchr(a,o)-a));
|
||||
}
|
||||
char GetOrientation() {
|
||||
const char *a = " -\\|/";
|
||||
return a[MirrorStone::get_orientation()];
|
||||
}
|
||||
void on_laserhit(Direction dir);
|
||||
};
|
||||
}
|
||||
|
||||
void PlaneMirror::on_laserhit(Direction dir)
|
||||
{
|
||||
char orientation = GetOrientation();
|
||||
bool transparent = is_transparent();
|
||||
|
||||
switch (orientation) {
|
||||
case '|':
|
||||
if (dir==EAST || dir==WEST) {
|
||||
emit_light(reverse(dir));
|
||||
if (transparent)
|
||||
emit_light(dir);
|
||||
}
|
||||
else if ((dir == NORTH || dir == SOUTH) && transparent &&
|
||||
server::GameCompatibility == GAMET_OXYD1) {
|
||||
emit_light(dir);
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (dir==NORTH || dir==SOUTH) {
|
||||
emit_light(reverse(dir));
|
||||
if (transparent)
|
||||
emit_light(dir);
|
||||
}
|
||||
else if ((dir == EAST || dir == WEST) && transparent &&
|
||||
server::GameCompatibility == GAMET_OXYD1) {
|
||||
emit_light(dir);
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
switch(dir) {
|
||||
case EAST: emit_light(NORTH); break;
|
||||
case SOUTH: emit_light(WEST); break;
|
||||
case NORTH: emit_light(EAST); break;
|
||||
case WEST: emit_light(SOUTH); break;
|
||||
case NODIR: break;
|
||||
}
|
||||
if (transparent)
|
||||
emit_light(dir);
|
||||
break;
|
||||
case '\\':
|
||||
switch(dir) {
|
||||
case EAST: emit_light(SOUTH); break;
|
||||
case SOUTH: emit_light(EAST); break;
|
||||
case NORTH: emit_light(WEST); break;
|
||||
case WEST: emit_light(NORTH); break;
|
||||
case NODIR: break;
|
||||
}
|
||||
if (transparent)
|
||||
emit_light(dir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- TriangleMirror -------------------- */
|
||||
|
||||
namespace
|
||||
{
|
||||
// The orientations of the TriangleMirror have an unusual definition,
|
||||
// but we cannot change them w/o changing many levels
|
||||
//
|
||||
// Flat side of the triangle
|
||||
// points to : Orientation :
|
||||
//
|
||||
// WEST 4
|
||||
// SOUTH 3
|
||||
// EAST 2
|
||||
// NORTH 1
|
||||
|
||||
class TriangleMirror : public MirrorStone {
|
||||
CLONEOBJ(TriangleMirror);
|
||||
public:
|
||||
TriangleMirror(char orientation='v', bool movable=false, bool transparent=false)
|
||||
: MirrorStone("st-3mirror", movable, transparent)
|
||||
{
|
||||
SetOrientation (orientation);
|
||||
}
|
||||
private:
|
||||
|
||||
void SetOrientation(char o) {
|
||||
const char *a = " v<^>";
|
||||
MirrorStone::set_orientation( int (strchr(a,o)-a));
|
||||
}
|
||||
|
||||
Direction GetOrientation() // orientation of the flat side of the mirror
|
||||
{
|
||||
const Direction a[] = {NODIR, NORTH, EAST, SOUTH, WEST};
|
||||
return a[MirrorStone::get_orientation()];
|
||||
}
|
||||
void on_laserhit (Direction dir);
|
||||
};
|
||||
}
|
||||
|
||||
void TriangleMirror::on_laserhit(Direction beam_dir)
|
||||
// note: 'beam_dir' is the direction where laserbeam goes to
|
||||
{
|
||||
// direction where flat side of triangle points to
|
||||
Direction flat_dir = GetOrientation();
|
||||
Direction tip_dir = reverse(flat_dir);
|
||||
|
||||
if (beam_dir == tip_dir) // beam hits the flat side
|
||||
emit_light(flat_dir);
|
||||
else if (beam_dir == flat_dir) {
|
||||
// this is the "complicated" case where the light falls
|
||||
// on the tip of the triangle
|
||||
switch (beam_dir) {
|
||||
case SOUTH: case NORTH:
|
||||
emit_light(EAST); emit_light(WEST); break;
|
||||
case WEST: case EAST:
|
||||
emit_light(SOUTH); emit_light(NORTH); break;
|
||||
case NODIR: break;
|
||||
}
|
||||
} else
|
||||
emit_light(tip_dir);
|
||||
|
||||
if (is_transparent())
|
||||
emit_light(beam_dir);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// FUNCTIONS
|
||||
//----------------------------------------------------------------------
|
||||
namespace
|
||||
{
|
||||
/* This flag is true iff all lasers should be recalculated at the
|
||||
end of the next tick. */
|
||||
bool light_recalc_scheduled = false;
|
||||
}
|
||||
|
||||
void lasers::Init() {
|
||||
Register (new LaserStone);
|
||||
Register ("st-laser-n", new LaserStone(NORTH));
|
||||
Register ("st-laser-e", new LaserStone(EAST));
|
||||
Register ("st-laser-s", new LaserStone(SOUTH));
|
||||
Register ("st-laser-w", new LaserStone(WEST));
|
||||
|
||||
Register (new TriangleMirror);
|
||||
Register ("st-mirror-3v", new TriangleMirror('v'));
|
||||
Register ("st-mirror-3<", new TriangleMirror('<'));
|
||||
Register ("st-mirror-3^", new TriangleMirror('^'));
|
||||
Register ("st-mirror-3>", new TriangleMirror('>'));
|
||||
Register ("st-mirror-3vm", new TriangleMirror('v', true));
|
||||
Register ("st-mirror-3<m", new TriangleMirror('<', true));
|
||||
Register ("st-mirror-3^m", new TriangleMirror('^', true));
|
||||
Register ("st-mirror-3>m", new TriangleMirror('>', true));
|
||||
Register ("st-mirror-3vt", new TriangleMirror('v', false, true));
|
||||
Register ("st-mirror-3<t", new TriangleMirror('<', false, true));
|
||||
Register ("st-mirror-3^t", new TriangleMirror('^', false, true));
|
||||
Register ("st-mirror-3>t", new TriangleMirror('>', false, true));
|
||||
Register ("st-mirror-3vtm", new TriangleMirror('v', true, true));
|
||||
Register ("st-mirror-3<tm", new TriangleMirror('<', true, true));
|
||||
Register ("st-mirror-3^tm", new TriangleMirror('^', true, true));
|
||||
Register ("st-mirror-3>tm", new TriangleMirror('>', true, true));
|
||||
|
||||
Register (new PlaneMirror);
|
||||
Register ("st-mirror-p|", new PlaneMirror('|'));
|
||||
Register ("st-mirror-p/", new PlaneMirror('/'));
|
||||
Register ("st-mirror-p-", new PlaneMirror('-'));
|
||||
Register ("st-mirror-p\\", new PlaneMirror('\\'));
|
||||
Register ("st-mirror-p|m", new PlaneMirror('|', true));
|
||||
Register ("st-mirror-p/m", new PlaneMirror('/', true));
|
||||
Register ("st-mirror-p-m", new PlaneMirror('-', true));
|
||||
Register ("st-mirror-p\\m", new PlaneMirror('\\', true));
|
||||
Register ("st-mirror-p|t", new PlaneMirror('|', false, true));
|
||||
Register ("st-mirror-p/t", new PlaneMirror('/', false, true));
|
||||
Register ("st-mirror-p-t", new PlaneMirror('-', false, true));
|
||||
Register ("st-mirror-p\\t", new PlaneMirror('\\', false, true));
|
||||
Register ("st-mirror-p|tm", new PlaneMirror('|', true, true));
|
||||
Register ("st-mirror-p/tm", new PlaneMirror('/', true, true));
|
||||
Register ("st-mirror-p-tm", new PlaneMirror('-', true, true));
|
||||
Register ("st-mirror-p\\tm", new PlaneMirror('\\', true, true));
|
||||
}
|
||||
|
||||
|
||||
void lasers::MaybeRecalcLight(GridPos p) {
|
||||
light_recalc_scheduled |=
|
||||
(LightFrom(p, NORTH) || LightFrom(p, SOUTH) ||
|
||||
LightFrom(p, WEST) || LightFrom(p, EAST));
|
||||
}
|
||||
|
||||
void lasers::RecalcLight() {
|
||||
light_recalc_scheduled = true;
|
||||
}
|
||||
|
||||
bool lasers::LightFrom (GridPos p, Direction dir) {
|
||||
p.move(dir);
|
||||
if (LaserEmitter *le = dynamic_cast<LaserEmitter*>(GetStone(p)))
|
||||
if (has_dir(le->emission_directions(), reverse(dir)))
|
||||
return true;
|
||||
if (LaserEmitter *le = dynamic_cast<LaserEmitter*>(GetItem(p)))
|
||||
return (has_dir(le->emission_directions(), reverse(dir)));
|
||||
return false;
|
||||
}
|
||||
|
||||
void lasers::RecalcLightNow() {
|
||||
if (light_recalc_scheduled) {
|
||||
PhotoCell::notify_start();
|
||||
LaserBeam::kill_all();
|
||||
LaserStone::reemit_all();
|
||||
PhotoCell::notify_finish();
|
||||
LaserBeam::all_emitted();
|
||||
light_recalc_scheduled = false;
|
||||
}
|
||||
}
|
||||
130
project/jni/application/enigma/src/laser.hh
Normal file
130
project/jni/application/enigma/src/laser.hh
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef LASER_HH
|
||||
#define LASER_HH
|
||||
|
||||
/* This file contains the declarations for (almost) everything that
|
||||
has to do with lasers. */
|
||||
|
||||
#include "objects.hh"
|
||||
|
||||
namespace world
|
||||
{
|
||||
/**
|
||||
* This interface must be implemented by all items and stones that
|
||||
* are capable of emitting light.
|
||||
*/
|
||||
class LaserEmitter {
|
||||
public:
|
||||
virtual ~LaserEmitter() {}
|
||||
virtual DirectionBits emission_directions() const = 0;
|
||||
};
|
||||
|
||||
/* -------------------- PhotoCell -------------------- */
|
||||
|
||||
/**
|
||||
* PhotoCells are objects (not necessarily stones) that are
|
||||
* sensitive to laser light. Whenever the game engine
|
||||
* recalculates the laser beams, instances of this class are
|
||||
* notified about the beginning and the end of a recalculation.
|
||||
*/
|
||||
class PhotoCell {
|
||||
public:
|
||||
virtual ~PhotoCell();
|
||||
|
||||
// ---------- Static functions ----------
|
||||
static void notify_start();
|
||||
static void notify_finish();
|
||||
|
||||
// ---------- PhotoCell interface ----------
|
||||
virtual void on_recalc_start() = 0;
|
||||
virtual void on_recalc_finish() = 0;
|
||||
protected:
|
||||
|
||||
/*! Derived classes must call this method to register
|
||||
themselves for the on_recalc_start() and on_recalc_finish()
|
||||
events. */
|
||||
void photo_activate();
|
||||
|
||||
/*! Derived classes must call this method to unregister
|
||||
themselves. It is automatically called by ~PhotoCell(), but
|
||||
objects may have to call it explicitly if they are not
|
||||
interested in PhotoCell events. */
|
||||
void photo_deactivate();
|
||||
private:
|
||||
static std::vector<void*> instances;
|
||||
};
|
||||
|
||||
/* -------------------- PhotoStone -------------------- */
|
||||
|
||||
/*! Most stones are indifferent to laser beams: They either block
|
||||
the light completely or they let it pass, but they do not change
|
||||
their internal state when they are hit by light. Certain kinds
|
||||
of stones need to be notified whenever the `light' goes on or off
|
||||
-- these can be derived from this class.
|
||||
|
||||
The most prominent example are Oxyd stones -- they open when
|
||||
they are hit by a laser beam. See the remarks at the beginning
|
||||
of this file to understand why overriding `on_laserhit' is not
|
||||
sufficient for a proper implementation of Oxyd stones.
|
||||
*/
|
||||
|
||||
class PhotoStone : public Stone, public PhotoCell {
|
||||
protected:
|
||||
PhotoStone (const char *kind);
|
||||
|
||||
private:
|
||||
bool illuminated;
|
||||
|
||||
// PhotoCell interface
|
||||
void on_recalc_start();
|
||||
void on_recalc_finish();
|
||||
|
||||
// PhotoStone interface
|
||||
virtual void notify_laseron() = 0;
|
||||
virtual void notify_laseroff() = 0;
|
||||
};
|
||||
}
|
||||
|
||||
/* -------------------- Functions -------------------- */
|
||||
namespace lasers
|
||||
{
|
||||
void Init();
|
||||
|
||||
/*! This function must be called at the end of each tick; it
|
||||
recalculates the laser beams if necessary. */
|
||||
void RecalcLightNow();
|
||||
|
||||
/*! Force all light beams to be recalculated at the end of the
|
||||
current tick. So far, this is only used by laser stones and in
|
||||
world::InitWorld(). */
|
||||
void RecalcLight();
|
||||
|
||||
/*! If position `p' is inside a laser beam, force all laser beams
|
||||
to be recalculated. This is mainly used when items and stones
|
||||
are created or removed, but it can be also used for objects
|
||||
(like doors) that sometimes shut off a light beam (when the door
|
||||
is closed) and sometimes don't (when the door is open). */
|
||||
void MaybeRecalcLight (enigma::GridPos p);
|
||||
|
||||
/*! Return true iff a stone or an item at position `p' it hit by
|
||||
light coming from direction `dir'. */
|
||||
bool LightFrom (enigma::GridPos p, enigma::Direction dir);
|
||||
}
|
||||
#endif
|
||||
720
project/jni/application/enigma/src/lev/Index.cpp
Normal file
720
project/jni/application/enigma/src/lev/Index.cpp
Normal file
@@ -0,0 +1,720 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/VolatileIndex.hh"
|
||||
#include "errors.hh"
|
||||
#include "main.hh"
|
||||
#include "options.hh"
|
||||
#include "sound.hh"
|
||||
#include "PreferenceManager.hh"
|
||||
#include "StateManager.hh"
|
||||
#include "lev/ScoreManager.hh"
|
||||
#include "lev/RatingManager.hh"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
|
||||
std::map<std::string, Index *> Index::indices;
|
||||
std::map<std::string, std::vector<Index *> *> Index::indexGroups;
|
||||
|
||||
Index * Index::currentIndex = NULL;
|
||||
std::string Index::currentGroup;
|
||||
std::map<std::string, std::string> Index::nullExtensions;
|
||||
|
||||
void Index::initGroups() {
|
||||
ASSERT(indexGroups.empty(), XFrontend, "Reinitialization of groups");
|
||||
std::vector<std::string> groupNames = getGroupNames();
|
||||
for (int i = 0; i < groupNames.size(); i++) {
|
||||
std::vector<Index *> *group = new std::vector<Index *>;
|
||||
indexGroups.insert(std::make_pair(groupNames[i], group));
|
||||
}
|
||||
currentGroup = app.state->getString("CurrentGroup");
|
||||
}
|
||||
|
||||
void Index::registerIndex(Index *anIndex) {
|
||||
if (anIndex == NULL)
|
||||
return;
|
||||
|
||||
// check for uniqueness of index name
|
||||
if (findIndex(anIndex->getName()) != NULL)
|
||||
return;
|
||||
|
||||
indices.insert(std::make_pair(anIndex->getName(), anIndex));
|
||||
|
||||
|
||||
// register index in state.xml and update current position, first with last values
|
||||
std::string groupName = "";
|
||||
double stateLocation = 0;
|
||||
app.state->addIndex(anIndex->getName(), groupName, stateLocation,
|
||||
anIndex->currentPosition, anIndex->screenFirstPosition);
|
||||
|
||||
// user location for index?
|
||||
if (stateLocation > 0)
|
||||
anIndex->indexLocation = stateLocation;
|
||||
|
||||
// reset positions that are out of range - this may happen due to
|
||||
// modified levelpacks (updates, deleted levels in auto, new commandline)
|
||||
if (anIndex->currentPosition < 0 || anIndex->currentPosition >= anIndex->size())
|
||||
anIndex->currentPosition = 0;
|
||||
|
||||
// check user preferences for assigned group
|
||||
if (!groupName.empty())
|
||||
anIndex->indexGroup = groupName; // use users preference
|
||||
else
|
||||
groupName = anIndex->indexGroup; // use index default group
|
||||
|
||||
std::vector<Index *> * group;
|
||||
|
||||
// if no prefs ask for index default group
|
||||
|
||||
// make new group if not existing
|
||||
if (groupName != INDEX_EVERY_GROUP) {
|
||||
std::map<std::string, std::vector<Index *> *>::iterator i = indexGroups.find(groupName);
|
||||
if (i != indexGroups.end()) {
|
||||
group = i->second;
|
||||
} else {
|
||||
// make the group
|
||||
group = new std::vector<Index *>;
|
||||
indexGroups.insert(std::make_pair(groupName, group));
|
||||
app.state->addGroup(groupName, anIndex->getName(), 0);
|
||||
|
||||
// fill group with indices that appear in every group
|
||||
std::map<std::string, Index *>::iterator iti;
|
||||
for (iti = indices.begin(); iti != indices.end(); iti++)
|
||||
if ((*iti).second->getGroupName() == INDEX_EVERY_GROUP)
|
||||
addIndexToGroup((*iti).second, group);
|
||||
}
|
||||
}
|
||||
|
||||
if (groupName != INDEX_EVERY_GROUP) {
|
||||
// insert according to user prefs or index defaults
|
||||
addIndexToGroup(anIndex, group);
|
||||
addIndexToGroup(anIndex, getGroup(INDEX_ALL_PACKS));
|
||||
} else {
|
||||
// add index to all groups inclusive INDEX_ALL_PACKS
|
||||
std::map<std::string, std::vector<Index *> *>::iterator itg;
|
||||
for (itg = indexGroups.begin(); itg != indexGroups.end(); itg++)
|
||||
addIndexToGroup(anIndex, (*itg).second);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void Index::addIndexToGroup(Index *anIndex, std::vector<Index *> * aGroup) {
|
||||
std::vector<Index *>::iterator itg;
|
||||
for (itg = aGroup->begin(); itg != aGroup->end() &&
|
||||
(*itg)->indexLocation <= anIndex->indexLocation;
|
||||
itg++) {
|
||||
}
|
||||
aGroup->insert(itg, anIndex);
|
||||
}
|
||||
|
||||
void Index::removeIndexFromGroup(Index *anIndex, std::string groupName) {
|
||||
std::vector<Index *> *theGroup = indexGroups[groupName];
|
||||
std::vector<Index *>::iterator itg;
|
||||
for (itg = theGroup->begin(); itg != theGroup->end(); itg++) {
|
||||
if ((*itg) == anIndex) {
|
||||
theGroup->erase(itg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Index * Index::findIndex(std::string anIndexName) {
|
||||
std::string::size_type lastChar = anIndexName.find_last_not_of(" ");
|
||||
if (lastChar == std::string::npos)
|
||||
// the name is effectively an empty string
|
||||
return NULL;
|
||||
|
||||
// stip of trailing and leading spaces
|
||||
std::string name = anIndexName.substr(0 , lastChar + 1);
|
||||
name = name.substr(anIndexName.find_first_not_of(" "));
|
||||
|
||||
std::map<std::string, Index *>::iterator i = indices.find(name);
|
||||
if (i != indices.end())
|
||||
return i->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string Index::getCurrentGroup() {
|
||||
if (currentIndex == NULL)
|
||||
// initialize current group
|
||||
getCurrentIndex();
|
||||
return currentGroup;
|
||||
}
|
||||
|
||||
void Index::setCurrentGroup(std::string groupName) {
|
||||
// set group - even "All Packs"
|
||||
app.state->setProperty("CurrentGroup", groupName);
|
||||
currentGroup = groupName;
|
||||
|
||||
// set current index for desired group
|
||||
std::string indexName = getGroupSelectedIndex(groupName);
|
||||
Index * newIndex = findIndex(indexName);
|
||||
std::string indexGroupName;
|
||||
|
||||
if (newIndex != NULL)
|
||||
indexGroupName = newIndex->getGroupName();
|
||||
|
||||
if (newIndex != NULL && (indexGroupName == groupName ||
|
||||
indexGroupName == INDEX_EVERY_GROUP ||
|
||||
groupName == INDEX_ALL_PACKS)) {
|
||||
// set the groups current index as main current index
|
||||
setCurrentIndex(indexName);
|
||||
} else {
|
||||
// the groups current index is no longer available or did change the
|
||||
// group -- reset the groups current index
|
||||
std::vector<Index *> * group = getGroup(groupName);
|
||||
if (group->size() > 0) {
|
||||
setCurrentIndex((*group)[0]->getName());
|
||||
} else {
|
||||
// the group is empty -- delete group current index entry and
|
||||
// leave the apps current index unchanged
|
||||
setGroupSelectedIndex(groupName,"");
|
||||
}
|
||||
}
|
||||
// Log << "Index setCurrentGroup: wanted " << groupName << " - got " << currentGroup << " - idxGroup " << indexGroupName <<"\n";
|
||||
}
|
||||
|
||||
std::vector<std::string> Index::getGroupNames() {
|
||||
std::vector<std::string> names;
|
||||
app.state->getGroupNames(&names);
|
||||
return names;
|
||||
}
|
||||
|
||||
void Index::deleteGroup(std::string groupName) {
|
||||
std::vector<Index *> * theGroup = getGroup(groupName);
|
||||
if (theGroup != NULL) {
|
||||
indexGroups.erase(groupName);
|
||||
delete theGroup;
|
||||
}
|
||||
|
||||
if (currentGroup == groupName) {
|
||||
std::vector<std::string> groups = getGroupNames();
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
if (groups[i] == groupName) {
|
||||
if (i > 0) {
|
||||
setCurrentGroup(groups[i-1]);
|
||||
} else {
|
||||
ASSERT (groups.size() > 1, XFrontend, "Delete of last existing group.");
|
||||
setCurrentGroup(groups[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
app.state->deleteGroup(groupName);
|
||||
}
|
||||
|
||||
void Index::moveGroup(std::string groupName, int newPos) {
|
||||
std::string indexName = app.state->getGroupSelectedIndex(groupName);
|
||||
std::string column = app.state->getGroupSelectedColumn(groupName);
|
||||
app.state->deleteGroup(groupName);
|
||||
app.state->insertGroup(newPos, groupName, indexName, column);
|
||||
}
|
||||
|
||||
void Index::renameGroup(std::string oldName, std::string newName) {
|
||||
// rename state group element
|
||||
app.state->renameGroup(oldName, newName);
|
||||
|
||||
// rename map of groups
|
||||
std::vector<Index *> * group = getGroup(oldName);
|
||||
indexGroups.erase(oldName);
|
||||
indexGroups.insert(std::make_pair(newName, group));
|
||||
|
||||
// rename group name in indices
|
||||
for (int i = 0; i < group->size(); i++) {
|
||||
if ((*group)[i]->getGroupName() == oldName) {
|
||||
(*group)[i]->indexGroup = newName;
|
||||
// set group as users choice for index in state
|
||||
app.state->setIndexGroup((*group)[i]->getName(), newName);
|
||||
}
|
||||
}
|
||||
|
||||
// handle currentGroup
|
||||
if (currentGroup == oldName) {
|
||||
currentGroup = newName;
|
||||
app.state->setProperty("CurrentGroup", newName);
|
||||
}
|
||||
}
|
||||
|
||||
void Index::insertGroup(std::string groupName, int newPos) {
|
||||
// make the group
|
||||
std::vector<Index *> *group = new std::vector<Index *>;
|
||||
indexGroups.insert(std::make_pair(groupName, group));
|
||||
app.state->insertGroup(newPos, groupName, "", "");
|
||||
|
||||
// fill group with indices that appear in every group
|
||||
std::map<std::string, Index *>::iterator iti;
|
||||
for (iti = indices.begin(); iti != indices.end(); iti++)
|
||||
if ((*iti).second->getGroupName() == INDEX_EVERY_GROUP)
|
||||
addIndexToGroup((*iti).second, group);
|
||||
|
||||
setCurrentGroup(groupName);
|
||||
}
|
||||
|
||||
std::string Index::getGroupSelectedIndex(std::string groupName) {
|
||||
return app.state->getGroupSelectedIndex(groupName);
|
||||
}
|
||||
|
||||
int Index::getGroupSelectedColumn(std::string groupName) {
|
||||
std::string columnString = app.state->getGroupSelectedColumn(groupName);
|
||||
if (columnString.empty())
|
||||
return INDEX_GROUP_COLUMN_UNKNOWN;
|
||||
else {
|
||||
int col = INDEX_GROUP_COLUMN_UNKNOWN;
|
||||
std::sscanf(columnString.c_str(), "%i", &col);
|
||||
return col;
|
||||
}
|
||||
}
|
||||
|
||||
void Index::setGroupSelectedIndex(std::string groupName, std::string indexName) {
|
||||
app.state->setGroupSelectedIndex(groupName, indexName);
|
||||
}
|
||||
|
||||
void Index::setGroupSelectedColumn(std::string groupName, int column) {
|
||||
if (column == INDEX_GROUP_COLUMN_UNKNOWN)
|
||||
app.state->setGroupSelectedColumn(groupName, "");
|
||||
else
|
||||
app.state->setGroupSelectedColumn(groupName, ecl::strf("%d",column));
|
||||
}
|
||||
|
||||
Index * Index::getCurrentIndex() {
|
||||
if (currentIndex == NULL) {
|
||||
// first look for user preference
|
||||
if (setCurrentIndex(app.state->getGroupSelectedIndex(
|
||||
app.state->getString("CurrentGroup"))))
|
||||
;
|
||||
|
||||
// fallback to "Tutorial" pack
|
||||
else if (setCurrentIndex("Tutorial"))
|
||||
;
|
||||
|
||||
// fallback to any pack
|
||||
else if (!indices.empty()) {
|
||||
setCurrentIndex(indices.begin()->second->getName());
|
||||
}
|
||||
// add empty pack
|
||||
else {
|
||||
std::vector<std::string> emptyList;
|
||||
registerIndex(new lev::VolatileIndex("Empty Index",
|
||||
INDEX_DEFAULT_GROUP, emptyList));
|
||||
setCurrentIndex("Empty Index");
|
||||
}
|
||||
}
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
bool Index::setCurrentIndex(std::string anIndexName) {
|
||||
Index * newIndex = findIndex(anIndexName);
|
||||
if (newIndex != NULL) {
|
||||
if (newIndex != currentIndex) {
|
||||
sound::SetDefaultSoundSet(newIndex->get_default_SoundSet());
|
||||
currentIndex = newIndex;
|
||||
std::string group = currentIndex->getGroupName();
|
||||
if (group != INDEX_EVERY_GROUP &&
|
||||
app.state->getString("CurrentGroup") != INDEX_ALL_PACKS) {
|
||||
app.state->setProperty("CurrentGroup", group);
|
||||
currentGroup = group;
|
||||
}
|
||||
if (getGroupSelectedIndex(currentGroup) != currentIndex->getName()) {
|
||||
setGroupSelectedIndex(currentGroup, currentIndex->getName());
|
||||
setGroupSelectedColumn(currentGroup, INDEX_GROUP_COLUMN_UNKNOWN);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Index * Index::nextGroupIndex() {
|
||||
std::vector<Index *> * curGroup = getGroup(currentGroup);
|
||||
ASSERT(curGroup != NULL, XFrontend, "");
|
||||
|
||||
for (int i = 0; i < curGroup->size() - 1; i++) {
|
||||
if ((*curGroup)[i] == currentIndex)
|
||||
return (*curGroup)[i+1];
|
||||
}
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
Index * Index::previousGroupIndex() {
|
||||
std::vector<Index *> * curGroup = getGroup(currentGroup);
|
||||
ASSERT(curGroup != NULL, XFrontend, "");
|
||||
|
||||
for (int i = 1; i < curGroup->size(); i++) {
|
||||
if ((*curGroup)[i] == currentIndex)
|
||||
return (*curGroup)[i-1];
|
||||
}
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
Proxy * Index::getCurrentProxy() {
|
||||
return getCurrentIndex()->getCurrent();
|
||||
}
|
||||
|
||||
std::vector<Index *> * Index::getGroup(std::string groupName) {
|
||||
std::map<std::string, std::vector<Index *> *>::iterator i = indexGroups.find(groupName);
|
||||
if (i != indexGroups.end())
|
||||
return i->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double Index::getNextUserLocation() {
|
||||
double lastUsed = INDEX_USER_PACK_LOCATION;
|
||||
std::map<std::string, Index *>::iterator iti;
|
||||
for (iti = indices.begin(); iti != indices.end(); iti++) {
|
||||
double idxLocation = (*iti).second->indexLocation;
|
||||
if (idxLocation > lastUsed && idxLocation < INDEX_DEFAULT_PACK_LOCATION) {
|
||||
lastUsed = idxLocation;
|
||||
}
|
||||
}
|
||||
if (lastUsed + 999 < INDEX_DEFAULT_PACK_LOCATION)
|
||||
return lastUsed + 100;
|
||||
else
|
||||
return 0.9 * lastUsed + INDEX_DEFAULT_PACK_LOCATION / 10;
|
||||
}
|
||||
|
||||
|
||||
Index::Index(std::string anIndexName, std::string aGroupName, double defaultLocation) :
|
||||
indexName (anIndexName), indexGroup (aGroupName), defaultGroup (aGroupName),
|
||||
indexLocation (defaultLocation), indexDefaultLocation (defaultLocation),
|
||||
currentPosition (0), screenFirstPosition (0) {
|
||||
}
|
||||
|
||||
Index::~Index() {}
|
||||
|
||||
std::string Index::getName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
std::string Index::getGroupName() {
|
||||
return indexGroup;
|
||||
}
|
||||
|
||||
std::string Index::getDefaultGroupName() {
|
||||
return defaultGroup;
|
||||
}
|
||||
|
||||
double Index::getLocation() {
|
||||
return indexLocation;
|
||||
}
|
||||
|
||||
double Index::getDefaultLocation() {
|
||||
return indexDefaultLocation;
|
||||
}
|
||||
|
||||
void Index::setDefaultLocation(double defLocation) {
|
||||
indexDefaultLocation = defLocation;
|
||||
}
|
||||
|
||||
void Index::moveToGroup(std::string newGroupName) {
|
||||
// remove from old group
|
||||
if (indexGroup != INDEX_EVERY_GROUP) {
|
||||
// remove index from the unique group
|
||||
removeIndexFromGroup(this, indexGroup);
|
||||
removeIndexFromGroup(this, INDEX_ALL_PACKS);
|
||||
} else {
|
||||
// remove index from all groups inclusive INDEX_ALL_PACKS
|
||||
std::vector<std::string> groupNames = getGroupNames();
|
||||
for (int i = 0; i < groupNames.size(); i++)
|
||||
removeIndexFromGroup(this, groupNames[i]);
|
||||
// declare this index as not belonging to any group
|
||||
indexGroup = "";
|
||||
}
|
||||
|
||||
// create group if not existing
|
||||
if (newGroupName != INDEX_EVERY_GROUP) {
|
||||
std::map<std::string, std::vector<Index *> *>::iterator i = indexGroups.find(newGroupName);
|
||||
if (i == indexGroups.end()) {
|
||||
// make the group
|
||||
std::vector<Index *> *group = new std::vector<Index *>;
|
||||
indexGroups.insert(std::make_pair(newGroupName, group));
|
||||
app.state->addGroup(newGroupName, indexName, 0);
|
||||
|
||||
// fill group with indices that appear in every group
|
||||
std::map<std::string, Index *>::iterator iti;
|
||||
for (iti = indices.begin(); iti != indices.end(); iti++)
|
||||
if ((*iti).second->getGroupName() == INDEX_EVERY_GROUP)
|
||||
addIndexToGroup((*iti).second, group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
indexGroup = newGroupName;
|
||||
|
||||
// add to new group
|
||||
if (newGroupName != INDEX_EVERY_GROUP) {
|
||||
// insert according to user prefs or index defaults
|
||||
addIndexToGroup(this, getGroup(newGroupName));
|
||||
addIndexToGroup(this, getGroup(INDEX_ALL_PACKS));
|
||||
} else {
|
||||
// add index to all groups inclusive INDEX_ALL_PACKS
|
||||
std::map<std::string, std::vector<Index *> *>::iterator itg;
|
||||
for (itg = indexGroups.begin(); itg != indexGroups.end(); itg++)
|
||||
addIndexToGroup(this, (*itg).second);
|
||||
}
|
||||
|
||||
// store new group as users state
|
||||
app.state->setIndexGroup(indexName,
|
||||
newGroupName == defaultGroup ? "" : newGroupName);
|
||||
|
||||
// select this index with its new group if it is the current Index
|
||||
if (this == currentIndex) {
|
||||
if (indexGroup != INDEX_EVERY_GROUP &&
|
||||
app.state->getString("CurrentGroup") != INDEX_ALL_PACKS) {
|
||||
app.state->setProperty("CurrentGroup", indexGroup);
|
||||
currentGroup = indexGroup;
|
||||
}
|
||||
if (getGroupSelectedIndex(currentGroup) != currentIndex->getName()) {
|
||||
setGroupSelectedIndex(currentGroup, currentIndex->getName());
|
||||
setGroupSelectedColumn(currentGroup, INDEX_GROUP_COLUMN_UNKNOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int indexLocationCompare(Index * first, Index * second) {
|
||||
return first->getLocation() < second->getLocation();
|
||||
}
|
||||
|
||||
void Index::locateBehind(std::string predName) {
|
||||
double predLocation = 0;
|
||||
double succLocation = 0;
|
||||
double newLocation;
|
||||
std::string predGroup;
|
||||
std::string succGroup;
|
||||
std::vector<Index *> * allGroup = getGroup(INDEX_ALL_PACKS);
|
||||
if (predName.empty()) {
|
||||
succLocation = (*allGroup)[0]->indexLocation;
|
||||
succGroup = (*allGroup)[0]->indexGroup;
|
||||
} else {
|
||||
for (int i = 0; i < allGroup->size(); i++) {
|
||||
if ((*allGroup)[i]->getName() == predName) {
|
||||
predLocation = (*allGroup)[i]->indexLocation;
|
||||
predGroup = (*allGroup)[i]->indexGroup;
|
||||
int succ = 0;
|
||||
if ((i+1 < allGroup->size()) && ((*allGroup)[i+1] != this)) {
|
||||
succ = i + 1;
|
||||
} else if (i+2 < allGroup->size()) {
|
||||
succ = i + 2;
|
||||
}
|
||||
if (succ > 0) {
|
||||
succLocation = (*allGroup)[succ]->indexLocation;
|
||||
succGroup = (*allGroup)[succ]->indexGroup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT (!(predLocation == 0 && succLocation == 0), XFrontend, "");
|
||||
if (predLocation == 0) {
|
||||
if (succGroup == indexGroup) {
|
||||
newLocation = succLocation * 0.98;
|
||||
} else {
|
||||
newLocation = succLocation * 0.75;
|
||||
}
|
||||
} else if (succLocation == 0) {
|
||||
if (predGroup == indexGroup) {
|
||||
newLocation = predLocation + 100;
|
||||
} else {
|
||||
newLocation = predLocation + 10000;
|
||||
}
|
||||
} else if ((predGroup == indexGroup && succGroup == indexGroup) ||
|
||||
(predGroup != indexGroup && succGroup != indexGroup)){
|
||||
newLocation = (predLocation + succLocation) / 2;
|
||||
} else if (predGroup == indexGroup) {
|
||||
newLocation = 0.95 * predLocation + 0.05 * succLocation;
|
||||
} else {
|
||||
newLocation = 0.05 * predLocation + 0.95 * succLocation;
|
||||
}
|
||||
// Log << "newLocation " << newLocation << "\n";
|
||||
indexLocation = newLocation;
|
||||
app.state->setIndexLocation(indexName, indexLocation);
|
||||
|
||||
// reorder all groups according to new location
|
||||
std::map<std::string, std::vector<Index *> *>::iterator itg;
|
||||
for (itg = indexGroups.begin(); itg != indexGroups.end(); itg++)
|
||||
std::sort((*itg).second->begin(), (*itg).second->end(), indexLocationCompare);
|
||||
}
|
||||
|
||||
void Index::renameIndex(std::string newName) {
|
||||
indices.erase(indexName);
|
||||
indices[newName] = this;
|
||||
app.state->setIndexName(indexName, newName);
|
||||
indexName = newName;
|
||||
}
|
||||
|
||||
bool Index::isSource(Proxy *) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int Index::getCurrentPosition() {
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
int Index::getCurrentLevel() {
|
||||
return currentPosition + 1;
|
||||
}
|
||||
|
||||
Proxy * Index::getCurrent() {
|
||||
return getProxy(currentPosition);
|
||||
}
|
||||
|
||||
void Index::setCurrentPosition(int newPos) {
|
||||
// reset positions that are out of range - this may happen due to
|
||||
// editable Indices
|
||||
if (newPos < 0 || newPos > size())
|
||||
newPos = 0;
|
||||
|
||||
//
|
||||
currentPosition = newPos;
|
||||
app.state->setIndexCurpos(getName(), currentPosition);
|
||||
}
|
||||
|
||||
int Index::getScreenFirstPosition() {
|
||||
return screenFirstPosition;
|
||||
}
|
||||
|
||||
void Index::setScreenFirstPosition(int iFirstPos) {
|
||||
screenFirstPosition = iFirstPos;
|
||||
app.state->setIndexCurfirst(getName(), screenFirstPosition);
|
||||
}
|
||||
|
||||
bool Index::mayPlayLevel(int levelNumber) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Proxy * Index::getProxy(int pos) {
|
||||
if (pos >= 0 && pos < proxies.size())
|
||||
return proxies[pos];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Index::containsProxy(Proxy * aProxy) {
|
||||
for (int i = 0; i < proxies.size(); i++) {
|
||||
if (proxies[i] == aProxy)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Index::hasNormLevelPath(std::string path) {
|
||||
for (int i = 0; i < proxies.size(); i++) {
|
||||
if (proxies[i]->getNormLevelPath() == path)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Index::advanceLevel(LevelAdvanceMode advMode) {
|
||||
NextLevelMode nextMode = static_cast<NextLevelMode>(app.state->getInt("NextLevelMode"));
|
||||
|
||||
switch (advMode) {
|
||||
case ADVANCE_STRICTLY:
|
||||
nextMode = NEXT_LEVEL_STRICTLY;
|
||||
break;
|
||||
case ADVANCE_UNSOLVED:
|
||||
nextMode = NEXT_LEVEL_UNSOLVED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
bool found = false;
|
||||
const int max = size();
|
||||
int newPos = currentPosition;
|
||||
lev::ScoreManager *scm = lev::ScoreManager::instance();
|
||||
lev::RatingManager *ratingMgr = lev::RatingManager::instance();
|
||||
int difficulty = app.state->getInt("Difficulty");
|
||||
|
||||
while (newPos < max - 1 && !found) {
|
||||
++newPos;
|
||||
|
||||
if (nextMode == NEXT_LEVEL_UNSOLVED || nextMode == NEXT_LEVEL_NOT_BEST ||
|
||||
nextMode == NEXT_LEVEL_OVER_PAR) {
|
||||
bool solved = scm->isSolved(proxies[newPos], difficulty);
|
||||
if (!solved) // always play unsolved levels
|
||||
found = true;
|
||||
else { // solved levels
|
||||
if (nextMode == NEXT_LEVEL_NOT_BEST) {
|
||||
int par_time = ratingMgr->getBestScore(proxies[newPos], difficulty);
|
||||
int best_user_time = scm->getBestUserScore(proxies[newPos], difficulty);
|
||||
if (best_user_time<0 || (par_time>0 && best_user_time>par_time))
|
||||
found = true;
|
||||
} else if (nextMode == NEXT_LEVEL_OVER_PAR) {
|
||||
int par_time = ratingMgr->getParScore(proxies[newPos], difficulty);
|
||||
int best_user_time = scm->getBestUserScore(proxies[newPos], difficulty);
|
||||
if (best_user_time<0 || (par_time>0 && best_user_time>par_time))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
found = true;
|
||||
}
|
||||
if (!found)
|
||||
newPos = 0; // ?
|
||||
|
||||
currentPosition = newPos;
|
||||
return found;
|
||||
}
|
||||
|
||||
int Index::size() const {
|
||||
return proxies.size();
|
||||
}
|
||||
|
||||
void Index::appendProxy(Proxy * newLevel, controlType varCtrl,
|
||||
scoreUnitType varUnit, std::string varTarget,
|
||||
std::map<std::string, std::string> varExtensions) {
|
||||
proxies.push_back(newLevel);
|
||||
}
|
||||
|
||||
void Index::clear() {
|
||||
// proxies.clear();
|
||||
}
|
||||
|
||||
void Index::updateFromProxies() {
|
||||
for (int i = 0, l = proxies.size(); i < l; i++) {
|
||||
try {
|
||||
proxies[i]->loadMetadata(true);
|
||||
} catch (XLevelLoading &err) {
|
||||
// silently ignore errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- LevelPack interface ---------- */
|
||||
|
||||
|
||||
/*! Return the default SoundSet (see options::SoundSet for meaning) */
|
||||
const char* Index::get_default_SoundSet() const {
|
||||
return "Enigma";
|
||||
}
|
||||
|
||||
/*! Returns true if it's a twoplayer levelpack, but has no
|
||||
it-yinyang (needed to add it-yinyang to inventory if
|
||||
oxyd-linkgame is played as single-player) */
|
||||
bool Index::needs_twoplayers() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
}} // namespace enigma::lev
|
||||
179
project/jni/application/enigma/src/lev/Index.hh
Normal file
179
project/jni/application/enigma/src/lev/Index.hh
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef LEV_INDEX_HH_INCLUDED
|
||||
#define LEV_INDEX_HH_INCLUDED
|
||||
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define INDEX_DEFAULT_GROUP "User"
|
||||
#define INDEX_EVERY_GROUP "Every Group"
|
||||
#define INDEX_ALL_PACKS "All Packs"
|
||||
|
||||
#define INDEX_STARTUP_PACK_NAME "Startup Levels"
|
||||
#define INDEX_AUTO_PACK_NAME "Auto Folder"
|
||||
#define INDEX_HISTORY_PACK_NAME "History"
|
||||
#define INDEX_SEARCH_PACK_NAME "Search Result"
|
||||
#define INDEX_CLIPBOARD_PACK_NAME "Clipboard"
|
||||
|
||||
#define INDEX_STARTUP_PACK_LOCATION 5100
|
||||
#define INDEX_AUTO_PACK_LOCATION 5200
|
||||
#define INDEX_HISTORY_PACK_LOCATION 5300
|
||||
#define INDEX_SEARCH_PACK_LOCATION 5400
|
||||
#define INDEX_CLIPBOARD_PACK_LOCATION 5500
|
||||
|
||||
#define INDEX_USER_PACK_LOCATION 50000
|
||||
#define INDEX_DEFAULT_PACK_LOCATION 69000
|
||||
|
||||
#define INDEX_GROUP_COLUMN_UNKNOWN -1000
|
||||
|
||||
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
enum LevelAdvanceMode {
|
||||
ADVANCE_NEXT_MODE, // honor NextLevelMode
|
||||
ADVANCE_STRICTLY, // move to the next level in index
|
||||
ADVANCE_UNSOLVED // move to next not yet solved level
|
||||
};
|
||||
|
||||
enum NextLevelMode {
|
||||
NEXT_LEVEL_STRICTLY, // move to the next level in index
|
||||
NEXT_LEVEL_UNSOLVED, // move to next not yet solved level
|
||||
NEXT_LEVEL_NOT_BEST, // move to next level where player is not best score holder
|
||||
NEXT_LEVEL_OVER_PAR // move to next level with a score over PAR
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Index {
|
||||
public:
|
||||
static void initGroups();
|
||||
static void registerIndex(Index *anIndex);
|
||||
static Index * findIndex(std::string anIndexName);
|
||||
static Index * getCurrentIndex();
|
||||
static bool setCurrentIndex(std::string anIndexName);
|
||||
static Index * nextGroupIndex();
|
||||
static Index * previousGroupIndex();
|
||||
static Proxy * getCurrentProxy();
|
||||
static std::string getCurrentGroup();
|
||||
static void setCurrentGroup(std::string groupName);
|
||||
static std::vector<std::string> getGroupNames();
|
||||
static std::vector<Index *> * getGroup(std::string groupName);
|
||||
static std::string getGroupSelectedIndex(std::string groupName);
|
||||
static int getGroupSelectedColumn(std::string groupName);
|
||||
static void setGroupSelectedIndex(std::string groupName, std::string indexName);
|
||||
static void setGroupSelectedColumn(std::string groupName, int column);
|
||||
static void deleteGroup(std::string groupName);
|
||||
static void moveGroup(std::string groupName, int newPos);
|
||||
static void renameGroup(std::string oldName, std::string newName);
|
||||
static void insertGroup(std::string groupName, int newPos);
|
||||
static double getNextUserLocation();
|
||||
|
||||
/**
|
||||
* Convention: method names *Level() can take int pos or Proxy as arg.
|
||||
*/
|
||||
Index(std::string anIndexName = "Unnamed Pack",
|
||||
std::string aGroupName = INDEX_DEFAULT_GROUP,
|
||||
double defaultLocation = INDEX_DEFAULT_PACK_LOCATION);
|
||||
~Index();
|
||||
|
||||
std::string getName();
|
||||
std::string getGroupName();
|
||||
std::string getDefaultGroupName();
|
||||
double getLocation();
|
||||
double getDefaultLocation();
|
||||
void setDefaultLocation(double defLocation);
|
||||
void moveToGroup(std::string groupName);
|
||||
void locateBehind(std::string indexName);
|
||||
void renameIndex(std::string newName);
|
||||
virtual bool isSource(Proxy * aProxy);
|
||||
|
||||
int getCurrentPosition(); // 0 .. size-1
|
||||
int getCurrentLevel(); // 1 .. size
|
||||
Proxy * getCurrent();
|
||||
void setCurrentPosition(int newPos);
|
||||
int getScreenFirstPosition();
|
||||
void setScreenFirstPosition(int iFirstPos);
|
||||
virtual bool mayPlayLevel(int levelNumber);
|
||||
Proxy * getProxy(int pos);
|
||||
bool containsProxy(Proxy * aProxy);
|
||||
bool hasNormLevelPath(std::string path);
|
||||
virtual bool advanceLevel(LevelAdvanceMode advMode);
|
||||
|
||||
/*! Return number of levels */
|
||||
virtual int size() const;
|
||||
virtual void appendProxy(Proxy * newLevel, controlType varCtrl = force,
|
||||
scoreUnitType varUnit = duration, std::string varTarget = "time",
|
||||
std::map<std::string, std::string> varExtensions = nullExtensions);
|
||||
virtual void clear();
|
||||
void updateFromProxies();
|
||||
|
||||
// ---------- LevelPack legacy methods ---to be renamed ------- */
|
||||
/*! Return the default SoundSet (see options::SoundSet for meaning) */
|
||||
virtual const char* get_default_SoundSet() const;
|
||||
|
||||
/*! Returns true if it's a twoplayer levelpack, but has no
|
||||
it-yinyang (needed to add it-yinyang to inventory if
|
||||
oxyd-linkgame is played as single-player) */
|
||||
virtual bool needs_twoplayers() const;
|
||||
|
||||
|
||||
protected:
|
||||
std::string indexName;
|
||||
std::string indexGroup;
|
||||
double indexLocation;
|
||||
std::string defaultGroup;
|
||||
double indexDefaultLocation;
|
||||
int currentPosition; // 0,...
|
||||
int screenFirstPosition; // LevelWidget ifirst
|
||||
std::vector<Proxy *> proxies;
|
||||
static std::map<std::string, std::string> nullExtensions;
|
||||
|
||||
private:
|
||||
/**
|
||||
* A map of index names to the indices themselves.
|
||||
*/
|
||||
static std::map<std::string, Index *> indices;
|
||||
|
||||
/**
|
||||
* A map of index group names to vectors of indices. The vectors
|
||||
* are sorted by the user sequence preference in the index group menu.
|
||||
* Every index is listed in the group the user asigned it to.
|
||||
*/
|
||||
static std::map<std::string, std::vector<Index *> *> indexGroups;
|
||||
|
||||
/**
|
||||
* Current active index. This index is selected in the Levelpack menu,
|
||||
* shown and used in the submenus and stored in the user preferences.
|
||||
* It's default is the "Tutorial" index.
|
||||
*/
|
||||
static Index * currentIndex;
|
||||
static std::string currentGroup;
|
||||
|
||||
static void addIndexToGroup(Index *anIndex, std::vector<Index *> * aGroup);
|
||||
static void removeIndexFromGroup(Index *anIndex, std::string groupName);
|
||||
|
||||
};
|
||||
|
||||
}} // namespace enigma::lev
|
||||
#endif
|
||||
1102
project/jni/application/enigma/src/lev/PersistentIndex.cpp
Normal file
1102
project/jni/application/enigma/src/lev/PersistentIndex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
134
project/jni/application/enigma/src/lev/PersistentIndex.hh
Normal file
134
project/jni/application/enigma/src/lev/PersistentIndex.hh
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Ronald Lamprecht
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef LEV_PERSISTENTINDEX_HH_INCLUDED
|
||||
#define LEV_PERSISTENTINDEX_HH_INCLUDED
|
||||
|
||||
#include "lev/Index.hh"
|
||||
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <xercesc/dom/DOMDocument.hpp>
|
||||
|
||||
|
||||
#define INDEX_STD_FILENAME "index.xml"
|
||||
|
||||
namespace enigma { namespace lev {
|
||||
|
||||
struct Variation {
|
||||
// Constructor
|
||||
Variation(controlType ctrlValue = force, scoreUnitType unitValue = duration,
|
||||
std::string targetValue = "time");
|
||||
|
||||
controlType ctrl;
|
||||
scoreUnitType unit;
|
||||
std::string target;
|
||||
std::map<std::string, std::string> extensions;
|
||||
|
||||
bool operator == (const Variation& otherVar);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class PersistentIndex : public Index {
|
||||
public:
|
||||
static void registerPersistentIndices(bool onlySystemIndices);
|
||||
static PersistentIndex * historyIndex;
|
||||
static void addCurrentToHistory();
|
||||
|
||||
/**
|
||||
* Convention: method names *Level() can take int pos or Proxy as arg.
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* thePackPath " " for a new not yet defined path
|
||||
*/
|
||||
PersistentIndex(std::string thePackPath, bool systemOnly,
|
||||
double defaultLocation = INDEX_DEFAULT_PACK_LOCATION,
|
||||
std::string anIndexName = "",
|
||||
std::string theIndexFilename = INDEX_STD_FILENAME,
|
||||
std::string aGroupName = INDEX_DEFAULT_GROUP);
|
||||
/**
|
||||
* Legacy 0.92 constructor - called once to convert the index to XML.
|
||||
* When the index has been stored as XML this constructor will not be
|
||||
* called again.
|
||||
*/
|
||||
PersistentIndex(std::istream *legacyIndex, std::string thePackPath, bool isZip = false,
|
||||
std::string anIndexName = "", std::string theIndexFilename = INDEX_STD_FILENAME);
|
||||
~PersistentIndex();
|
||||
void load(bool systemOnly, bool update = false);
|
||||
void loadDoc();
|
||||
std::string getPackPath();
|
||||
bool setName(std::string newName);
|
||||
std::string getOwner();
|
||||
void setOwner(std::string newOwner);
|
||||
int getRelease();
|
||||
void setRelease(int newRelease);
|
||||
int getRevision();
|
||||
void setRevision(int newRevision);
|
||||
double getCompatibility();
|
||||
void setCompatibility(double newCompatibility);
|
||||
bool isUserEditable();
|
||||
bool isUpdatable();
|
||||
bool isCross();
|
||||
void markNewAsCross();
|
||||
virtual void clear();
|
||||
virtual void appendProxy(Proxy * newLevel, controlType varCtrl = force,
|
||||
scoreUnitType varUnit = duration, std::string varTarget = "time",
|
||||
std::map<std::string, std::string> varExtensions = nullExtensions);
|
||||
void insertProxy(int pos, Proxy * newLevel, bool allowDuplicates = true,
|
||||
controlType varCtrl = force, scoreUnitType varUnit = duration,
|
||||
std::string varTarget = "time",
|
||||
std::map<std::string, std::string> varExtensions = nullExtensions);
|
||||
Variation getVariation(int pos);
|
||||
void erase(int pos);
|
||||
void exchange(int pos1, int pos2);
|
||||
virtual bool isSource(Proxy * aProxy);
|
||||
bool save(bool allowOverwrite = true);
|
||||
protected:
|
||||
std::string packPath; // "auto", "",...
|
||||
std::string indexFilename;
|
||||
std::string owner;
|
||||
int release;
|
||||
int revision;
|
||||
double compatibility;
|
||||
std::vector<Variation> variations;
|
||||
bool isModified;
|
||||
bool isUserOwned;
|
||||
bool isEditable;
|
||||
std::string indexUrl;
|
||||
private:
|
||||
static std::vector<PersistentIndex *> indexCandidates;
|
||||
std::string absIndexPath;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *infoElem;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *updateElem;
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement *levelsElem;
|
||||
|
||||
static void checkCandidate(PersistentIndex * candidate);
|
||||
// legacy 0.92
|
||||
void parsePar(const string& par, int& par_value, std::string& par_text);
|
||||
};
|
||||
|
||||
void AddLevelPack (const char *init_file, const char *name);
|
||||
void AddZippedLevelPack (const char *zipfile);
|
||||
|
||||
}} // namespace enigma::lev
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user