mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-01 17:38:41 +00:00
Replace C++ mainmenu by formspec powered one
This commit is contained in:
parent
fe4ce03d52
commit
967121a34b
37 changed files with 8058 additions and 3949 deletions
|
@ -271,6 +271,7 @@ set(common_SRCS
|
|||
staticobject.cpp
|
||||
serverlist.cpp
|
||||
pathfinder.cpp
|
||||
convert_json.cpp
|
||||
${SCRIPT_SRCS}
|
||||
${UTIL_SRCS}
|
||||
)
|
||||
|
@ -313,7 +314,6 @@ set(minetest_SRCS
|
|||
clientobject.cpp
|
||||
chat.cpp
|
||||
hud.cpp
|
||||
guiMainMenu.cpp
|
||||
guiKeyChangeMenu.cpp
|
||||
guiMessageMenu.cpp
|
||||
guiTextInputMenu.cpp
|
||||
|
@ -323,15 +323,16 @@ set(minetest_SRCS
|
|||
guiVolumeChange.cpp
|
||||
guiDeathScreen.cpp
|
||||
guiChatConsole.cpp
|
||||
guiCreateWorld.cpp
|
||||
guiConfigureWorld.cpp
|
||||
guiConfirmMenu.cpp
|
||||
client.cpp
|
||||
filecache.cpp
|
||||
tile.cpp
|
||||
shader.cpp
|
||||
game.cpp
|
||||
main.cpp
|
||||
guiEngine.cpp
|
||||
guiLuaApi.cpp
|
||||
guiFileSelectMenu.cpp
|
||||
convert_json.cpp
|
||||
)
|
||||
|
||||
if(USE_FREETYPE)
|
||||
|
@ -488,7 +489,7 @@ else()
|
|||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${RELEASE_WARNING_FLAGS} ${WARNING_FLAGS} ${OTHER_FLAGS} -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -Wall ${WARNING_FLAGS} ${OTHER_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall ${WARNING_FLAGS} ${OTHER_FLAGS}")
|
||||
|
||||
if(USE_GPROF)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg")
|
||||
|
|
367
src/convert_json.cpp
Normal file
367
src/convert_json.cpp
Normal file
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 <vector>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "convert_json.h"
|
||||
#include "mods.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
|
||||
#if USE_CURL
|
||||
#include <curl/curl.h>
|
||||
|
||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Json::Value fetchJsonValue(const std::string url,
|
||||
struct curl_slist *chunk) {
|
||||
#if USE_CURL
|
||||
std::string liststring;
|
||||
CURL *curl;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (curl)
|
||||
{
|
||||
CURLcode res;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &liststring);
|
||||
|
||||
if (chunk != 0)
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
|
||||
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK)
|
||||
errorstream<<"Jsonreader: "<< url <<" not found (internet connection?)"<<std::endl;
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
Json::Value root;
|
||||
Json::Reader reader;
|
||||
std::istringstream stream(liststring);
|
||||
if (!liststring.size()) {
|
||||
return Json::Value();
|
||||
}
|
||||
|
||||
if (!reader.parse( stream, root ) )
|
||||
{
|
||||
errorstream << "URL: " << url << std::endl;
|
||||
errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
|
||||
errorstream << "data: \"" << liststring << "\"" << std::endl;
|
||||
return Json::Value();
|
||||
}
|
||||
|
||||
if (root.isArray()) {
|
||||
return root;
|
||||
}
|
||||
if ((root["list"].isArray())) {
|
||||
return root["list"];
|
||||
}
|
||||
else {
|
||||
return root;
|
||||
}
|
||||
#endif
|
||||
return Json::Value();
|
||||
}
|
||||
|
||||
std::vector<ModStoreMod> readModStoreList(Json::Value& modlist) {
|
||||
std::vector<ModStoreMod> retval;
|
||||
|
||||
if (modlist.isArray()) {
|
||||
for (unsigned int i = 0; i < modlist.size(); i++)
|
||||
{
|
||||
ModStoreMod toadd;
|
||||
toadd.valid = true;
|
||||
|
||||
//id
|
||||
if (modlist[i]["id"].asString().size()) {
|
||||
const char* id_raw = modlist[i]["id"].asString().c_str();
|
||||
char* endptr = 0;
|
||||
int numbervalue = strtol(id_raw,&endptr,10);
|
||||
|
||||
if ((*id_raw != 0) && (*endptr == 0)) {
|
||||
toadd.id = numbervalue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
toadd.valid = false;
|
||||
}
|
||||
|
||||
//title
|
||||
if (modlist[i]["title"].asString().size()) {
|
||||
toadd.title = modlist[i]["title"].asString();
|
||||
}
|
||||
else {
|
||||
toadd.valid = false;
|
||||
}
|
||||
|
||||
//basename
|
||||
if (modlist[i]["basename"].asString().size()) {
|
||||
toadd.basename = modlist[i]["basename"].asString();
|
||||
}
|
||||
else {
|
||||
toadd.valid = false;
|
||||
}
|
||||
|
||||
//author
|
||||
|
||||
//rating
|
||||
|
||||
//version
|
||||
|
||||
if (toadd.valid) {
|
||||
retval.push_back(toadd);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
ModStoreModDetails readModStoreModDetails(Json::Value& details) {
|
||||
|
||||
ModStoreModDetails retval;
|
||||
|
||||
retval.valid = true;
|
||||
|
||||
//version set
|
||||
if (details["version_set"].isArray()) {
|
||||
for (unsigned int i = 0; i < details["version_set"].size(); i++)
|
||||
{
|
||||
ModStoreVersionEntry toadd;
|
||||
|
||||
if (details["version_set"][i]["id"].asString().size()) {
|
||||
const char* id_raw = details["version_set"][i]["id"].asString().c_str();
|
||||
char* endptr = 0;
|
||||
int numbervalue = strtol(id_raw,&endptr,10);
|
||||
|
||||
if ((*id_raw != 0) && (*endptr == 0)) {
|
||||
toadd.id = numbervalue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
//date
|
||||
if (details["version_set"][i]["date"].asString().size()) {
|
||||
toadd.date = details["version_set"][i]["date"].asString();
|
||||
}
|
||||
|
||||
//file
|
||||
if (details["version_set"][i]["file"].asString().size()) {
|
||||
toadd.file = details["version_set"][i]["file"].asString();
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
//approved
|
||||
|
||||
//mtversion
|
||||
|
||||
if( retval.valid ) {
|
||||
retval.versions.push_back(toadd);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retval.versions.size() < 1) {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
//categories
|
||||
if (details["categories"].isObject()) {
|
||||
for (unsigned int i = 0; i < details["categories"].size(); i++) {
|
||||
ModStoreCategoryInfo toadd;
|
||||
|
||||
if (details["categories"][i]["id"].asString().size()) {
|
||||
|
||||
const char* id_raw = details["categories"][i]["id"].asString().c_str();
|
||||
char* endptr = 0;
|
||||
int numbervalue = strtol(id_raw,&endptr,10);
|
||||
|
||||
if ((*id_raw != 0) && (*endptr == 0)) {
|
||||
toadd.id = numbervalue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
if (details["categories"][i]["title"].asString().size()) {
|
||||
toadd.name = details["categories"][i]["title"].asString();
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
if( retval.valid ) {
|
||||
retval.categories.push_back(toadd);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//author
|
||||
if (details["author"].isObject()) {
|
||||
if (details["author"]["id"].asString().size()) {
|
||||
|
||||
const char* id_raw = details["author"]["id"].asString().c_str();
|
||||
char* endptr = 0;
|
||||
int numbervalue = strtol(id_raw,&endptr,10);
|
||||
|
||||
if ((*id_raw != 0) && (*endptr == 0)) {
|
||||
retval.author.id = numbervalue;
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
if (details["author"]["username"].asString().size()) {
|
||||
retval.author.username = details["author"]["username"].asString();
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
//license
|
||||
if (details["license"].isObject()) {
|
||||
if (details["license"]["id"].asString().size()) {
|
||||
|
||||
const char* id_raw = details["license"]["id"].asString().c_str();
|
||||
char* endptr = 0;
|
||||
int numbervalue = strtol(id_raw,&endptr,10);
|
||||
|
||||
if ((*id_raw != 0) && (*endptr == 0)) {
|
||||
retval.license.id = numbervalue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
if (details["license"]["short"].asString().size()) {
|
||||
retval.license.shortinfo = details["license"]["short"].asString();
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
if (details["license"]["link"].asString().size()) {
|
||||
retval.license.url = details["license"]["link"].asString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//id
|
||||
if (details["id"].asString().size()) {
|
||||
|
||||
const char* id_raw = details["id"].asString().c_str();
|
||||
char* endptr = 0;
|
||||
int numbervalue = strtol(id_raw,&endptr,10);
|
||||
|
||||
if ((*id_raw != 0) && (*endptr == 0)) {
|
||||
retval.id = numbervalue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
//title
|
||||
if (details["title"].asString().size()) {
|
||||
retval.title = details["title"].asString();
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
//basename
|
||||
if (details["basename"].asString().size()) {
|
||||
retval.basename = details["basename"].asString();
|
||||
}
|
||||
else {
|
||||
retval.valid = false;
|
||||
}
|
||||
|
||||
//description
|
||||
if (details["desc"].asString().size()) {
|
||||
retval.description = details["desc"].asString();
|
||||
}
|
||||
|
||||
//repository
|
||||
if (details["replink"].asString().size()) {
|
||||
retval.repository = details["replink"].asString();
|
||||
}
|
||||
|
||||
//value
|
||||
if (details["rating"].asString().size()) {
|
||||
|
||||
const char* id_raw = details["rating"].asString().c_str();
|
||||
char* endptr = 0;
|
||||
float numbervalue = strtof(id_raw,&endptr);
|
||||
|
||||
if ((*id_raw != 0) && (*endptr == 0)) {
|
||||
retval.rating = numbervalue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval.rating = 0.0;
|
||||
}
|
||||
|
||||
//depends
|
||||
if (details["depends"].isArray()) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
//softdepends
|
||||
if (details["softdep"].isArray()) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
//screenshot url
|
||||
if (details["screenshot_url"].asString().size()) {
|
||||
retval.screenshot_url = details["screenshot_url"].asString();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -17,40 +17,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef GUICONFIRMMENU_HEADER
|
||||
#define GUICONFIRMMENU_HEADER
|
||||
#ifndef __CONVERT_JSON_H__
|
||||
#define __CONVERT_JSON_H__
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "modalMenu.h"
|
||||
#include <string>
|
||||
#include "json/json.h"
|
||||
|
||||
struct ConfirmDest
|
||||
{
|
||||
virtual void answer(bool answer) = 0;
|
||||
virtual ~ConfirmDest() {};
|
||||
};
|
||||
struct ModStoreMod;
|
||||
struct ModStoreModDetails;
|
||||
|
||||
class GUIConfirmMenu : public GUIModalMenu
|
||||
{
|
||||
public:
|
||||
GUIConfirmMenu(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
ConfirmDest *dest,
|
||||
std::wstring message_text);
|
||||
~GUIConfirmMenu();
|
||||
|
||||
void removeChildren();
|
||||
// Remove and re-add (or reposition) stuff
|
||||
void regenerateGui(v2u32 screensize);
|
||||
void drawMenu();
|
||||
void acceptInput(bool answer);
|
||||
bool OnEvent(const SEvent& event);
|
||||
|
||||
private:
|
||||
ConfirmDest *m_dest;
|
||||
std::wstring m_message_text;
|
||||
};
|
||||
std::vector<ModStoreMod> readModStoreList(Json::Value& modlist);
|
||||
ModStoreModDetails readModStoreModDetails(Json::Value& details);
|
||||
|
||||
Json::Value fetchJsonValue(const std::string url,
|
||||
struct curl_slist *chunk);
|
||||
|
||||
#endif
|
||||
|
|
@ -256,6 +256,11 @@ void set_default_settings(Settings *settings)
|
|||
// IPv6
|
||||
settings->setDefault("enable_ipv6", "true");
|
||||
settings->setDefault("ipv6_server", "false");
|
||||
|
||||
settings->setDefault("modstore_download_url", "http://forum.minetest.net/media/");
|
||||
settings->setDefault("modstore_listmods_url", "http://forum.minetest.net/mmdb/mods/");
|
||||
settings->setDefault("modstore_details_url", "http://forum.minetest.net/mmdb/mod/*/");
|
||||
|
||||
}
|
||||
|
||||
void override_default_settings(Settings *settings, Settings *from)
|
||||
|
|
267
src/filesys.cpp
267
src/filesys.cpp
|
@ -20,7 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "filesys.h"
|
||||
#include "strfnd.h"
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "log.h"
|
||||
|
||||
namespace fs
|
||||
|
@ -30,11 +32,9 @@ namespace fs
|
|||
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <tchar.h>
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define BUFSIZE MAX_PATH
|
||||
|
||||
|
@ -145,6 +145,11 @@ bool IsDir(std::string path)
|
|||
(attr & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
||||
bool IsDirDelimiter(char c)
|
||||
{
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
bool RecursiveDelete(std::string path)
|
||||
{
|
||||
infostream<<"Recursively deleting \""<<path<<"\""<<std::endl;
|
||||
|
@ -207,11 +212,26 @@ bool DeleteSingleFileOrEmptyDirectory(std::string path)
|
|||
}
|
||||
}
|
||||
|
||||
std::string TempPath()
|
||||
{
|
||||
DWORD bufsize = GetTempPath(0, "");
|
||||
if(bufsize == 0){
|
||||
errorstream<<"GetTempPath failed, error = "<<GetLastError()<<std::endl;
|
||||
return "";
|
||||
}
|
||||
std::vector<char> buf(bufsize);
|
||||
DWORD len = GetTempPath(bufsize, &buf[0]);
|
||||
if(len == 0 || len > bufsize){
|
||||
errorstream<<"GetTempPath failed, error = "<<GetLastError()<<std::endl;
|
||||
return "";
|
||||
}
|
||||
return std::string(buf.begin(), buf.begin() + len);
|
||||
}
|
||||
|
||||
#else // POSIX
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
@ -301,6 +321,11 @@ bool IsDir(std::string path)
|
|||
return ((statbuf.st_mode & S_IFDIR) == S_IFDIR);
|
||||
}
|
||||
|
||||
bool IsDirDelimiter(char c)
|
||||
{
|
||||
return c == '/';
|
||||
}
|
||||
|
||||
bool RecursiveDelete(std::string path)
|
||||
{
|
||||
/*
|
||||
|
@ -364,6 +389,20 @@ bool DeleteSingleFileOrEmptyDirectory(std::string path)
|
|||
}
|
||||
}
|
||||
|
||||
std::string TempPath()
|
||||
{
|
||||
/*
|
||||
Should the environment variables TMPDIR, TMP and TEMP
|
||||
and the macro P_tmpdir (if defined by stdio.h) be checked
|
||||
before falling back on /tmp?
|
||||
|
||||
Probably not, because this function is intended to be
|
||||
compatible with lua's os.tmpname which under the default
|
||||
configuration hardcodes mkstemp("/tmp/lua_XXXXXX").
|
||||
*/
|
||||
return std::string(DIR_DELIM) + "tmp";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void GetRecursiveSubPaths(std::string path, std::vector<std::string> &dst)
|
||||
|
@ -414,16 +453,14 @@ bool RecursiveDeleteContent(std::string path)
|
|||
bool CreateAllDirs(std::string path)
|
||||
{
|
||||
|
||||
size_t pos;
|
||||
std::vector<std::string> tocreate;
|
||||
std::string basepath = path;
|
||||
while(!PathExists(basepath))
|
||||
{
|
||||
tocreate.push_back(basepath);
|
||||
pos = basepath.rfind(DIR_DELIM_C);
|
||||
if(pos == std::string::npos)
|
||||
basepath = RemoveLastPathComponent(basepath);
|
||||
if(basepath.empty())
|
||||
break;
|
||||
basepath = basepath.substr(0,pos);
|
||||
}
|
||||
for(int i=tocreate.size()-1;i>=0;i--)
|
||||
if(!CreateDir(tocreate[i]))
|
||||
|
@ -431,5 +468,221 @@ bool CreateAllDirs(std::string path)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CopyFileContents(std::string source, std::string target)
|
||||
{
|
||||
FILE *sourcefile = fopen(source.c_str(), "rb");
|
||||
if(sourcefile == NULL){
|
||||
errorstream<<source<<": can't open for reading: "
|
||||
<<strerror(errno)<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE *targetfile = fopen(target.c_str(), "wb");
|
||||
if(targetfile == NULL){
|
||||
errorstream<<target<<": can't open for writing: "
|
||||
<<strerror(errno)<<std::endl;
|
||||
fclose(sourcefile);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t total = 0;
|
||||
bool retval = true;
|
||||
bool done = false;
|
||||
char readbuffer[BUFSIZ];
|
||||
while(!done){
|
||||
size_t readbytes = fread(readbuffer, 1,
|
||||
sizeof(readbuffer), sourcefile);
|
||||
total += readbytes;
|
||||
if(ferror(sourcefile)){
|
||||
errorstream<<source<<": IO error: "
|
||||
<<strerror(errno)<<std::endl;
|
||||
retval = false;
|
||||
done = true;
|
||||
}
|
||||
if(readbytes > 0){
|
||||
fwrite(readbuffer, 1, readbytes, targetfile);
|
||||
}
|
||||
if(feof(sourcefile) || ferror(sourcefile)){
|
||||
// flush destination file to catch write errors
|
||||
// (e.g. disk full)
|
||||
fflush(targetfile);
|
||||
done = true;
|
||||
}
|
||||
if(ferror(targetfile)){
|
||||
errorstream<<target<<": IO error: "
|
||||
<<strerror(errno)<<std::endl;
|
||||
retval = false;
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
infostream<<"copied "<<total<<" bytes from "
|
||||
<<source<<" to "<<target<<std::endl;
|
||||
fclose(sourcefile);
|
||||
fclose(targetfile);
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool CopyDir(std::string source, std::string target)
|
||||
{
|
||||
if(PathExists(source)){
|
||||
if(!PathExists(target)){
|
||||
fs::CreateAllDirs(target);
|
||||
}
|
||||
bool retval = true;
|
||||
std::vector<DirListNode> content = fs::GetDirListing(source);
|
||||
|
||||
for(unsigned int i=0; i < content.size(); i++){
|
||||
std::string sourcechild = source + DIR_DELIM + content[i].name;
|
||||
std::string targetchild = target + DIR_DELIM + content[i].name;
|
||||
if(content[i].dir){
|
||||
if(!fs::CopyDir(sourcechild, targetchild)){
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!fs::CopyFileContents(sourcechild, targetchild)){
|
||||
retval = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PathStartsWith(std::string path, std::string prefix)
|
||||
{
|
||||
size_t pathsize = path.size();
|
||||
size_t pathpos = 0;
|
||||
size_t prefixsize = prefix.size();
|
||||
size_t prefixpos = 0;
|
||||
for(;;){
|
||||
bool delim1 = pathpos == pathsize
|
||||
|| IsDirDelimiter(path[pathpos]);
|
||||
bool delim2 = prefixpos == prefixsize
|
||||
|| IsDirDelimiter(prefix[prefixpos]);
|
||||
|
||||
if(delim1 != delim2)
|
||||
return false;
|
||||
|
||||
if(delim1){
|
||||
while(pathpos < pathsize &&
|
||||
IsDirDelimiter(path[pathpos]))
|
||||
++pathpos;
|
||||
while(prefixpos < prefixsize &&
|
||||
IsDirDelimiter(prefix[prefixpos]))
|
||||
++prefixpos;
|
||||
if(prefixpos == prefixsize)
|
||||
return true;
|
||||
if(pathpos == pathsize)
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
size_t len = 0;
|
||||
do{
|
||||
char pathchar = path[pathpos+len];
|
||||
char prefixchar = prefix[prefixpos+len];
|
||||
if(FILESYS_CASE_INSENSITIVE){
|
||||
pathchar = tolower(pathchar);
|
||||
prefixchar = tolower(prefixchar);
|
||||
}
|
||||
if(pathchar != prefixchar)
|
||||
return false;
|
||||
++len;
|
||||
} while(pathpos+len < pathsize
|
||||
&& !IsDirDelimiter(path[pathpos+len])
|
||||
&& prefixpos+len < prefixsize
|
||||
&& !IsDirDelimiter(
|
||||
prefix[prefixsize+len]));
|
||||
pathpos += len;
|
||||
prefixpos += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string RemoveLastPathComponent(std::string path,
|
||||
std::string *removed, int count)
|
||||
{
|
||||
if(removed)
|
||||
*removed = "";
|
||||
|
||||
size_t remaining = path.size();
|
||||
|
||||
for(int i = 0; i < count; ++i){
|
||||
// strip a dir delimiter
|
||||
while(remaining != 0 && IsDirDelimiter(path[remaining-1]))
|
||||
remaining--;
|
||||
// strip a path component
|
||||
size_t component_end = remaining;
|
||||
while(remaining != 0 && !IsDirDelimiter(path[remaining-1]))
|
||||
remaining--;
|
||||
size_t component_start = remaining;
|
||||
// strip a dir delimiter
|
||||
while(remaining != 0 && IsDirDelimiter(path[remaining-1]))
|
||||
remaining--;
|
||||
if(removed){
|
||||
std::string component = path.substr(component_start,
|
||||
component_end - component_start);
|
||||
if(i)
|
||||
*removed = component + DIR_DELIM + *removed;
|
||||
else
|
||||
*removed = component;
|
||||
}
|
||||
}
|
||||
return path.substr(0, remaining);
|
||||
}
|
||||
|
||||
std::string RemoveRelativePathComponents(std::string path)
|
||||
{
|
||||
size_t pos = path.size();
|
||||
size_t dotdot_count = 0;
|
||||
while(pos != 0){
|
||||
size_t component_with_delim_end = pos;
|
||||
// skip a dir delimiter
|
||||
while(pos != 0 && IsDirDelimiter(path[pos-1]))
|
||||
pos--;
|
||||
// strip a path component
|
||||
size_t component_end = pos;
|
||||
while(pos != 0 && !IsDirDelimiter(path[pos-1]))
|
||||
pos--;
|
||||
size_t component_start = pos;
|
||||
|
||||
std::string component = path.substr(component_start,
|
||||
component_end - component_start);
|
||||
bool remove_this_component = false;
|
||||
if(component == "."){
|
||||
remove_this_component = true;
|
||||
}
|
||||
else if(component == ".."){
|
||||
remove_this_component = true;
|
||||
dotdot_count += 1;
|
||||
}
|
||||
else if(dotdot_count != 0){
|
||||
remove_this_component = true;
|
||||
dotdot_count -= 1;
|
||||
}
|
||||
|
||||
if(remove_this_component){
|
||||
while(pos != 0 && IsDirDelimiter(path[pos-1]))
|
||||
pos--;
|
||||
path = path.substr(0, pos) + DIR_DELIM +
|
||||
path.substr(component_with_delim_end,
|
||||
std::string::npos);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
if(dotdot_count > 0)
|
||||
return "";
|
||||
|
||||
// remove trailing dir delimiters
|
||||
pos = path.size();
|
||||
while(pos != 0 && IsDirDelimiter(path[pos-1]))
|
||||
pos--;
|
||||
return path.substr(0, pos);
|
||||
}
|
||||
|
||||
} // namespace fs
|
||||
|
||||
|
|
|
@ -26,10 +26,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#ifdef _WIN32 // WINDOWS
|
||||
#define DIR_DELIM "\\"
|
||||
#define DIR_DELIM_C '\\'
|
||||
#define FILESYS_CASE_INSENSITIVE 1
|
||||
#else // POSIX
|
||||
#define DIR_DELIM "/"
|
||||
#define DIR_DELIM_C '/'
|
||||
#define FILESYS_CASE_INSENSITIVE 0
|
||||
#endif
|
||||
|
||||
namespace fs
|
||||
|
@ -49,12 +49,17 @@ bool PathExists(std::string path);
|
|||
|
||||
bool IsDir(std::string path);
|
||||
|
||||
bool IsDirDelimiter(char c);
|
||||
|
||||
// Only pass full paths to this one. True on success.
|
||||
// NOTE: The WIN32 version returns always true.
|
||||
bool RecursiveDelete(std::string path);
|
||||
|
||||
bool DeleteSingleFileOrEmptyDirectory(std::string path);
|
||||
|
||||
// Returns path to temp directory, can return "" on error
|
||||
std::string TempPath();
|
||||
|
||||
/* Multiplatform */
|
||||
|
||||
// The path itself not included
|
||||
|
@ -69,6 +74,30 @@ bool RecursiveDeleteContent(std::string path);
|
|||
// Create all directories on the given path that don't already exist.
|
||||
bool CreateAllDirs(std::string path);
|
||||
|
||||
// Copy a regular file
|
||||
bool CopyFileContents(std::string source, std::string target);
|
||||
|
||||
// Copy directory and all subdirectories
|
||||
// Omits files and subdirectories that start with a period
|
||||
bool CopyDir(std::string source, std::string target);
|
||||
|
||||
// Check if one path is prefix of another
|
||||
// For example, "/tmp" is a prefix of "/tmp" and "/tmp/file" but not "/tmp2"
|
||||
// Ignores case differences and '/' vs. '\\' on Windows
|
||||
bool PathStartsWith(std::string path, std::string prefix);
|
||||
|
||||
// Remove last path component and the dir delimiter before and/or after it,
|
||||
// returns "" if there is only one path component.
|
||||
// removed: If non-NULL, receives the removed component(s).
|
||||
// count: Number of components to remove
|
||||
std::string RemoveLastPathComponent(std::string path,
|
||||
std::string *removed = NULL, int count = 1);
|
||||
|
||||
// Remove "." and ".." path components and for every ".." removed, remove
|
||||
// the last normal path component before it. Unlike AbsolutePath,
|
||||
// this does not resolve symlinks and check for existence of directories.
|
||||
std::string RemoveRelativePathComponents(std::string path);
|
||||
|
||||
}//fs
|
||||
|
||||
#endif
|
||||
|
|
27
src/game.cpp
27
src/game.cpp
|
@ -208,33 +208,6 @@ public:
|
|||
Client *m_client;
|
||||
};
|
||||
|
||||
class FormspecFormSource: public IFormSource
|
||||
{
|
||||
public:
|
||||
FormspecFormSource(std::string formspec,FormspecFormSource** game_formspec)
|
||||
{
|
||||
m_formspec = formspec;
|
||||
m_game_formspec = game_formspec;
|
||||
}
|
||||
|
||||
~FormspecFormSource()
|
||||
{
|
||||
*m_game_formspec = 0;
|
||||
}
|
||||
|
||||
void setForm(std::string formspec) {
|
||||
m_formspec = formspec;
|
||||
}
|
||||
|
||||
std::string getForm()
|
||||
{
|
||||
return m_formspec;
|
||||
}
|
||||
|
||||
std::string m_formspec;
|
||||
FormspecFormSource** m_game_formspec;
|
||||
};
|
||||
|
||||
/*
|
||||
Check if a node is pointable
|
||||
*/
|
||||
|
|
|
@ -1,693 +0,0 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "guiConfigureWorld.h"
|
||||
#include "guiMessageMenu.h"
|
||||
#include <IGUIButton.h>
|
||||
#include <IGUICheckBox.h>
|
||||
#include <IGUIListBox.h>
|
||||
#include <IGUIStaticText.h>
|
||||
#include <IGUITreeView.h>
|
||||
#include "gettext.h"
|
||||
#include "util/string.h"
|
||||
#include "settings.h"
|
||||
#include "filesys.h"
|
||||
|
||||
enum
|
||||
{
|
||||
GUI_ID_MOD_TREEVIEW = 101,
|
||||
GUI_ID_ENABLED_CHECKBOX,
|
||||
GUI_ID_ENABLEALL,
|
||||
GUI_ID_DISABLEALL,
|
||||
GUI_ID_DEPENDS_LISTBOX,
|
||||
GUI_ID_RDEPENDS_LISTBOX,
|
||||
GUI_ID_CANCEL,
|
||||
GUI_ID_SAVE
|
||||
};
|
||||
|
||||
#define QUESTIONMARK_STR L"?"
|
||||
#define CHECKMARK_STR L"\411"
|
||||
#define CROSS_STR L"\403"
|
||||
|
||||
GUIConfigureWorld::GUIConfigureWorld(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr, WorldSpec wspec):
|
||||
GUIModalMenu(env, parent, id, menumgr),
|
||||
m_wspec(wspec),
|
||||
m_gspec(findWorldSubgame(m_wspec.path)),
|
||||
m_menumgr(menumgr)
|
||||
{
|
||||
//will be initialized in regenerateGUI()
|
||||
m_treeview=NULL;
|
||||
|
||||
// game mods
|
||||
m_gamemods = flattenModTree(getModsInPath(m_gspec.gamemods_path));
|
||||
|
||||
// world mods
|
||||
std::string worldmods_path = wspec.path + DIR_DELIM + "worldmods";
|
||||
m_worldmods = flattenModTree(getModsInPath(worldmods_path));
|
||||
|
||||
// fill m_addontree with add-on mods
|
||||
std::set<std::string> paths = m_gspec.addon_mods_paths;
|
||||
for(std::set<std::string>::iterator it=paths.begin();
|
||||
it != paths.end(); ++it)
|
||||
{
|
||||
std::map<std::string,ModSpec> mods = getModsInPath(*it);
|
||||
m_addontree.insert(mods.begin(), mods.end());
|
||||
}
|
||||
|
||||
// expand modpacks
|
||||
m_addonmods = flattenModTree(m_addontree);
|
||||
|
||||
// collect reverse dependencies
|
||||
for(std::map<std::string, ModSpec>::iterator it = m_addonmods.begin();
|
||||
it != m_addonmods.end(); ++it)
|
||||
{
|
||||
std::string modname = (*it).first;
|
||||
ModSpec mod = (*it).second;
|
||||
for(std::set<std::string>::iterator dep_it = mod.depends.begin();
|
||||
dep_it != mod.depends.end(); ++dep_it)
|
||||
{
|
||||
m_reverse_depends.insert(std::make_pair((*dep_it),modname));
|
||||
}
|
||||
}
|
||||
|
||||
m_settings.readConfigFile((m_wspec.path + DIR_DELIM + "world.mt").c_str());
|
||||
std::vector<std::string> names = m_settings.getNames();
|
||||
|
||||
// mod_names contains the names of mods mentioned in the world.mt file
|
||||
std::set<std::string> mod_names;
|
||||
for(std::vector<std::string>::iterator it = names.begin();
|
||||
it != names.end(); ++it)
|
||||
{
|
||||
std::string name = *it;
|
||||
if (name.compare(0,9,"load_mod_")==0)
|
||||
mod_names.insert(name.substr(9));
|
||||
}
|
||||
|
||||
// find new mods (installed but not mentioned in world.mt)
|
||||
for(std::map<std::string, ModSpec>::iterator it = m_addonmods.begin();
|
||||
it != m_addonmods.end(); ++it)
|
||||
{
|
||||
std::string modname = (*it).first;
|
||||
ModSpec mod = (*it).second;
|
||||
// a mod is new if it is not a modpack, and does not occur in
|
||||
// mod_names
|
||||
if(!mod.is_modpack &&
|
||||
mod_names.count(modname) == 0)
|
||||
m_settings.setBool("load_mod_"+modname, false);
|
||||
}
|
||||
// find missing mods (mentioned in world.mt, but not installed)
|
||||
for(std::set<std::string>::iterator it = mod_names.begin();
|
||||
it != mod_names.end(); ++it)
|
||||
{
|
||||
std::string modname = *it;
|
||||
if(m_addonmods.count(modname) == 0)
|
||||
m_settings.remove("load_mod_"+modname);
|
||||
}
|
||||
std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
|
||||
m_settings.updateConfigFile(worldmtfile.c_str());
|
||||
}
|
||||
|
||||
void GUIConfigureWorld::drawMenu()
|
||||
{
|
||||
gui::IGUISkin* skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
return;
|
||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||
|
||||
video::SColor bgcolor(140,0,0,0);
|
||||
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
|
||||
|
||||
gui::IGUIElement::draw();
|
||||
}
|
||||
|
||||
|
||||
void GUIConfigureWorld::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
|
||||
/*
|
||||
Remove stuff
|
||||
*/
|
||||
removeChildren();
|
||||
|
||||
/*
|
||||
Calculate new sizes and positions
|
||||
*/
|
||||
core::rect<s32> rect(
|
||||
screensize.X/2 - 580/2,
|
||||
screensize.Y/2 - 300/2,
|
||||
screensize.X/2 + 580/2,
|
||||
screensize.Y/2 + 300/2
|
||||
);
|
||||
|
||||
DesiredRect = rect;
|
||||
recalculateAbsolutePosition(false);
|
||||
|
||||
v2s32 topleft = v2s32(10, 10);
|
||||
|
||||
/*
|
||||
Add stuff
|
||||
*/
|
||||
changeCtype("");
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 200, 20);
|
||||
rect += topleft;
|
||||
//proper text is set below, when a mod is selected
|
||||
m_modname_text = Environment->addStaticText(L"Mod: N/A", rect, false,
|
||||
false, this, -1);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 200, 20);
|
||||
rect += v2s32(0, 25) + topleft;
|
||||
wchar_t* text = wgettext("enabled");
|
||||
m_enabled_checkbox =
|
||||
Environment->addCheckBox(false, rect, this, GUI_ID_ENABLED_CHECKBOX,
|
||||
text);
|
||||
delete[] text;
|
||||
m_enabled_checkbox->setVisible(false);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 85, 30);
|
||||
rect = rect + v2s32(0, 25) + topleft;
|
||||
wchar_t* text = wgettext("Enable All");
|
||||
m_enableall = Environment->addButton(rect, this, GUI_ID_ENABLEALL,
|
||||
text);
|
||||
delete[] text;
|
||||
m_enableall->setVisible(false);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 85, 30);
|
||||
rect = rect + v2s32(115, 25) + topleft;
|
||||
wchar_t* text = wgettext("Disable All");
|
||||
m_disableall = Environment->addButton(rect, this, GUI_ID_DISABLEALL, text );
|
||||
delete[] text;
|
||||
m_disableall->setVisible(false);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 200, 20);
|
||||
rect += v2s32(0, 60) + topleft;
|
||||
wchar_t* text = wgettext("depends on:");
|
||||
Environment->addStaticText(text, rect, false, false, this, -1);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 200, 85);
|
||||
rect += v2s32(0, 80) + topleft;
|
||||
m_dependencies_listbox =
|
||||
Environment->addListBox(rect, this, GUI_ID_DEPENDS_LISTBOX, true);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 200, 20);
|
||||
rect += v2s32(0, 175) + topleft;
|
||||
wchar_t* text = wgettext("is required by:");
|
||||
Environment->addStaticText( text, rect, false, false, this, -1);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 200, 85);
|
||||
rect += v2s32(0, 195) + topleft;
|
||||
m_rdependencies_listbox =
|
||||
Environment->addListBox(rect,this, GUI_ID_RDEPENDS_LISTBOX,true);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 340, 250);
|
||||
rect += v2s32(220, 0) + topleft;
|
||||
m_treeview = Environment->addTreeView(rect, this,
|
||||
GUI_ID_MOD_TREEVIEW,true);
|
||||
gui::IGUITreeViewNode* node
|
||||
= m_treeview->getRoot()->addChildBack(L"Add-Ons");
|
||||
buildTreeView(m_addontree, node);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 120, 30);
|
||||
rect = rect + v2s32(330, 270) - topleft;
|
||||
wchar_t* text = wgettext("Cancel");
|
||||
Environment->addButton(rect, this, GUI_ID_CANCEL, text);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 120, 30);
|
||||
rect = rect + v2s32(460, 270) - topleft;
|
||||
wchar_t* text = wgettext("Save");
|
||||
Environment->addButton(rect, this, GUI_ID_SAVE, text);
|
||||
delete[] text;
|
||||
}
|
||||
changeCtype("C");
|
||||
|
||||
// at start, none of the treeview nodes is selected, so we select
|
||||
// the first element in the treeview of mods manually here.
|
||||
if(m_treeview->getRoot()->hasChilds())
|
||||
{
|
||||
m_treeview->getRoot()->getFirstChild()->setExpanded(true);
|
||||
m_treeview->getRoot()->getFirstChild()->setSelected(true);
|
||||
// Because a manual ->setSelected() doesn't cause an event, we
|
||||
// have to do this here:
|
||||
adjustSidebar();
|
||||
}
|
||||
}
|
||||
|
||||
bool GUIConfigureWorld::OnEvent(const SEvent& event)
|
||||
{
|
||||
|
||||
gui::IGUITreeViewNode* selected_node = NULL;
|
||||
if(m_treeview != NULL)
|
||||
selected_node = m_treeview->getSelected();
|
||||
|
||||
if(event.EventType==EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
|
||||
{
|
||||
switch (event.KeyInput.Key) {
|
||||
case KEY_ESCAPE: {
|
||||
quitMenu();
|
||||
return true;
|
||||
}
|
||||
// irrlicht's built-in TreeView gui has no keyboard control,
|
||||
// so we do it here: up/down to select prev/next node,
|
||||
// left/right to collapse/expand nodes, space to toggle
|
||||
// enabled/disabled.
|
||||
case KEY_DOWN: {
|
||||
if(selected_node != NULL)
|
||||
{
|
||||
gui::IGUITreeViewNode* node = selected_node->getNextVisible();
|
||||
if(node != NULL)
|
||||
{
|
||||
node->setSelected(true);
|
||||
adjustSidebar();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case KEY_UP: {
|
||||
if(selected_node != NULL)
|
||||
{
|
||||
gui::IGUITreeViewNode* node = selected_node->getPrevSibling();
|
||||
if(node!=NULL)
|
||||
{
|
||||
node->setSelected(true);
|
||||
adjustSidebar();
|
||||
}
|
||||
else
|
||||
{
|
||||
gui::IGUITreeViewNode* parent = selected_node->getParent();
|
||||
if(selected_node == parent->getFirstChild() &&
|
||||
parent != m_treeview->getRoot())
|
||||
{
|
||||
parent->setSelected(true);
|
||||
adjustSidebar();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case KEY_RIGHT: {
|
||||
if(selected_node != NULL && selected_node->hasChilds())
|
||||
selected_node->setExpanded(true);
|
||||
return true;
|
||||
}
|
||||
case KEY_LEFT: {
|
||||
if(selected_node != NULL && selected_node->hasChilds())
|
||||
selected_node->setExpanded(false);
|
||||
return true;
|
||||
}
|
||||
case KEY_SPACE: {
|
||||
if(selected_node != NULL && !selected_node->hasChilds() &&
|
||||
selected_node->getText() != NULL)
|
||||
{
|
||||
std::string modname = wide_to_narrow(selected_node->getText());
|
||||
bool checked = m_enabled_checkbox->isChecked();
|
||||
m_enabled_checkbox->setChecked(!checked);
|
||||
setEnabled(modname,!checked);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default: {}
|
||||
}
|
||||
}
|
||||
if(event.EventType==EET_GUI_EVENT)
|
||||
{
|
||||
if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
|
||||
&& isVisible())
|
||||
{
|
||||
if(!canTakeFocus(event.GUIEvent.Element))
|
||||
{
|
||||
dstream<<"GUIConfigureWorld: Not allowing focus change."
|
||||
<<std::endl;
|
||||
// Returning true disables focus change
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED){
|
||||
switch(event.GUIEvent.Caller->getID()){
|
||||
case GUI_ID_CANCEL: {
|
||||
quitMenu();
|
||||
return true;
|
||||
}
|
||||
case GUI_ID_SAVE: {
|
||||
std::string worldmtfile = m_wspec.path+DIR_DELIM+"world.mt";
|
||||
m_settings.updateConfigFile(worldmtfile.c_str());
|
||||
|
||||
// The trailing spaces are because there seems to be a
|
||||
// bug in the text-size calculation. if the trailing
|
||||
// spaces are removed from the message text, the
|
||||
// message gets wrapped and parts of it are cut off:
|
||||
wchar_t* text = wgettext("Configuration saved. ");
|
||||
GUIMessageMenu *menu =
|
||||
new GUIMessageMenu(Environment, Parent, -1, m_menumgr,
|
||||
text );
|
||||
delete[] text;
|
||||
menu->drop();
|
||||
|
||||
try
|
||||
{
|
||||
ModConfiguration modconf(m_wspec.path);
|
||||
if(!modconf.isConsistent())
|
||||
{
|
||||
wchar_t* text = wgettext("Warning: Configuration not consistent. ");
|
||||
GUIMessageMenu *menu =
|
||||
new GUIMessageMenu(Environment, Parent, -1, m_menumgr,
|
||||
text );
|
||||
delete[] text;
|
||||
menu->drop();
|
||||
}
|
||||
}
|
||||
catch(ModError &err)
|
||||
{
|
||||
errorstream<<err.what()<<std::endl;
|
||||
std::wstring text = narrow_to_wide(err.what()) + wgettext("\nCheck debug.txt for details.");
|
||||
GUIMessageMenu *menu =
|
||||
new GUIMessageMenu(Environment, Parent, -1, m_menumgr,
|
||||
text );
|
||||
menu->drop();
|
||||
}
|
||||
|
||||
quitMenu();
|
||||
return true;
|
||||
}
|
||||
case GUI_ID_ENABLEALL: {
|
||||
if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
|
||||
{
|
||||
enableAllMods(m_addonmods,true);
|
||||
}
|
||||
else if(selected_node != NULL && selected_node->getText() != NULL)
|
||||
{
|
||||
std::string modname = wide_to_narrow(selected_node->getText());
|
||||
std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
|
||||
if(mod_it != m_addonmods.end())
|
||||
enableAllMods(mod_it->second.modpack_content,true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case GUI_ID_DISABLEALL: {
|
||||
if(selected_node != NULL && selected_node->getParent() == m_treeview->getRoot())
|
||||
{
|
||||
enableAllMods(m_addonmods,false);
|
||||
}
|
||||
if(selected_node != NULL && selected_node->getText() != NULL)
|
||||
{
|
||||
std::string modname = wide_to_narrow(selected_node->getText());
|
||||
std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
|
||||
if(mod_it != m_addonmods.end())
|
||||
enableAllMods(mod_it->second.modpack_content,false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(event.GUIEvent.EventType==gui::EGET_CHECKBOX_CHANGED &&
|
||||
event.GUIEvent.Caller->getID() == GUI_ID_ENABLED_CHECKBOX)
|
||||
{
|
||||
if(selected_node != NULL && !selected_node->hasChilds() &&
|
||||
selected_node->getText() != NULL)
|
||||
{
|
||||
std::string modname = wide_to_narrow(selected_node->getText());
|
||||
setEnabled(modname, m_enabled_checkbox->isChecked());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(event.GUIEvent.EventType==gui::EGET_TREEVIEW_NODE_SELECT &&
|
||||
event.GUIEvent.Caller->getID() == GUI_ID_MOD_TREEVIEW)
|
||||
{
|
||||
selecting_dep = -1;
|
||||
selecting_rdep = -1;
|
||||
adjustSidebar();
|
||||
return true;
|
||||
}
|
||||
if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
|
||||
event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
|
||||
{
|
||||
selecting_dep = m_dependencies_listbox->getSelected();
|
||||
selecting_rdep = -1;
|
||||
return true;
|
||||
}
|
||||
if(event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED &&
|
||||
event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
|
||||
{
|
||||
selecting_dep = -1;
|
||||
selecting_rdep = m_rdependencies_listbox->getSelected();
|
||||
return true;
|
||||
}
|
||||
|
||||
//double click in a dependency listbox: find corresponding
|
||||
//treeviewnode and select it:
|
||||
if(event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN)
|
||||
{
|
||||
gui::IGUIListBox* box = NULL;
|
||||
if(event.GUIEvent.Caller->getID() == GUI_ID_DEPENDS_LISTBOX)
|
||||
{
|
||||
box = m_dependencies_listbox;
|
||||
if(box->getSelected() != selecting_dep)
|
||||
return true;
|
||||
}
|
||||
if(event.GUIEvent.Caller->getID() == GUI_ID_RDEPENDS_LISTBOX)
|
||||
{
|
||||
box = m_rdependencies_listbox;
|
||||
if(box->getSelected() != selecting_rdep)
|
||||
return true;
|
||||
}
|
||||
if(box != NULL && box->getSelected() != -1 &&
|
||||
box->getListItem(box->getSelected()) != NULL)
|
||||
{
|
||||
std::string modname =
|
||||
wide_to_narrow(box->getListItem(box->getSelected()));
|
||||
std::map<std::string, gui::IGUITreeViewNode*>::iterator it =
|
||||
m_nodes.find(modname);
|
||||
if(it != m_nodes.end())
|
||||
{
|
||||
// select node and make sure node is visible by
|
||||
// expanding all parents
|
||||
gui::IGUITreeViewNode* node = (*it).second;
|
||||
node->setSelected(true);
|
||||
while(!node->isVisible() &&
|
||||
node->getParent() != m_treeview->getRoot())
|
||||
{
|
||||
node = node->getParent();
|
||||
node->setExpanded(true);
|
||||
}
|
||||
adjustSidebar();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parent ? Parent->OnEvent(event) : false;
|
||||
}
|
||||
|
||||
void GUIConfigureWorld::buildTreeView(std::map<std::string, ModSpec> mods,
|
||||
gui::IGUITreeViewNode* node)
|
||||
{
|
||||
for(std::map<std::string,ModSpec>::iterator it = mods.begin();
|
||||
it != mods.end(); ++it)
|
||||
{
|
||||
std::string modname = (*it).first;
|
||||
ModSpec mod = (*it).second;
|
||||
gui::IGUITreeViewNode* new_node =
|
||||
node->addChildBack(narrow_to_wide(modname).c_str());
|
||||
m_nodes.insert(std::make_pair(modname, new_node));
|
||||
if(mod.is_modpack)
|
||||
buildTreeView(mod.modpack_content, new_node);
|
||||
else
|
||||
{
|
||||
// set icon for node: x for disabled mods, checkmark for enabled mods
|
||||
bool mod_enabled = false;
|
||||
if(m_settings.exists("load_mod_"+modname))
|
||||
mod_enabled = m_settings.getBool("load_mod_"+modname);
|
||||
if(mod_enabled)
|
||||
new_node->setIcon(CHECKMARK_STR);
|
||||
else
|
||||
new_node->setIcon(CROSS_STR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GUIConfigureWorld::adjustSidebar()
|
||||
{
|
||||
gui::IGUITreeViewNode* node = m_treeview->getSelected();
|
||||
std::wstring modname_w;
|
||||
if(node->getText() != NULL)
|
||||
modname_w = node->getText();
|
||||
else
|
||||
modname_w = L"N/A";
|
||||
std::string modname = wide_to_narrow(modname_w);
|
||||
|
||||
ModSpec mspec;
|
||||
std::map<std::string, ModSpec>::iterator it = m_addonmods.find(modname);
|
||||
if(it != m_addonmods.end())
|
||||
mspec = it->second;
|
||||
|
||||
m_dependencies_listbox->clear();
|
||||
m_rdependencies_listbox->clear();
|
||||
|
||||
// if no mods installed, there is nothing to enable/disable, so we
|
||||
// don't show buttons or checkbox on the sidebar
|
||||
if(node->getParent() == m_treeview->getRoot() && !node->hasChilds())
|
||||
{
|
||||
m_disableall->setVisible(false);
|
||||
m_enableall->setVisible(false);
|
||||
m_enabled_checkbox->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// a modpack is not enabled/disabled by itself, only its cotnents
|
||||
// are. so we show show enable/disable all buttons, but hide the
|
||||
// checkbox
|
||||
if(node->getParent() == m_treeview->getRoot() ||
|
||||
mspec.is_modpack)
|
||||
{
|
||||
m_enabled_checkbox->setVisible(false);
|
||||
m_disableall->setVisible(true);
|
||||
m_enableall->setVisible(true);
|
||||
m_modname_text->setText((L"Modpack: "+modname_w).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// for a normal mod, we hide the enable/disable all buttons, but show the checkbox.
|
||||
m_disableall->setVisible(false);
|
||||
m_enableall->setVisible(false);
|
||||
m_enabled_checkbox->setVisible(true);
|
||||
m_modname_text->setText((L"Mod: "+modname_w).c_str());
|
||||
|
||||
// the mod is enabled unless it is disabled in the world.mt settings.
|
||||
bool mod_enabled = true;
|
||||
if(m_settings.exists("load_mod_"+modname))
|
||||
mod_enabled = m_settings.getBool("load_mod_"+modname);
|
||||
m_enabled_checkbox->setChecked(mod_enabled);
|
||||
|
||||
for(std::set<std::string>::iterator it=mspec.depends.begin();
|
||||
it != mspec.depends.end(); ++it)
|
||||
{
|
||||
// check if it is an add-on mod or a game/world mod. We only
|
||||
// want to show add-ons
|
||||
std::string dependency = (*it);
|
||||
if(m_gamemods.count(dependency) > 0)
|
||||
dependency += " (" + m_gspec.id + ")";
|
||||
else if(m_worldmods.count(dependency) > 0)
|
||||
dependency += " (" + m_wspec.name + ")";
|
||||
else if(m_addonmods.count(dependency) == 0)
|
||||
dependency += " (missing)";
|
||||
m_dependencies_listbox->addItem(narrow_to_wide(dependency).c_str());
|
||||
}
|
||||
|
||||
// reverse dependencies of this mod:
|
||||
std::pair< std::multimap<std::string, std::string>::iterator,
|
||||
std::multimap<std::string, std::string>::iterator > rdep =
|
||||
m_reverse_depends.equal_range(modname);
|
||||
for(std::multimap<std::string,std::string>::iterator it = rdep.first;
|
||||
it != rdep.second; ++it)
|
||||
{
|
||||
// check if it is an add-on mod or a game/world mod. We only
|
||||
// want to show add-ons
|
||||
std::string rdependency = (*it).second;
|
||||
if(m_addonmods.count(rdependency) > 0)
|
||||
m_rdependencies_listbox->addItem(narrow_to_wide(rdependency).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void GUIConfigureWorld::enableAllMods(std::map<std::string, ModSpec> mods,bool enable)
|
||||
{
|
||||
for(std::map<std::string, ModSpec>::iterator it = mods.begin();
|
||||
it != mods.end(); ++it)
|
||||
{
|
||||
ModSpec mod = (*it).second;
|
||||
if(mod.is_modpack)
|
||||
// a modpack, recursively enable all mods in it
|
||||
enableAllMods(mod.modpack_content,enable);
|
||||
else // not a modpack
|
||||
setEnabled(mod.name, enable);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void GUIConfigureWorld::enableMod(std::string modname)
|
||||
{
|
||||
std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
|
||||
if(mod_it == m_addonmods.end()){
|
||||
errorstream << "enableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
|
||||
return;
|
||||
}
|
||||
ModSpec mspec = mod_it->second;
|
||||
m_settings.setBool("load_mod_"+modname,true);
|
||||
std::map<std::string,gui::IGUITreeViewNode*>::iterator it =
|
||||
m_nodes.find(modname);
|
||||
if(it != m_nodes.end())
|
||||
(*it).second->setIcon(CHECKMARK_STR);
|
||||
//also enable all dependencies
|
||||
for(std::set<std::string>::iterator it=mspec.depends.begin();
|
||||
it != mspec.depends.end(); ++it)
|
||||
{
|
||||
std::string dependency = *it;
|
||||
// only enable it if it is an add-on mod
|
||||
if(m_addonmods.count(dependency) > 0)
|
||||
enableMod(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
void GUIConfigureWorld::disableMod(std::string modname)
|
||||
{
|
||||
std::map<std::string, ModSpec>::iterator mod_it = m_addonmods.find(modname);
|
||||
if(mod_it == m_addonmods.end()){
|
||||
errorstream << "disableMod() called with invalid mod name \"" << modname << "\"" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_settings.setBool("load_mod_"+modname,false);
|
||||
std::map<std::string,gui::IGUITreeViewNode*>::iterator it =
|
||||
m_nodes.find(modname);
|
||||
if(it != m_nodes.end())
|
||||
(*it).second->setIcon(CROSS_STR);
|
||||
//also disable all mods that depend on this one
|
||||
std::pair<std::multimap<std::string, std::string>::iterator,
|
||||
std::multimap<std::string, std::string>::iterator > rdep =
|
||||
m_reverse_depends.equal_range(modname);
|
||||
for(std::multimap<std::string,std::string>::iterator it = rdep.first;
|
||||
it != rdep.second; ++it)
|
||||
{
|
||||
std::string rdependency = (*it).second;
|
||||
// only disable it if it is an add-on mod
|
||||
if(m_addonmods.count(rdependency) > 0)
|
||||
disableMod(rdependency);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 GUICONFIGUREWORLD_HEADER
|
||||
#define GUICONFIGUREWORLD_HEADER
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "modalMenu.h"
|
||||
#include "mods.h"
|
||||
#include "subgame.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
namespace irr{
|
||||
namespace gui{
|
||||
class IGUITreeViewNode;
|
||||
}
|
||||
}
|
||||
|
||||
class GUIConfigureWorld : public GUIModalMenu
|
||||
{
|
||||
public:
|
||||
GUIConfigureWorld(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr, WorldSpec wspec);
|
||||
|
||||
void regenerateGui(v2u32 screensize);
|
||||
|
||||
void drawMenu();
|
||||
|
||||
bool OnEvent(const SEvent& event);
|
||||
|
||||
private:
|
||||
WorldSpec m_wspec;
|
||||
SubgameSpec m_gspec;
|
||||
|
||||
// tree of installed add-on mods. key is the mod name, modpacks
|
||||
// are not expanded.
|
||||
std::map<std::string, ModSpec> m_addontree;
|
||||
|
||||
// like m_addontree, but modpacks are expanded.
|
||||
std::map<std::string, ModSpec> m_addonmods;
|
||||
|
||||
// list of game mods (flattened)
|
||||
std::map<std::string, ModSpec> m_gamemods;
|
||||
|
||||
// list of world mods (flattened)
|
||||
std::map<std::string, ModSpec> m_worldmods;
|
||||
|
||||
// for each mod, the set of mods depending on it
|
||||
std::multimap<std::string, std::string> m_reverse_depends;
|
||||
|
||||
// the settings in the world.mt file
|
||||
Settings m_settings;
|
||||
|
||||
// maps modnames to nodes in m_treeview
|
||||
std::map<std::string,gui::IGUITreeViewNode*> m_nodes;
|
||||
|
||||
gui::IGUIStaticText* m_modname_text;
|
||||
gui::IGUITreeView* m_treeview;
|
||||
gui::IGUIButton* m_enableall;
|
||||
gui::IGUIButton* m_disableall;
|
||||
gui::IGUICheckBox* m_enabled_checkbox;
|
||||
gui::IGUIListBox* m_dependencies_listbox;
|
||||
gui::IGUIListBox* m_rdependencies_listbox;
|
||||
void buildTreeView(std::map<std::string,ModSpec> mods,
|
||||
gui::IGUITreeViewNode* node);
|
||||
void adjustSidebar();
|
||||
void enableAllMods(std::map<std::string,ModSpec> mods, bool enable);
|
||||
void setEnabled(std::string modname, bool enable)
|
||||
{
|
||||
if(enable)
|
||||
enableMod(modname);
|
||||
else
|
||||
disableMod(modname);
|
||||
};
|
||||
|
||||
void enableMod(std::string modname);
|
||||
void disableMod(std::string modname);
|
||||
|
||||
// hack to work around wonky handling of double-click in
|
||||
// irrlicht. store selected index of listbox items here so event
|
||||
// handling can check whether it was a real double click on the
|
||||
// same item. (irrlicht also reports a double click if you rapidly
|
||||
// select two different items.)
|
||||
int selecting_dep;
|
||||
int selecting_rdep;
|
||||
|
||||
IMenuManager* m_menumgr;
|
||||
};
|
||||
#endif
|
|
@ -1,204 +0,0 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 "guiConfirmMenu.h"
|
||||
#include "debug.h"
|
||||
#include "serialization.h"
|
||||
#include <string>
|
||||
#include <IGUICheckBox.h>
|
||||
#include <IGUIEditBox.h>
|
||||
#include <IGUIButton.h>
|
||||
#include <IGUIStaticText.h>
|
||||
#include <IGUIFont.h>
|
||||
|
||||
#include "gettext.h"
|
||||
|
||||
enum
|
||||
{
|
||||
GUI_ID_YES = 101,
|
||||
GUI_ID_NO,
|
||||
};
|
||||
|
||||
GUIConfirmMenu::GUIConfirmMenu(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
ConfirmDest *dest,
|
||||
std::wstring message_text
|
||||
):
|
||||
GUIModalMenu(env, parent, id, menumgr),
|
||||
m_dest(dest),
|
||||
m_message_text(message_text)
|
||||
{
|
||||
}
|
||||
|
||||
GUIConfirmMenu::~GUIConfirmMenu()
|
||||
{
|
||||
removeChildren();
|
||||
if(m_dest)
|
||||
delete m_dest;
|
||||
}
|
||||
|
||||
void GUIConfirmMenu::removeChildren()
|
||||
{
|
||||
const core::list<gui::IGUIElement*> &children = getChildren();
|
||||
core::list<gui::IGUIElement*> children_copy;
|
||||
for(core::list<gui::IGUIElement*>::ConstIterator
|
||||
i = children.begin(); i != children.end(); i++)
|
||||
{
|
||||
children_copy.push_back(*i);
|
||||
}
|
||||
for(core::list<gui::IGUIElement*>::Iterator
|
||||
i = children_copy.begin();
|
||||
i != children_copy.end(); i++)
|
||||
{
|
||||
(*i)->remove();
|
||||
}
|
||||
}
|
||||
|
||||
void GUIConfirmMenu::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
/*
|
||||
Remove stuff
|
||||
*/
|
||||
removeChildren();
|
||||
|
||||
/*
|
||||
Calculate new sizes and positions
|
||||
*/
|
||||
core::rect<s32> rect(
|
||||
screensize.X/2 - 580/2,
|
||||
screensize.Y/2 - 300/2,
|
||||
screensize.X/2 + 580/2,
|
||||
screensize.Y/2 + 300/2
|
||||
);
|
||||
|
||||
DesiredRect = rect;
|
||||
recalculateAbsolutePosition(false);
|
||||
|
||||
v2s32 size = rect.getSize();
|
||||
|
||||
gui::IGUISkin *skin = Environment->getSkin();
|
||||
gui::IGUIFont *font = skin->getFont();
|
||||
s32 msg_h = font->getDimension(m_message_text.c_str()).Height;
|
||||
s32 msg_w = font->getDimension(m_message_text.c_str()).Width;
|
||||
if(msg_h > 200)
|
||||
msg_h = 200;
|
||||
if(msg_w > 540)
|
||||
msg_w = 540;
|
||||
|
||||
/*
|
||||
Add stuff
|
||||
*/
|
||||
{
|
||||
core::rect<s32> rect(0, 0, msg_w, msg_h);
|
||||
rect += v2s32(size.X/2-msg_w/2, size.Y/2-30/2 - msg_h/2);
|
||||
Environment->addStaticText(m_message_text.c_str(),
|
||||
rect, false, true, this, -1);
|
||||
}
|
||||
changeCtype("");
|
||||
int bw = 100;
|
||||
{
|
||||
core::rect<s32> rect(0, 0, bw, 30);
|
||||
rect = rect + v2s32(size.X/2-bw/2-(bw/2+5), size.Y/2-30/2+5 + msg_h/2);
|
||||
wchar_t* text = wgettext("Yes");
|
||||
Environment->addButton(rect, this, GUI_ID_YES,
|
||||
text);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, bw, 30);
|
||||
rect = rect + v2s32(size.X/2-bw/2+(bw/2+5), size.Y/2-30/2+5 + msg_h/2);
|
||||
wchar_t* text = wgettext("No");
|
||||
Environment->addButton(rect, this, GUI_ID_NO,
|
||||
text);
|
||||
delete[] text;
|
||||
}
|
||||
changeCtype("C");
|
||||
}
|
||||
|
||||
void GUIConfirmMenu::drawMenu()
|
||||
{
|
||||
gui::IGUISkin* skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
return;
|
||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||
|
||||
video::SColor bgcolor(140,0,0,0);
|
||||
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
|
||||
|
||||
gui::IGUIElement::draw();
|
||||
}
|
||||
|
||||
void GUIConfirmMenu::acceptInput(bool answer)
|
||||
{
|
||||
if(m_dest)
|
||||
m_dest->answer(answer);
|
||||
}
|
||||
|
||||
bool GUIConfirmMenu::OnEvent(const SEvent& event)
|
||||
{
|
||||
if(event.EventType==EET_KEY_INPUT_EVENT)
|
||||
{
|
||||
if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
|
||||
{
|
||||
acceptInput(false);
|
||||
quitMenu();
|
||||
return true;
|
||||
}
|
||||
if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
|
||||
{
|
||||
acceptInput(true);
|
||||
quitMenu();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(event.EventType==EET_GUI_EVENT)
|
||||
{
|
||||
if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
|
||||
&& isVisible())
|
||||
{
|
||||
if(!canTakeFocus(event.GUIEvent.Element))
|
||||
{
|
||||
dstream<<"GUIConfirmMenu: Not allowing focus change."
|
||||
<<std::endl;
|
||||
// Returning true disables focus change
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
|
||||
{
|
||||
switch(event.GUIEvent.Caller->getID())
|
||||
{
|
||||
case GUI_ID_YES:
|
||||
acceptInput(true);
|
||||
quitMenu();
|
||||
// quitMenu deallocates menu
|
||||
return true;
|
||||
case GUI_ID_NO:
|
||||
acceptInput(false);
|
||||
quitMenu();
|
||||
// quitMenu deallocates menu
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Parent ? Parent->OnEvent(event) : false;
|
||||
}
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 "guiCreateWorld.h"
|
||||
#include "debug.h"
|
||||
#include "serialization.h"
|
||||
#include <string>
|
||||
#include <IGUICheckBox.h>
|
||||
#include <IGUIEditBox.h>
|
||||
#include <IGUIButton.h>
|
||||
#include <IGUIStaticText.h>
|
||||
#include <IGUIFont.h>
|
||||
#include <IGUIListBox.h>
|
||||
#include "gettext.h"
|
||||
#include "util/string.h"
|
||||
|
||||
enum
|
||||
{
|
||||
GUI_ID_NAME_INPUT = 101,
|
||||
GUI_ID_GAME_LISTBOX,
|
||||
GUI_ID_CREATE,
|
||||
GUI_ID_CANCEL
|
||||
};
|
||||
|
||||
GUICreateWorld::GUICreateWorld(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
CreateWorldDest *dest,
|
||||
const std::vector<SubgameSpec> &games,
|
||||
const std::string &initial_game
|
||||
):
|
||||
GUIModalMenu(env, parent, id, menumgr),
|
||||
m_dest(dest),
|
||||
m_games(games),
|
||||
m_initial_game_i(0)
|
||||
{
|
||||
assert(games.size() > 0);
|
||||
|
||||
for(size_t i=0; i<games.size(); i++){
|
||||
if(games[i].id == initial_game){
|
||||
m_initial_game_i = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUICreateWorld::~GUICreateWorld()
|
||||
{
|
||||
removeChildren();
|
||||
if(m_dest)
|
||||
delete m_dest;
|
||||
}
|
||||
|
||||
void GUICreateWorld::removeChildren()
|
||||
{
|
||||
const core::list<gui::IGUIElement*> &children = getChildren();
|
||||
core::list<gui::IGUIElement*> children_copy;
|
||||
for(core::list<gui::IGUIElement*>::ConstIterator
|
||||
i = children.begin(); i != children.end(); i++)
|
||||
{
|
||||
children_copy.push_back(*i);
|
||||
}
|
||||
for(core::list<gui::IGUIElement*>::Iterator
|
||||
i = children_copy.begin();
|
||||
i != children_copy.end(); i++)
|
||||
{
|
||||
(*i)->remove();
|
||||
}
|
||||
}
|
||||
|
||||
void GUICreateWorld::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
std::wstring name = L"";
|
||||
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT);
|
||||
if(e != NULL)
|
||||
name = e->getText();
|
||||
}
|
||||
|
||||
/*
|
||||
Remove stuff
|
||||
*/
|
||||
removeChildren();
|
||||
|
||||
/*
|
||||
Calculate new sizes and positions
|
||||
*/
|
||||
core::rect<s32> rect(
|
||||
screensize.X/2 - 580/2,
|
||||
screensize.Y/2 - 300/2,
|
||||
screensize.X/2 + 580/2,
|
||||
screensize.Y/2 + 300/2
|
||||
);
|
||||
|
||||
DesiredRect = rect;
|
||||
recalculateAbsolutePosition(false);
|
||||
|
||||
v2s32 topleft = v2s32(10+80, 10+70);
|
||||
|
||||
/*
|
||||
Add stuff
|
||||
*/
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 100, 20);
|
||||
rect += v2s32(0, 5) + topleft;
|
||||
wchar_t* text = wgettext("World name");
|
||||
Environment->addStaticText(text, rect, false, true, this, -1);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 300, 30);
|
||||
rect = rect + v2s32(100, 0) + topleft;
|
||||
gui::IGUIElement *e =
|
||||
Environment->addEditBox(name.c_str(), rect, true, this, GUI_ID_NAME_INPUT);
|
||||
Environment->setFocus(e);
|
||||
|
||||
irr::SEvent evt;
|
||||
evt.EventType = EET_KEY_INPUT_EVENT;
|
||||
evt.KeyInput.Key = KEY_END;
|
||||
evt.KeyInput.PressedDown = true;
|
||||
evt.KeyInput.Char = 0;
|
||||
evt.KeyInput.Control = 0;
|
||||
evt.KeyInput.Shift = 0;
|
||||
e->OnEvent(evt);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 100, 20);
|
||||
rect += v2s32(0, 40+5) + topleft;
|
||||
wchar_t* text = wgettext("Game");
|
||||
Environment->addStaticText(text, rect, false, true, this, -1);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 300, 80);
|
||||
rect += v2s32(100, 40) + topleft;
|
||||
gui::IGUIListBox *e = Environment->addListBox(rect, this,
|
||||
GUI_ID_GAME_LISTBOX);
|
||||
e->setDrawBackground(true);
|
||||
for(u32 i=0; i<m_games.size(); i++){
|
||||
std::wostringstream os(std::ios::binary);
|
||||
os<<narrow_to_wide(m_games[i].name).c_str();
|
||||
os<<L" [";
|
||||
os<<narrow_to_wide(m_games[i].id).c_str();
|
||||
os<<L"]";
|
||||
e->addItem(os.str().c_str());
|
||||
}
|
||||
e->setSelected(m_initial_game_i);
|
||||
}
|
||||
changeCtype("");
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 120, 30);
|
||||
rect = rect + v2s32(170, 140) + topleft;
|
||||
wchar_t* text = wgettext("Create");
|
||||
Environment->addButton(rect, this, GUI_ID_CREATE,
|
||||
text);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 120, 30);
|
||||
rect = rect + v2s32(300, 140) + topleft;
|
||||
wchar_t* text = wgettext("Cancel");
|
||||
Environment->addButton(rect, this, GUI_ID_CANCEL,
|
||||
text);
|
||||
delete [] text;
|
||||
}
|
||||
changeCtype("C");
|
||||
}
|
||||
|
||||
void GUICreateWorld::drawMenu()
|
||||
{
|
||||
gui::IGUISkin* skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
return;
|
||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||
|
||||
video::SColor bgcolor(140,0,0,0);
|
||||
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
|
||||
|
||||
gui::IGUIElement::draw();
|
||||
}
|
||||
|
||||
void GUICreateWorld::acceptInput()
|
||||
{
|
||||
if(m_dest)
|
||||
{
|
||||
int selected = -1;
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_GAME_LISTBOX);
|
||||
if(e != NULL && e->getType() == gui::EGUIET_LIST_BOX)
|
||||
selected = ((gui::IGUIListBox*)e)->getSelected();
|
||||
}
|
||||
std::wstring name;
|
||||
{
|
||||
gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT);
|
||||
if(e != NULL)
|
||||
name = e->getText();
|
||||
}
|
||||
if(selected != -1 && name != L"")
|
||||
m_dest->accepted(name, m_games[selected].id);
|
||||
delete m_dest;
|
||||
m_dest = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool GUICreateWorld::OnEvent(const SEvent& event)
|
||||
{
|
||||
if(event.EventType==EET_KEY_INPUT_EVENT)
|
||||
{
|
||||
if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
|
||||
{
|
||||
quitMenu();
|
||||
return true;
|
||||
}
|
||||
if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
|
||||
{
|
||||
acceptInput();
|
||||
quitMenu();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(event.EventType==EET_GUI_EVENT)
|
||||
{
|
||||
if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
|
||||
&& isVisible())
|
||||
{
|
||||
if(!canTakeFocus(event.GUIEvent.Element))
|
||||
{
|
||||
dstream<<"GUICreateWorld: Not allowing focus change."
|
||||
<<std::endl;
|
||||
// Returning true disables focus change
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool accept_input = false;
|
||||
if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED){
|
||||
switch(event.GUIEvent.Caller->getID()){
|
||||
case GUI_ID_CANCEL:
|
||||
quitMenu();
|
||||
return true;
|
||||
break;
|
||||
case GUI_ID_CREATE:
|
||||
accept_input = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER){
|
||||
switch(event.GUIEvent.Caller->getID()){
|
||||
case GUI_ID_NAME_INPUT:
|
||||
accept_input = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(accept_input){
|
||||
acceptInput();
|
||||
quitMenu();
|
||||
// quitMenu deallocates menu
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Parent ? Parent->OnEvent(event) : false;
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 GUICREATEWORLD_HEADER
|
||||
#define GUICREATEWORLD_HEADER
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "modalMenu.h"
|
||||
#include <string>
|
||||
#include "subgame.h"
|
||||
|
||||
struct CreateWorldDest
|
||||
{
|
||||
virtual void accepted(std::wstring name, std::string gameid) = 0;
|
||||
virtual ~CreateWorldDest() {};
|
||||
};
|
||||
|
||||
class GUICreateWorld : public GUIModalMenu
|
||||
{
|
||||
public:
|
||||
GUICreateWorld(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
CreateWorldDest *dest,
|
||||
const std::vector<SubgameSpec> &games,
|
||||
const std::string &initial_game);
|
||||
~GUICreateWorld();
|
||||
|
||||
void removeChildren();
|
||||
/*
|
||||
Remove and re-add (or reposition) stuff
|
||||
*/
|
||||
void regenerateGui(v2u32 screensize);
|
||||
|
||||
void drawMenu();
|
||||
|
||||
void acceptInput();
|
||||
|
||||
bool OnEvent(const SEvent& event);
|
||||
|
||||
private:
|
||||
CreateWorldDest *m_dest;
|
||||
std::vector<SubgameSpec> m_games;
|
||||
int m_initial_game_i;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
570
src/guiEngine.cpp
Normal file
570
src/guiEngine.cpp
Normal file
|
@ -0,0 +1,570 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 sapier
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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.
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
}
|
||||
|
||||
#include "irrlicht.h"
|
||||
|
||||
#include "porting.h"
|
||||
#include "filesys.h"
|
||||
#include "main.h"
|
||||
#include "settings.h"
|
||||
#include "guiMainMenu.h"
|
||||
|
||||
#include "guiEngine.h"
|
||||
|
||||
#if USE_CURL
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
int menuscript_ErrorHandler(lua_State *L) {
|
||||
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
|
||||
if (!lua_istable(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
lua_getfield(L, -1, "traceback");
|
||||
if (!lua_isfunction(L, -1)) {
|
||||
lua_pop(L, 2);
|
||||
return 1;
|
||||
}
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushinteger(L, 2);
|
||||
lua_call(L, 2, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
TextDestGuiEngine::TextDestGuiEngine(GUIEngine* engine)
|
||||
{
|
||||
m_engine = engine;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void TextDestGuiEngine::gotText(std::map<std::string, std::string> fields)
|
||||
{
|
||||
m_engine->handleButtons(fields);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void TextDestGuiEngine::gotText(std::wstring text)
|
||||
{
|
||||
m_engine->handleEvent(wide_to_narrow(text));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
|
||||
gui::IGUIElement* parent,
|
||||
IMenuManager *menumgr,
|
||||
scene::ISceneManager* smgr,
|
||||
MainMenuData* data) :
|
||||
m_device(dev),
|
||||
m_parent(parent),
|
||||
m_menumanager(menumgr),
|
||||
m_smgr(smgr),
|
||||
m_data(data),
|
||||
m_formspecgui(0),
|
||||
m_buttonhandler(0),
|
||||
m_menu(0),
|
||||
m_startgame(false),
|
||||
m_engineluastack(0),
|
||||
m_luaerrorhandler(-1),
|
||||
m_scriptdir(""),
|
||||
m_irr_toplefttext(0),
|
||||
m_clouds_enabled(true),
|
||||
m_cloud()
|
||||
{
|
||||
//initialize texture pointers
|
||||
for (unsigned int i = 0; i < TEX_LAYER_MAX; i++) {
|
||||
m_textures[i] = 0;
|
||||
}
|
||||
// is deleted by guiformspec!
|
||||
m_buttonhandler = new TextDestGuiEngine(this);
|
||||
|
||||
//create luastack
|
||||
m_engineluastack = luaL_newstate();
|
||||
|
||||
//load basic lua modules
|
||||
luaL_openlibs(m_engineluastack);
|
||||
|
||||
//init
|
||||
guiLuaApi::initialize(m_engineluastack,this);
|
||||
|
||||
//push errorstring
|
||||
if (m_data->errormessage != "")
|
||||
{
|
||||
lua_getglobal(m_engineluastack, "gamedata");
|
||||
int gamedata_idx = lua_gettop(m_engineluastack);
|
||||
lua_pushstring(m_engineluastack, "errormessage");
|
||||
lua_pushstring(m_engineluastack,m_data->errormessage.c_str());
|
||||
lua_settable(m_engineluastack, gamedata_idx);
|
||||
m_data->errormessage = "";
|
||||
}
|
||||
|
||||
//create topleft header
|
||||
core::rect<s32> rect(0, 0, 500, 40);
|
||||
rect += v2s32(4, 0);
|
||||
std::string t = "Minetest " VERSION_STRING;
|
||||
|
||||
m_irr_toplefttext =
|
||||
m_device->getGUIEnvironment()->addStaticText(narrow_to_wide(t).c_str(),
|
||||
rect,false,true,0,-1);
|
||||
|
||||
//create formspecsource
|
||||
m_formspecgui = new FormspecFormSource("",&m_formspecgui);
|
||||
|
||||
/* Create menu */
|
||||
m_menu =
|
||||
new GUIFormSpecMenu( m_device,
|
||||
m_parent,
|
||||
-1,
|
||||
m_menumanager,
|
||||
0 /* &client */,
|
||||
0 /* gamedef */);
|
||||
|
||||
m_menu->allowClose(false);
|
||||
m_menu->lockSize(true,v2u32(800,600));
|
||||
m_menu->setFormSource(m_formspecgui);
|
||||
m_menu->setTextDest(m_buttonhandler);
|
||||
m_menu->useGettext(true);
|
||||
|
||||
std::string builtin_helpers
|
||||
= porting::path_share + DIR_DELIM + "builtin"
|
||||
+ DIR_DELIM + "mainmenu_helper.lua";
|
||||
|
||||
if (!runScript(builtin_helpers)) {
|
||||
errorstream
|
||||
<< "GUIEngine::GUIEngine unable to load builtin helper script"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string menuscript = "";
|
||||
if (g_settings->exists("main_menu_script"))
|
||||
menuscript = g_settings->get("main_menu_script");
|
||||
std::string builtin_menuscript =
|
||||
porting::path_share + DIR_DELIM + "builtin"
|
||||
+ DIR_DELIM + "mainmenu.lua";
|
||||
|
||||
lua_pushcfunction(m_engineluastack, menuscript_ErrorHandler);
|
||||
m_luaerrorhandler = lua_gettop(m_engineluastack);
|
||||
|
||||
m_scriptdir = menuscript.substr(0,menuscript.find_last_of(DIR_DELIM)-1);
|
||||
if((menuscript == "") || (!runScript(menuscript))) {
|
||||
infostream
|
||||
<< "GUIEngine::GUIEngine execution of custom menu failed!"
|
||||
<< std::endl
|
||||
<< "\tfalling back to builtin menu"
|
||||
<< std::endl;
|
||||
m_scriptdir = fs::RemoveRelativePathComponents(porting::path_share + DIR_DELIM + "builtin"+ DIR_DELIM);
|
||||
if(!runScript(builtin_menuscript)) {
|
||||
errorstream
|
||||
<< "GUIEngine::GUIEngine unable to load builtin menu"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
|
||||
m_menumanager->deletingMenu(m_menu);
|
||||
m_menu->drop();
|
||||
m_menu = 0;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
bool GUIEngine::runScript(std::string script) {
|
||||
|
||||
int ret = luaL_loadfile(m_engineluastack, script.c_str()) ||
|
||||
lua_pcall(m_engineluastack, 0, 0, m_luaerrorhandler);
|
||||
if(ret){
|
||||
errorstream<<"========== ERROR FROM LUA WHILE CREATING MAIN MENU ==========="<<std::endl;
|
||||
errorstream<<"Failed to load and run script from "<<std::endl;
|
||||
errorstream<<script<<":"<<std::endl;
|
||||
errorstream<<std::endl;
|
||||
errorstream<<lua_tostring(m_engineluastack, -1)<<std::endl;
|
||||
errorstream<<std::endl;
|
||||
errorstream<<"=================== END OF ERROR FROM LUA ===================="<<std::endl;
|
||||
lua_pop(m_engineluastack, 1); // Pop error message from stack
|
||||
lua_pop(m_engineluastack, 1); // Pop the error handler from stack
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::run()
|
||||
{
|
||||
|
||||
// Always create clouds because they may or may not be
|
||||
// needed based on the game selected
|
||||
video::IVideoDriver* driver = m_device->getVideoDriver();
|
||||
|
||||
cloudInit();
|
||||
|
||||
while(m_device->run() && (!m_startgame)) {
|
||||
driver->beginScene(true, true, video::SColor(255,140,186,250));
|
||||
|
||||
if (m_clouds_enabled)
|
||||
{
|
||||
cloudPreProcess();
|
||||
drawOverlay(driver);
|
||||
}
|
||||
else
|
||||
drawBackground(driver);
|
||||
|
||||
drawHeader(driver);
|
||||
drawFooter(driver);
|
||||
|
||||
m_device->getGUIEnvironment()->drawAll();
|
||||
|
||||
driver->endScene();
|
||||
|
||||
if (m_clouds_enabled)
|
||||
cloudPostProcess();
|
||||
else
|
||||
sleep_ms(25);
|
||||
}
|
||||
|
||||
m_menu->quitMenu();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::handleEvent(std::string text)
|
||||
{
|
||||
lua_getglobal(m_engineluastack, "engine");
|
||||
|
||||
lua_getfield(m_engineluastack, -1, "event_handler");
|
||||
|
||||
if(lua_isnil(m_engineluastack, -1))
|
||||
return;
|
||||
|
||||
luaL_checktype(m_engineluastack, -1, LUA_TFUNCTION);
|
||||
|
||||
lua_pushstring(m_engineluastack, text.c_str());
|
||||
|
||||
if(lua_pcall(m_engineluastack, 1, 0, m_luaerrorhandler))
|
||||
scriptError("error: %s", lua_tostring(m_engineluastack, -1));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::handleButtons(std::map<std::string, std::string> fields)
|
||||
{
|
||||
lua_getglobal(m_engineluastack, "engine");
|
||||
|
||||
lua_getfield(m_engineluastack, -1, "button_handler");
|
||||
|
||||
if(lua_isnil(m_engineluastack, -1))
|
||||
return;
|
||||
|
||||
luaL_checktype(m_engineluastack, -1, LUA_TFUNCTION);
|
||||
|
||||
lua_newtable(m_engineluastack);
|
||||
for(std::map<std::string, std::string>::const_iterator
|
||||
i = fields.begin(); i != fields.end(); i++){
|
||||
const std::string &name = i->first;
|
||||
const std::string &value = i->second;
|
||||
lua_pushstring(m_engineluastack, name.c_str());
|
||||
lua_pushlstring(m_engineluastack, value.c_str(), value.size());
|
||||
lua_settable(m_engineluastack, -3);
|
||||
}
|
||||
|
||||
if(lua_pcall(m_engineluastack, 1, 0, m_luaerrorhandler))
|
||||
scriptError("error: %s", lua_tostring(m_engineluastack, -1));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
GUIEngine::~GUIEngine()
|
||||
{
|
||||
video::IVideoDriver* driver = m_device->getVideoDriver();
|
||||
assert(driver != 0);
|
||||
|
||||
lua_close(m_engineluastack);
|
||||
|
||||
m_irr_toplefttext->setText(L"");
|
||||
|
||||
//initialize texture pointers
|
||||
for (unsigned int i = 0; i < TEX_LAYER_MAX; i++) {
|
||||
if (m_textures[i] != 0)
|
||||
driver->removeTexture(m_textures[i]);
|
||||
}
|
||||
|
||||
m_cloud.clouds->drop();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::cloudInit()
|
||||
{
|
||||
m_cloud.clouds = new Clouds(m_smgr->getRootSceneNode(),
|
||||
m_smgr, -1, rand(), 100);
|
||||
m_cloud.clouds->update(v2f(0, 0), video::SColor(255,200,200,255));
|
||||
|
||||
m_cloud.camera = m_smgr->addCameraSceneNode(0,
|
||||
v3f(0,0,0), v3f(0, 60, 100));
|
||||
m_cloud.camera->setFarValue(10000);
|
||||
|
||||
m_cloud.lasttime = m_device->getTimer()->getTime();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::cloudPreProcess()
|
||||
{
|
||||
u32 time = m_device->getTimer()->getTime();
|
||||
|
||||
if(time > m_cloud.lasttime)
|
||||
m_cloud.dtime = (time - m_cloud.lasttime) / 1000.0;
|
||||
else
|
||||
m_cloud.dtime = 0;
|
||||
|
||||
m_cloud.lasttime = time;
|
||||
|
||||
m_cloud.clouds->step(m_cloud.dtime*3);
|
||||
m_cloud.clouds->render();
|
||||
m_smgr->drawAll();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::cloudPostProcess()
|
||||
{
|
||||
float fps_max = g_settings->getFloat("fps_max");
|
||||
// Time of frame without fps limit
|
||||
float busytime;
|
||||
u32 busytime_u32;
|
||||
// not using getRealTime is necessary for wine
|
||||
u32 time = m_device->getTimer()->getTime();
|
||||
if(time > m_cloud.lasttime)
|
||||
busytime_u32 = time - m_cloud.lasttime;
|
||||
else
|
||||
busytime_u32 = 0;
|
||||
busytime = busytime_u32 / 1000.0;
|
||||
|
||||
// FPS limiter
|
||||
u32 frametime_min = 1000./fps_max;
|
||||
|
||||
if(busytime_u32 < frametime_min) {
|
||||
u32 sleeptime = frametime_min - busytime_u32;
|
||||
m_device->sleep(sleeptime);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::drawBackground(video::IVideoDriver* driver)
|
||||
{
|
||||
v2u32 screensize = driver->getScreenSize();
|
||||
|
||||
video::ITexture* texture = m_textures[TEX_LAYER_BACKGROUND];
|
||||
|
||||
/* If no texture, draw background of solid color */
|
||||
if(!texture){
|
||||
video::SColor color(255,80,58,37);
|
||||
core::rect<s32> rect(0, 0, screensize.X, screensize.Y);
|
||||
driver->draw2DRectangle(color, rect, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Draw background texture */
|
||||
v2u32 sourcesize = texture->getSize();
|
||||
driver->draw2DImage(texture,
|
||||
core::rect<s32>(0, 0, screensize.X, screensize.Y),
|
||||
core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::drawOverlay(video::IVideoDriver* driver)
|
||||
{
|
||||
v2u32 screensize = driver->getScreenSize();
|
||||
|
||||
video::ITexture* texture = m_textures[TEX_LAYER_OVERLAY];
|
||||
|
||||
/* If no texture, draw background of solid color */
|
||||
if(!texture)
|
||||
return;
|
||||
|
||||
/* Draw background texture */
|
||||
v2u32 sourcesize = texture->getSize();
|
||||
driver->draw2DImage(texture,
|
||||
core::rect<s32>(0, 0, screensize.X, screensize.Y),
|
||||
core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::drawHeader(video::IVideoDriver* driver)
|
||||
{
|
||||
core::dimension2d<u32> screensize = driver->getScreenSize();
|
||||
|
||||
video::ITexture* texture = m_textures[TEX_LAYER_HEADER];
|
||||
|
||||
/* If no texture, draw nothing */
|
||||
if(!texture)
|
||||
return;
|
||||
|
||||
f32 mult = (((f32)screensize.Width / 2)) /
|
||||
((f32)texture->getOriginalSize().Width);
|
||||
|
||||
v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult,
|
||||
((f32)texture->getOriginalSize().Height) * mult);
|
||||
|
||||
// Don't draw the header is there isn't enough room
|
||||
s32 free_space = (((s32)screensize.Height)-320)/2;
|
||||
|
||||
if (free_space > splashsize.Y) {
|
||||
core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
|
||||
splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
|
||||
((free_space/2)-splashsize.Y/2)+10);
|
||||
|
||||
video::SColor bgcolor(255,50,50,50);
|
||||
|
||||
driver->draw2DImage(texture, splashrect,
|
||||
core::rect<s32>(core::position2d<s32>(0,0),
|
||||
core::dimension2di(texture->getSize())),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::drawFooter(video::IVideoDriver* driver)
|
||||
{
|
||||
core::dimension2d<u32> screensize = driver->getScreenSize();
|
||||
|
||||
video::ITexture* texture = m_textures[TEX_LAYER_FOOTER];
|
||||
|
||||
/* If no texture, draw nothing */
|
||||
if(!texture)
|
||||
return;
|
||||
|
||||
f32 mult = (((f32)screensize.Width)) /
|
||||
((f32)texture->getOriginalSize().Width);
|
||||
|
||||
v2s32 footersize(((f32)texture->getOriginalSize().Width) * mult,
|
||||
((f32)texture->getOriginalSize().Height) * mult);
|
||||
|
||||
// Don't draw the footer if there isn't enough room
|
||||
s32 free_space = (((s32)screensize.Height)-320)/2;
|
||||
|
||||
if (free_space > footersize.Y) {
|
||||
core::rect<s32> rect(0,0,footersize.X,footersize.Y);
|
||||
rect += v2s32(screensize.Width/2,screensize.Height-footersize.Y);
|
||||
rect -= v2s32(footersize.X/2, 0);
|
||||
|
||||
driver->draw2DImage(texture, rect,
|
||||
core::rect<s32>(core::position2d<s32>(0,0),
|
||||
core::dimension2di(texture->getSize())),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
bool GUIEngine::setTexture(texture_layer layer,std::string texturepath) {
|
||||
|
||||
video::IVideoDriver* driver = m_device->getVideoDriver();
|
||||
assert(driver != 0);
|
||||
|
||||
if (m_textures[layer] != 0)
|
||||
{
|
||||
driver->removeTexture(m_textures[layer]);
|
||||
m_textures[layer] = 0;
|
||||
}
|
||||
|
||||
if ((texturepath == "") || !fs::PathExists(texturepath))
|
||||
return false;
|
||||
|
||||
m_textures[layer] = driver->getTexture(texturepath.c_str());
|
||||
|
||||
if (m_textures[layer] == 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
#if USE_CURL
|
||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
FILE* targetfile = (FILE*) userp;
|
||||
fwrite(contents,size,nmemb,targetfile);
|
||||
return size * nmemb;
|
||||
}
|
||||
#endif
|
||||
bool GUIEngine::downloadFile(std::string url,std::string target) {
|
||||
#if USE_CURL
|
||||
//download file via curl
|
||||
CURL *curl;
|
||||
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (curl)
|
||||
{
|
||||
CURLcode res;
|
||||
bool retval = true;
|
||||
|
||||
FILE* targetfile = fopen(target.c_str(),"wb");
|
||||
|
||||
if (targetfile) {
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, targetfile);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK) {
|
||||
errorstream << "File at url \"" << url
|
||||
<<"\" not found (internet connection?)" <<std::endl;
|
||||
retval = false;
|
||||
}
|
||||
fclose(targetfile);
|
||||
}
|
||||
else {
|
||||
retval = false;
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::scriptError(const char *fmt, ...)
|
||||
{
|
||||
va_list argp;
|
||||
va_start(argp, fmt);
|
||||
char buf[10000];
|
||||
vsnprintf(buf, 10000, fmt, argp);
|
||||
va_end(argp);
|
||||
errorstream<<"MAINMENU ERROR: "<<buf;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
void GUIEngine::setTopleftText(std::string append) {
|
||||
std::string toset = "Minetest " VERSION_STRING;
|
||||
|
||||
if (append != "") {
|
||||
toset += " / ";
|
||||
toset += append;
|
||||
}
|
||||
|
||||
m_irr_toplefttext->setText(narrow_to_wide(toset).c_str());
|
||||
}
|
260
src/guiEngine.h
Normal file
260
src/guiEngine.h
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 sapier
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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_ENGINE_H_
|
||||
#define GUI_ENGINE_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/* Includes */
|
||||
/******************************************************************************/
|
||||
#include "irrlichttypes.h"
|
||||
#include "modalMenu.h"
|
||||
#include "clouds.h"
|
||||
#include "guiLuaApi.h"
|
||||
#include "guiFormSpecMenu.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/* Typedefs and macros */
|
||||
/******************************************************************************/
|
||||
#define MAX_MENUBAR_BTN_COUNT 10
|
||||
#define MAX_MENUBAR_BTN_ID 256
|
||||
#define MIN_MENUBAR_BTN_ID (MAX_MENUBAR_BTN_ID - MAX_MENUBAR_BTN_COUNT)
|
||||
|
||||
/** texture layer ids */
|
||||
typedef enum {
|
||||
TEX_LAYER_BACKGROUND = 0,
|
||||
TEX_LAYER_OVERLAY,
|
||||
TEX_LAYER_HEADER,
|
||||
TEX_LAYER_FOOTER,
|
||||
TEX_LAYER_MAX
|
||||
} texture_layer;
|
||||
|
||||
/******************************************************************************/
|
||||
/* forward declarations */
|
||||
/******************************************************************************/
|
||||
class GUIEngine;
|
||||
struct MainMenuData;
|
||||
|
||||
/******************************************************************************/
|
||||
/* declarations */
|
||||
/******************************************************************************/
|
||||
|
||||
/** GUIEngine specific implementation of TextDest used within guiFormSpecMenu */
|
||||
class TextDestGuiEngine : public TextDest
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* default constructor
|
||||
* @param engine the engine data is transmitted for further processing
|
||||
*/
|
||||
TextDestGuiEngine(GUIEngine* engine);
|
||||
/**
|
||||
* receive fields transmitted by guiFormSpecMenu
|
||||
* @param fields map containing formspec field elements currently active
|
||||
*/
|
||||
void gotText(std::map<std::string, std::string> fields);
|
||||
|
||||
/**
|
||||
* receive text/events transmitted by guiFormSpecMenu
|
||||
* @param text textual representation of event
|
||||
*/
|
||||
void gotText(std::wstring text);
|
||||
private:
|
||||
/** target to transmit data to */
|
||||
GUIEngine* m_engine;
|
||||
};
|
||||
|
||||
|
||||
/** implementation of main menu based uppon formspecs */
|
||||
class GUIEngine {
|
||||
public:
|
||||
/** TextDestGuiEngine needs to transfer data to engine */
|
||||
friend class TextDestGuiEngine;
|
||||
/** guiLuaApi is used to initialize contained stack */
|
||||
friend class guiLuaApi;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
* @param dev device to draw at
|
||||
* @param parent parent gui element
|
||||
* @param menumgr manager to add menus to
|
||||
* @param smgr scene manager to add scene elements to
|
||||
* @param data struct to transfer data to main game handling
|
||||
*/
|
||||
GUIEngine( irr::IrrlichtDevice* dev,
|
||||
gui::IGUIElement* parent,
|
||||
IMenuManager *menumgr,
|
||||
scene::ISceneManager* smgr,
|
||||
MainMenuData* data);
|
||||
|
||||
/** default destructor */
|
||||
virtual ~GUIEngine();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* process field data recieved from formspec
|
||||
* @param fields data in field format
|
||||
*/
|
||||
void handleButtons(std::map<std::string, std::string> fields);
|
||||
/**
|
||||
* process events received from formspec
|
||||
* @param text events in textual form
|
||||
*/
|
||||
void handleEvent(std::string text);
|
||||
|
||||
/**
|
||||
* return dir of current menuscript
|
||||
*/
|
||||
std::string getScriptDir() {
|
||||
return m_scriptdir;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/* run main menu loop */
|
||||
void run();
|
||||
|
||||
/** handler to limit frame rate within main menu */
|
||||
void limitFrameRate();
|
||||
|
||||
/** device to draw at */
|
||||
irr::IrrlichtDevice* m_device;
|
||||
/** parent gui element */
|
||||
gui::IGUIElement* m_parent;
|
||||
/** manager to add menus to */
|
||||
IMenuManager* m_menumanager;
|
||||
/** scene manager to add scene elements to */
|
||||
scene::ISceneManager* m_smgr;
|
||||
/** pointer to data beeing transfered back to main game handling */
|
||||
MainMenuData* m_data;
|
||||
|
||||
/** representation of form source to be used in mainmenu formspec */
|
||||
FormspecFormSource* m_formspecgui;
|
||||
/** formspec input receiver */
|
||||
TextDestGuiEngine* m_buttonhandler;
|
||||
/** the formspec menu */
|
||||
GUIFormSpecMenu* m_menu;
|
||||
|
||||
/** variable used to abort menu and return back to main game handling */
|
||||
bool m_startgame;
|
||||
|
||||
/**
|
||||
* initialize lua stack
|
||||
* @param L stack to initialize
|
||||
*/
|
||||
void initalize_api(lua_State * L);
|
||||
|
||||
/**
|
||||
* run a lua script
|
||||
* @param script full path to script to run
|
||||
*/
|
||||
bool runScript(std::string script);
|
||||
|
||||
/**
|
||||
* script error handler to process errors within lua
|
||||
*/
|
||||
void scriptError(const char *fmt, ...);
|
||||
|
||||
/** lua stack */
|
||||
lua_State* m_engineluastack;
|
||||
/** lua internal stack number of error handler*/
|
||||
int m_luaerrorhandler;
|
||||
|
||||
/** script basefolder */
|
||||
std::string m_scriptdir;
|
||||
|
||||
/**
|
||||
* draw background layer
|
||||
* @param driver to use for drawing
|
||||
*/
|
||||
void drawBackground(video::IVideoDriver* driver);
|
||||
/**
|
||||
* draw overlay layer
|
||||
* @param driver to use for drawing
|
||||
*/
|
||||
void drawOverlay(video::IVideoDriver* driver);
|
||||
/**
|
||||
* draw header layer
|
||||
* @param driver to use for drawing
|
||||
*/
|
||||
void drawHeader(video::IVideoDriver* driver);
|
||||
/**
|
||||
* draw footer layer
|
||||
* @param driver to use for drawing
|
||||
*/
|
||||
void drawFooter(video::IVideoDriver* driver);
|
||||
|
||||
/**
|
||||
* load a texture for a specified layer
|
||||
* @param layer draw layer to specify texture
|
||||
* @param texturepath full path of texture to load
|
||||
*/
|
||||
bool setTexture(texture_layer layer,std::string texturepath);
|
||||
|
||||
/**
|
||||
* download a file using curl
|
||||
* @param url url to download
|
||||
* @param target file to store to
|
||||
*/
|
||||
bool downloadFile(std::string url,std::string target);
|
||||
|
||||
/** array containing pointers to current specified texture layers */
|
||||
video::ITexture* m_textures[TEX_LAYER_MAX];
|
||||
|
||||
/** draw version string in topleft corner */
|
||||
void drawVersion();
|
||||
|
||||
/**
|
||||
* specify text to be appended to version string
|
||||
* @param text to set
|
||||
*/
|
||||
void setTopleftText(std::string append);
|
||||
|
||||
/** pointer to gui element shown at topleft corner */
|
||||
irr::gui::IGUIStaticText* m_irr_toplefttext;
|
||||
|
||||
/** initialize cloud subsystem */
|
||||
void cloudInit();
|
||||
/** do preprocessing for cloud subsystem */
|
||||
void cloudPreProcess();
|
||||
/** do postprocessing for cloud subsystem */
|
||||
void cloudPostProcess();
|
||||
|
||||
/** internam data required for drawing clouds */
|
||||
struct clouddata {
|
||||
/** delta time since last cloud processing */
|
||||
f32 dtime;
|
||||
/** absolute time of last cloud processing */
|
||||
u32 lasttime;
|
||||
/** pointer to cloud class */
|
||||
Clouds* clouds;
|
||||
/** camera required for drawing clouds */
|
||||
scene::ICameraSceneNode* camera;
|
||||
};
|
||||
|
||||
/** is drawing of clouds enabled atm */
|
||||
bool m_clouds_enabled;
|
||||
/** data used to draw clouds */
|
||||
clouddata m_cloud;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* GUI_ENGINE_H_ */
|
133
src/guiFileSelectMenu.cpp
Normal file
133
src/guiFileSelectMenu.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 sapier
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 "guiFileSelectMenu.h"
|
||||
#include "util/string.h"
|
||||
#include <locale.h>
|
||||
|
||||
GUIFileSelectMenu::GUIFileSelectMenu(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
|
||||
std::string title, std::string formname) :
|
||||
GUIModalMenu(env, parent, id, menumgr)
|
||||
{
|
||||
m_title = narrow_to_wide(title);
|
||||
m_parent = parent;
|
||||
m_formname = formname;
|
||||
m_text_dst = 0;
|
||||
m_accepted = false;
|
||||
m_previous_locale = setlocale(LC_ALL,0);
|
||||
}
|
||||
|
||||
GUIFileSelectMenu::~GUIFileSelectMenu()
|
||||
{
|
||||
removeChildren();
|
||||
setlocale(LC_ALL,m_previous_locale.c_str());
|
||||
}
|
||||
|
||||
void GUIFileSelectMenu::removeChildren()
|
||||
{
|
||||
const core::list<gui::IGUIElement*> &children = getChildren();
|
||||
core::list<gui::IGUIElement*> children_copy;
|
||||
for (core::list<gui::IGUIElement*>::ConstIterator i = children.begin(); i
|
||||
!= children.end(); i++)
|
||||
{
|
||||
children_copy.push_back(*i);
|
||||
}
|
||||
for (core::list<gui::IGUIElement*>::Iterator i = children_copy.begin(); i
|
||||
!= children_copy.end(); i++)
|
||||
{
|
||||
(*i)->remove();
|
||||
}
|
||||
}
|
||||
|
||||
void GUIFileSelectMenu::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
removeChildren();
|
||||
m_fileOpenDialog = 0;
|
||||
|
||||
core::dimension2du size(600,400);
|
||||
core::rect < s32 > rect(0,0,screensize.X,screensize.Y);
|
||||
|
||||
DesiredRect = rect;
|
||||
recalculateAbsolutePosition(false);
|
||||
|
||||
m_fileOpenDialog =
|
||||
Environment->addFileOpenDialog(m_title.c_str(),false,this,-1);
|
||||
|
||||
core::position2di pos = core::position2di(screensize.X/2 - size.Width/2,screensize.Y/2 -size.Height/2);
|
||||
m_fileOpenDialog->setRelativePosition(pos);
|
||||
m_fileOpenDialog->setMinSize(size);
|
||||
}
|
||||
|
||||
void GUIFileSelectMenu::drawMenu()
|
||||
{
|
||||
gui::IGUISkin* skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
return;
|
||||
|
||||
gui::IGUIElement::draw();
|
||||
}
|
||||
|
||||
void GUIFileSelectMenu::acceptInput() {
|
||||
if ((m_text_dst != 0) && (this->m_formname != "")){
|
||||
std::map<std::string, std::string> fields;
|
||||
|
||||
if (m_accepted)
|
||||
fields[m_formname + "_accepted"] = wide_to_narrow(m_fileOpenDialog->getFileName());
|
||||
else
|
||||
fields[m_formname + "_canceled"] = m_formname;
|
||||
|
||||
this->m_text_dst->gotText(fields);
|
||||
}
|
||||
}
|
||||
|
||||
bool GUIFileSelectMenu::OnEvent(const SEvent& event)
|
||||
{
|
||||
|
||||
if (event.EventType == irr::EET_GUI_EVENT) {
|
||||
|
||||
int callerId = event.GUIEvent.Caller->getID();
|
||||
if (callerId >= 0) {
|
||||
std::cout << "CallerId:" << callerId << std::endl;
|
||||
}
|
||||
|
||||
switch (event.GUIEvent.EventType) {
|
||||
case gui::EGET_ELEMENT_CLOSED:
|
||||
case gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED:
|
||||
m_accepted=false;
|
||||
acceptInput();
|
||||
quitMenu();
|
||||
return true;
|
||||
break;
|
||||
|
||||
case gui::EGET_DIRECTORY_SELECTED:
|
||||
case gui::EGET_FILE_SELECTED:
|
||||
m_accepted=true;
|
||||
acceptInput();
|
||||
quitMenu();
|
||||
return true;
|
||||
break;
|
||||
|
||||
default:
|
||||
//ignore this event
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Parent ? Parent->OnEvent(event) : false;
|
||||
}
|
80
src/guiFileSelectMenu.h
Normal file
80
src/guiFileSelectMenu.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 sapier
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 GUIFILESELECTMENU_H_
|
||||
#define GUIFILESELECTMENU_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "modalMenu.h"
|
||||
#include "IGUIFileOpenDialog.h"
|
||||
#include "guiFormSpecMenu.h" //required because of TextDest only !!!
|
||||
|
||||
|
||||
class GUIFileSelectMenu: public GUIModalMenu
|
||||
{
|
||||
public:
|
||||
GUIFileSelectMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent,
|
||||
s32 id, IMenuManager *menumgr,
|
||||
std::string title,
|
||||
std::string formid);
|
||||
~GUIFileSelectMenu();
|
||||
|
||||
void removeChildren();
|
||||
|
||||
/*
|
||||
Remove and re-add (or reposition) stuff
|
||||
*/
|
||||
void regenerateGui(v2u32 screensize);
|
||||
|
||||
void drawMenu();
|
||||
|
||||
bool OnEvent(const SEvent& event);
|
||||
|
||||
bool isRunning() {
|
||||
return m_running;
|
||||
}
|
||||
|
||||
void setTextDest(TextDest * dest) {
|
||||
m_text_dst = dest;
|
||||
}
|
||||
|
||||
private:
|
||||
void acceptInput();
|
||||
|
||||
std::wstring m_title;
|
||||
bool m_accepted;
|
||||
gui::IGUIElement* m_parent;
|
||||
|
||||
std::string m_selectedPath;
|
||||
|
||||
gui::IGUIFileOpenDialog* m_fileOpenDialog;
|
||||
|
||||
std::string m_previous_locale;
|
||||
|
||||
bool m_running;
|
||||
|
||||
TextDest *m_text_dst;
|
||||
|
||||
std::string m_formname;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* GUIFILESELECTMENU_H_ */
|
File diff suppressed because it is too large
Load diff
|
@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#ifndef GUIINVENTORYMENU_HEADER
|
||||
#define GUIINVENTORYMENU_HEADER
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "inventory.h"
|
||||
#include "inventorymanager.h"
|
||||
|
@ -29,6 +31,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
class IGameDef;
|
||||
class InventoryManager;
|
||||
|
||||
typedef enum {
|
||||
f_Button,
|
||||
f_ListBox,
|
||||
f_TabHeader,
|
||||
f_CheckBox,
|
||||
f_DropDown,
|
||||
f_Unknown
|
||||
} FormspecFieldType;
|
||||
|
||||
struct TextDest
|
||||
{
|
||||
virtual ~TextDest() {};
|
||||
|
@ -113,10 +124,19 @@ class GUIFormSpecMenu : public GUIModalMenu
|
|||
pos(a_pos),
|
||||
geom(a_geom)
|
||||
{
|
||||
scale = true;
|
||||
}
|
||||
ImageDrawSpec(const std::string &a_name,
|
||||
v2s32 a_pos):
|
||||
name(a_name),
|
||||
pos(a_pos)
|
||||
{
|
||||
scale = false;
|
||||
}
|
||||
std::string name;
|
||||
v2s32 pos;
|
||||
v2s32 geom;
|
||||
bool scale;
|
||||
};
|
||||
|
||||
struct FieldSpec
|
||||
|
@ -131,7 +151,7 @@ class GUIFormSpecMenu : public GUIModalMenu
|
|||
fid(id)
|
||||
{
|
||||
send = false;
|
||||
is_button = false;
|
||||
ftype = f_Unknown;
|
||||
is_exit = false;
|
||||
tooltip="";
|
||||
}
|
||||
|
@ -140,12 +160,24 @@ class GUIFormSpecMenu : public GUIModalMenu
|
|||
std::wstring fdefault;
|
||||
int fid;
|
||||
bool send;
|
||||
bool is_button;
|
||||
FormspecFieldType ftype;
|
||||
bool is_exit;
|
||||
core::rect<s32> rect;
|
||||
std::string tooltip;
|
||||
};
|
||||
|
||||
struct BoxDrawSpec {
|
||||
BoxDrawSpec(v2s32 a_pos, v2s32 a_geom,irr::video::SColor a_color):
|
||||
pos(a_pos),
|
||||
geom(a_geom),
|
||||
color(a_color)
|
||||
{
|
||||
}
|
||||
v2s32 pos;
|
||||
v2s32 geom;
|
||||
irr::video::SColor color;
|
||||
};
|
||||
|
||||
public:
|
||||
GUIFormSpecMenu(irr::IrrlichtDevice* dev,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
|
@ -153,6 +185,7 @@ public:
|
|||
InventoryManager *invmgr,
|
||||
IGameDef *gamedef
|
||||
);
|
||||
|
||||
~GUIFormSpecMenu();
|
||||
|
||||
void setFormSpec(const std::string &formspec_string,
|
||||
|
@ -175,6 +208,20 @@ public:
|
|||
m_text_dst = text_dst;
|
||||
}
|
||||
|
||||
void allowClose(bool value)
|
||||
{
|
||||
m_allowclose = value;
|
||||
}
|
||||
|
||||
void useGettext(bool value) {
|
||||
m_use_gettext = true;
|
||||
}
|
||||
|
||||
void lockSize(bool lock,v2u32 basescreensize=v2u32(0,0)) {
|
||||
m_lock = lock;
|
||||
m_lockscreensize = basescreensize;
|
||||
}
|
||||
|
||||
void removeChildren();
|
||||
/*
|
||||
Remove and re-add (or reposition) stuff
|
||||
|
@ -188,18 +235,21 @@ public:
|
|||
void updateSelectedItem();
|
||||
ItemStack verifySelectedItem();
|
||||
|
||||
void acceptInput();
|
||||
void acceptInput(int evttype=-1);
|
||||
bool OnEvent(const SEvent& event);
|
||||
|
||||
int getListboxIndex(std::string listboxname);
|
||||
|
||||
protected:
|
||||
v2s32 getBasePos() const
|
||||
{
|
||||
return padding + AbsoluteRect.UpperLeftCorner;
|
||||
return padding + offset + AbsoluteRect.UpperLeftCorner;
|
||||
}
|
||||
|
||||
v2s32 padding;
|
||||
v2s32 spacing;
|
||||
v2s32 imgsize;
|
||||
v2s32 offset;
|
||||
|
||||
irr::IrrlichtDevice* m_device;
|
||||
InventoryManager *m_invmgr;
|
||||
|
@ -214,7 +264,10 @@ protected:
|
|||
std::vector<ImageDrawSpec> m_backgrounds;
|
||||
std::vector<ImageDrawSpec> m_images;
|
||||
std::vector<ImageDrawSpec> m_itemimages;
|
||||
std::vector<BoxDrawSpec> m_boxes;
|
||||
std::vector<FieldSpec> m_fields;
|
||||
std::vector<std::pair<FieldSpec,gui::IGUIListBox*> > m_listboxes;
|
||||
std::vector<std::pair<FieldSpec,gui::IGUICheckBox*> > m_checkboxes;
|
||||
|
||||
ItemSpec *m_selected_item;
|
||||
u32 m_selected_amount;
|
||||
|
@ -228,6 +281,74 @@ protected:
|
|||
|
||||
v2s32 m_pointer;
|
||||
gui::IGUIStaticText *m_tooltip_element;
|
||||
|
||||
bool m_allowclose;
|
||||
bool m_use_gettext;
|
||||
bool m_lock;
|
||||
v2u32 m_lockscreensize;
|
||||
private:
|
||||
typedef struct {
|
||||
v2s32 size;
|
||||
s32 helptext_h;
|
||||
core::rect<s32> rect;
|
||||
v2s32 basepos;
|
||||
int bp_set;
|
||||
v2u32 screensize;
|
||||
std::map<std::wstring,int> listbox_selections;
|
||||
} parserData;
|
||||
|
||||
std::vector<video::ITexture *> m_Textures;
|
||||
|
||||
void parseElement(parserData* data,std::string element);
|
||||
|
||||
void parseSize(parserData* data,std::string element);
|
||||
void parseList(parserData* data,std::string element);
|
||||
void parseCheckbox(parserData* data,std::string element);
|
||||
void parseImage(parserData* data,std::string element);
|
||||
void parseItemImage(parserData* data,std::string element);
|
||||
void parseButton(parserData* data,std::string element,std::string typ);
|
||||
void parseBackground(parserData* data,std::string element);
|
||||
void parseTextList(parserData* data,std::string element);
|
||||
void parseDropDown(parserData* data,std::string element);
|
||||
void parsePwdField(parserData* data,std::string element);
|
||||
void parseField(parserData* data,std::string element,std::string type);
|
||||
void parseSimpleField(parserData* data,std::vector<std::string> &parts);
|
||||
void parseTextArea(parserData* data,std::vector<std::string>& parts,std::string type);
|
||||
void parseLabel(parserData* data,std::string element);
|
||||
void parseVertLabel(parserData* data,std::string element);
|
||||
void parseImageButton(parserData* data,std::string element,std::string type);
|
||||
void parseItemImageButton(parserData* data,std::string element);
|
||||
void parseTabHeader(parserData* data,std::string element);
|
||||
void parseBox(parserData* data,std::string element);
|
||||
|
||||
irr::video::SColor getColor(std::string color,bool& valid_color);
|
||||
};
|
||||
|
||||
class FormspecFormSource: public IFormSource
|
||||
{
|
||||
public:
|
||||
FormspecFormSource(std::string formspec,FormspecFormSource** game_formspec)
|
||||
{
|
||||
m_formspec = formspec;
|
||||
m_game_formspec = game_formspec;
|
||||
}
|
||||
|
||||
~FormspecFormSource()
|
||||
{
|
||||
*m_game_formspec = 0;
|
||||
}
|
||||
|
||||
void setForm(std::string formspec) {
|
||||
m_formspec = formspec;
|
||||
}
|
||||
|
||||
std::string getForm()
|
||||
{
|
||||
return m_formspec;
|
||||
}
|
||||
|
||||
std::string m_formspec;
|
||||
FormspecFormSource** m_game_formspec;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
1067
src/guiLuaApi.cpp
Normal file
1067
src/guiLuaApi.cpp
Normal file
File diff suppressed because it is too large
Load diff
183
src/guiLuaApi.h
Normal file
183
src/guiLuaApi.h
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2013 sapier
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser 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 GUILUAAPI_H_
|
||||
#define GUILUAAPI_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/* Includes */
|
||||
/******************************************************************************/
|
||||
#include "serverlist.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/* Typedefs and macros */
|
||||
/******************************************************************************/
|
||||
typedef int (*lua_CFunction) (lua_State *L);
|
||||
|
||||
/******************************************************************************/
|
||||
/* forward declarations */
|
||||
/******************************************************************************/
|
||||
class GUIEngine;
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
/* declarations */
|
||||
/******************************************************************************/
|
||||
|
||||
/** Implementation of lua api support for mainmenu */
|
||||
class guiLuaApi {
|
||||
|
||||
public:
|
||||
/**
|
||||
* initialize given Lua stack
|
||||
* @param L lua stack to initialize
|
||||
* @param engine pointer to GUIEngine element to use as reference
|
||||
*/
|
||||
static void initialize(lua_State* L,GUIEngine* engine);
|
||||
|
||||
/** default destructor */
|
||||
virtual ~guiLuaApi() {}
|
||||
|
||||
private:
|
||||
/**
|
||||
* read a text variable from gamedata table within lua stack
|
||||
* @param L stack to read variable from
|
||||
* @param name name of variable to read
|
||||
* @return string value of requested variable
|
||||
*/
|
||||
static std::string getTextData(lua_State *L, std::string name);
|
||||
|
||||
/**
|
||||
* read a integer variable from gamedata table within lua stack
|
||||
* @param L stack to read variable from
|
||||
* @param name name of variable to read
|
||||
* @return integer value of requested variable
|
||||
*/
|
||||
static int getIntegerData(lua_State *L, std::string name,bool& valid);
|
||||
|
||||
/**
|
||||
* read a bool variable from gamedata table within lua stack
|
||||
* @param L stack to read variable from
|
||||
* @param name name of variable to read
|
||||
* @return bool value of requested variable
|
||||
*/
|
||||
static int getBoolData(lua_State *L, std::string name,bool& valid);
|
||||
|
||||
/**
|
||||
* get the corresponding engine pointer from a lua stack
|
||||
* @param L stack to read pointer from
|
||||
* @return pointer to GUIEngine
|
||||
*/
|
||||
static GUIEngine* get_engine(lua_State *L);
|
||||
|
||||
|
||||
/**
|
||||
* register a static member function as lua api call at current position of stack
|
||||
* @param L stack to registe fct to
|
||||
* @param name of function within lua
|
||||
* @param fct C-Function to call on lua call of function
|
||||
* @param top current top of stack
|
||||
*/
|
||||
static bool registerFunction( lua_State* L,
|
||||
const char* name,
|
||||
lua_CFunction fct,
|
||||
int top
|
||||
);
|
||||
|
||||
/**
|
||||
* check if a path is within some of minetests folders
|
||||
* @param path path to check
|
||||
* @return true/false
|
||||
*/
|
||||
static bool isMinetestPath(std::string path);
|
||||
|
||||
//api calls
|
||||
|
||||
static int l_start(lua_State *L);
|
||||
|
||||
static int l_close(lua_State *L);
|
||||
|
||||
static int l_create_world(lua_State *L);
|
||||
|
||||
static int l_delete_world(lua_State *L);
|
||||
|
||||
static int l_get_worlds(lua_State *L);
|
||||
|
||||
static int l_get_games(lua_State *L);
|
||||
|
||||
static int l_get_favorites(lua_State *L);
|
||||
|
||||
static int l_delete_favorite(lua_State *L);
|
||||
|
||||
static int l_get_version(lua_State *L);
|
||||
|
||||
//gui
|
||||
|
||||
static int l_show_keys_menu(lua_State *L);
|
||||
|
||||
static int l_show_file_open_dialog(lua_State *L);
|
||||
|
||||
static int l_set_topleft_text(lua_State *L);
|
||||
|
||||
static int l_set_clouds(lua_State *L);
|
||||
|
||||
static int l_get_textlist_index(lua_State *L);
|
||||
|
||||
static int l_set_background(lua_State *L);
|
||||
|
||||
static int l_update_formspec(lua_State *L);
|
||||
|
||||
//settings
|
||||
|
||||
static int l_setting_set(lua_State *L);
|
||||
|
||||
static int l_setting_get(lua_State *L);
|
||||
|
||||
static int l_setting_getbool(lua_State *L);
|
||||
|
||||
static int l_setting_setbool(lua_State *L);
|
||||
|
||||
//filesystem
|
||||
|
||||
static int l_get_scriptdir(lua_State *L);
|
||||
|
||||
static int l_get_modpath(lua_State *L);
|
||||
|
||||
static int l_get_gamepath(lua_State *L);
|
||||
|
||||
static int l_get_dirlist(lua_State *L);
|
||||
|
||||
static int l_create_dir(lua_State *L);
|
||||
|
||||
static int l_delete_dir(lua_State *L);
|
||||
|
||||
static int l_copy_dir(lua_State *L);
|
||||
|
||||
static int l_extract_zip(lua_State *L);
|
||||
|
||||
static int l_get_modstore_details(lua_State *L);
|
||||
|
||||
static int l_get_modstore_list(lua_State *L);
|
||||
|
||||
static int l_download_file(lua_State *L);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
1521
src/guiMainMenu.cpp
1521
src/guiMainMenu.cpp
File diff suppressed because it is too large
Load diff
|
@ -24,15 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "modalMenu.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include "subgame.h"
|
||||
#include "serverlist.h"
|
||||
|
||||
class IGameCallback;
|
||||
|
||||
enum {
|
||||
SERVERLIST_FAVORITES,
|
||||
SERVERLIST_PUBLIC,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -45,113 +36,31 @@ enum
|
|||
|
||||
struct MainMenuData
|
||||
{
|
||||
// These are in the native format of the gui elements
|
||||
// Generic
|
||||
int selected_tab;
|
||||
std::string selected_game;
|
||||
std::string selected_game_name;
|
||||
// Client options
|
||||
std::string servername;
|
||||
std::string serverdescription;
|
||||
std::wstring address;
|
||||
std::wstring port;
|
||||
std::wstring name;
|
||||
std::wstring password;
|
||||
bool fancy_trees;
|
||||
bool smooth_lighting;
|
||||
bool clouds_3d;
|
||||
bool opaque_water;
|
||||
bool mip_map;
|
||||
bool anisotropic_filter;
|
||||
bool bilinear_filter;
|
||||
bool trilinear_filter;
|
||||
int enable_shaders;
|
||||
bool preload_item_visuals;
|
||||
bool enable_particles;
|
||||
bool liquid_finite;
|
||||
std::string address;
|
||||
std::string port;
|
||||
std::string name;
|
||||
std::string password;
|
||||
|
||||
// Server options
|
||||
bool creative_mode;
|
||||
bool enable_damage;
|
||||
bool enable_public;
|
||||
int selected_world;
|
||||
bool simple_singleplayer_mode;
|
||||
|
||||
// Actions
|
||||
std::wstring create_world_name;
|
||||
std::string create_world_gameid;
|
||||
bool only_refresh;
|
||||
|
||||
int selected_serverlist;
|
||||
|
||||
std::vector<WorldSpec> worlds;
|
||||
std::vector<SubgameSpec> games;
|
||||
std::vector<ServerListSpec> servers;
|
||||
bool kill;
|
||||
|
||||
//error handling
|
||||
std::string errormessage;
|
||||
MainMenuData():
|
||||
// Generic
|
||||
selected_tab(0),
|
||||
selected_game("minetest"),
|
||||
selected_game_name("Minetest"),
|
||||
// Client opts
|
||||
fancy_trees(false),
|
||||
smooth_lighting(false),
|
||||
// Server opts
|
||||
creative_mode(false),
|
||||
enable_damage(false),
|
||||
enable_public(false),
|
||||
selected_world(0),
|
||||
simple_singleplayer_mode(false),
|
||||
// Actions
|
||||
only_refresh(false),
|
||||
|
||||
selected_serverlist(SERVERLIST_FAVORITES)
|
||||
errormessage("")
|
||||
{}
|
||||
};
|
||||
|
||||
class GUIMainMenu : public GUIModalMenu
|
||||
{
|
||||
public:
|
||||
GUIMainMenu(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id,
|
||||
IMenuManager *menumgr,
|
||||
MainMenuData *data,
|
||||
IGameCallback *gamecallback);
|
||||
~GUIMainMenu();
|
||||
|
||||
void removeChildren();
|
||||
// Remove and re-add (or reposition) stuff
|
||||
void regenerateGui(v2u32 screensize);
|
||||
void drawMenu();
|
||||
void readInput(MainMenuData *dst);
|
||||
void acceptInput();
|
||||
bool getStatus()
|
||||
{ return m_accepted; }
|
||||
bool OnEvent(const SEvent& event);
|
||||
void createNewWorld(std::wstring name, std::string gameid);
|
||||
void deleteWorld(const std::vector<std::string> &paths);
|
||||
int getTab();
|
||||
void displayMessageMenu(std::wstring msg);
|
||||
|
||||
private:
|
||||
MainMenuData *m_data;
|
||||
bool m_accepted;
|
||||
IGameCallback *m_gamecallback;
|
||||
|
||||
gui::IGUIEnvironment* env;
|
||||
gui::IGUIElement* parent;
|
||||
s32 id;
|
||||
IMenuManager *menumgr;
|
||||
|
||||
std::vector<int> m_world_indices;
|
||||
|
||||
bool m_is_regenerating;
|
||||
v2s32 m_topleft_client;
|
||||
v2s32 m_size_client;
|
||||
v2s32 m_topleft_server;
|
||||
v2s32 m_size_server;
|
||||
void updateGuiServerList();
|
||||
void serverListOnSelected();
|
||||
ServerListSpec getServerListSpec(std::string address, std::string port);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
463
src/main.cpp
463
src/main.cpp
|
@ -78,6 +78,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "serverlist.h"
|
||||
#include "sound.h"
|
||||
#include "sound_openal.h"
|
||||
#include "guiEngine.h"
|
||||
|
||||
/*
|
||||
Settings.
|
||||
|
@ -660,180 +661,6 @@ private:
|
|||
bool rightreleased;
|
||||
};
|
||||
|
||||
struct MenuTextures
|
||||
{
|
||||
std::string current_gameid;
|
||||
bool global_textures;
|
||||
video::ITexture *background;
|
||||
video::ITexture *overlay;
|
||||
video::ITexture *header;
|
||||
video::ITexture *footer;
|
||||
|
||||
MenuTextures():
|
||||
global_textures(false),
|
||||
background(NULL),
|
||||
overlay(NULL),
|
||||
header(NULL),
|
||||
footer(NULL)
|
||||
{}
|
||||
|
||||
static video::ITexture* getMenuTexture(const std::string &tname,
|
||||
video::IVideoDriver* driver, const SubgameSpec *spec)
|
||||
{
|
||||
if(spec){
|
||||
std::string path;
|
||||
// eg. minetest_menu_background.png (for texture packs)
|
||||
std::string pack_tname = spec->id + "_menu_" + tname + ".png";
|
||||
path = getTexturePath(pack_tname);
|
||||
if(path != "")
|
||||
return driver->getTexture(path.c_str());
|
||||
// eg. games/minetest_game/menu/background.png
|
||||
path = getImagePath(spec->path + DIR_DELIM + "menu" + DIR_DELIM + tname + ".png");
|
||||
if(path != "")
|
||||
return driver->getTexture(path.c_str());
|
||||
} else {
|
||||
std::string path;
|
||||
// eg. menu_background.png
|
||||
std::string pack_tname = "menu_" + tname + ".png";
|
||||
path = getTexturePath(pack_tname);
|
||||
if(path != "")
|
||||
return driver->getTexture(path.c_str());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void update(video::IVideoDriver* driver, const SubgameSpec *spec, int tab)
|
||||
{
|
||||
if(tab == TAB_SINGLEPLAYER){
|
||||
if(spec->id == current_gameid)
|
||||
return;
|
||||
current_gameid = spec->id;
|
||||
global_textures = false;
|
||||
background = getMenuTexture("background", driver, spec);
|
||||
overlay = getMenuTexture("overlay", driver, spec);
|
||||
header = getMenuTexture("header", driver, spec);
|
||||
footer = getMenuTexture("footer", driver, spec);
|
||||
} else {
|
||||
if(global_textures)
|
||||
return;
|
||||
current_gameid = "";
|
||||
global_textures = true;
|
||||
background = getMenuTexture("background", driver, NULL);
|
||||
overlay = getMenuTexture("overlay", driver, NULL);
|
||||
header = getMenuTexture("header", driver, NULL);
|
||||
footer = getMenuTexture("footer", driver, NULL);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void drawMenuBackground(video::IVideoDriver* driver, const MenuTextures &menutextures)
|
||||
{
|
||||
v2u32 screensize = driver->getScreenSize();
|
||||
video::ITexture *texture = menutextures.background;
|
||||
|
||||
/* If no texture, draw background of solid color */
|
||||
if(!texture){
|
||||
video::SColor color(255,80,58,37);
|
||||
core::rect<s32> rect(0, 0, screensize.X, screensize.Y);
|
||||
driver->draw2DRectangle(color, rect, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Draw background texture */
|
||||
v2u32 sourcesize = texture->getSize();
|
||||
driver->draw2DImage(texture,
|
||||
core::rect<s32>(0, 0, screensize.X, screensize.Y),
|
||||
core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
|
||||
void drawMenuOverlay(video::IVideoDriver* driver, const MenuTextures &menutextures)
|
||||
{
|
||||
v2u32 screensize = driver->getScreenSize();
|
||||
video::ITexture *texture = menutextures.overlay;
|
||||
|
||||
/* If no texture, draw nothing */
|
||||
if(!texture)
|
||||
return;
|
||||
|
||||
/* Draw overlay texture */
|
||||
v2u32 sourcesize = texture->getSize();
|
||||
driver->draw2DImage(texture,
|
||||
core::rect<s32>(0, 0, screensize.X, screensize.Y),
|
||||
core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
|
||||
void drawMenuHeader(video::IVideoDriver* driver, const MenuTextures &menutextures)
|
||||
{
|
||||
core::dimension2d<u32> screensize = driver->getScreenSize();
|
||||
video::ITexture *texture = menutextures.header;
|
||||
|
||||
/* If no texture, draw nothing */
|
||||
if(!texture)
|
||||
return;
|
||||
|
||||
f32 mult = (((f32)screensize.Width / 2)) /
|
||||
((f32)texture->getOriginalSize().Width);
|
||||
|
||||
v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult,
|
||||
((f32)texture->getOriginalSize().Height) * mult);
|
||||
|
||||
// Don't draw the header is there isn't enough room
|
||||
s32 free_space = (((s32)screensize.Height)-320)/2;
|
||||
if (free_space > splashsize.Y) {
|
||||
core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
|
||||
splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
|
||||
((free_space/2)-splashsize.Y/2)+10);
|
||||
|
||||
video::SColor bgcolor(255,50,50,50);
|
||||
|
||||
driver->draw2DImage(texture, splashrect,
|
||||
core::rect<s32>(core::position2d<s32>(0,0),
|
||||
core::dimension2di(texture->getSize())),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
void drawMenuFooter(video::IVideoDriver* driver, const MenuTextures &menutextures)
|
||||
{
|
||||
core::dimension2d<u32> screensize = driver->getScreenSize();
|
||||
video::ITexture *texture = menutextures.footer;
|
||||
|
||||
/* If no texture, draw nothing */
|
||||
if(!texture)
|
||||
return;
|
||||
|
||||
f32 mult = (((f32)screensize.Width)) /
|
||||
((f32)texture->getOriginalSize().Width);
|
||||
|
||||
v2s32 footersize(((f32)texture->getOriginalSize().Width) * mult,
|
||||
((f32)texture->getOriginalSize().Height) * mult);
|
||||
|
||||
// Don't draw the footer if there isn't enough room
|
||||
s32 free_space = (((s32)screensize.Height)-320)/2;
|
||||
if (free_space > footersize.Y) {
|
||||
core::rect<s32> rect(0,0,footersize.X,footersize.Y);
|
||||
rect += v2s32(screensize.Width/2,screensize.Height-footersize.Y);
|
||||
rect -= v2s32(footersize.X/2, 0);
|
||||
|
||||
driver->draw2DImage(texture, rect,
|
||||
core::rect<s32>(core::position2d<s32>(0,0),
|
||||
core::dimension2di(texture->getSize())),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
static const SubgameSpec* getMenuGame(const MainMenuData &menudata)
|
||||
{
|
||||
for(size_t i=0; i<menudata.games.size(); i++){
|
||||
if(menudata.games[i].id == menudata.selected_game){
|
||||
return &menudata.games[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // !SERVER
|
||||
|
||||
// These are defined global so that they're not optimized too much.
|
||||
|
@ -1730,83 +1557,37 @@ int main(int argc, char *argv[])
|
|||
|
||||
// Initialize menu data
|
||||
MainMenuData menudata;
|
||||
if(g_settings->exists("selected_mainmenu_tab"))
|
||||
menudata.selected_tab = g_settings->getS32("selected_mainmenu_tab");
|
||||
if(g_settings->exists("selected_serverlist"))
|
||||
menudata.selected_serverlist = g_settings->getS32("selected_serverlist");
|
||||
if(g_settings->exists("selected_mainmenu_game")){
|
||||
menudata.selected_game = g_settings->get("selected_mainmenu_game");
|
||||
menudata.selected_game_name = findSubgame(menudata.selected_game).name;
|
||||
}
|
||||
menudata.address = narrow_to_wide(address);
|
||||
menudata.name = narrow_to_wide(playername);
|
||||
menudata.port = narrow_to_wide(itos(port));
|
||||
menudata.kill = kill;
|
||||
menudata.address = address;
|
||||
menudata.name = playername;
|
||||
menudata.port = itos(port);
|
||||
menudata.errormessage = wide_to_narrow(error_message);
|
||||
error_message = L"";
|
||||
if(cmd_args.exists("password"))
|
||||
menudata.password = narrow_to_wide(cmd_args.get("password"));
|
||||
menudata.fancy_trees = g_settings->getBool("new_style_leaves");
|
||||
menudata.smooth_lighting = g_settings->getBool("smooth_lighting");
|
||||
menudata.clouds_3d = g_settings->getBool("enable_3d_clouds");
|
||||
menudata.opaque_water = g_settings->getBool("opaque_water");
|
||||
menudata.mip_map = g_settings->getBool("mip_map");
|
||||
menudata.anisotropic_filter = g_settings->getBool("anisotropic_filter");
|
||||
menudata.bilinear_filter = g_settings->getBool("bilinear_filter");
|
||||
menudata.trilinear_filter = g_settings->getBool("trilinear_filter");
|
||||
menudata.enable_shaders = g_settings->getS32("enable_shaders");
|
||||
menudata.preload_item_visuals = g_settings->getBool("preload_item_visuals");
|
||||
menudata.enable_particles = g_settings->getBool("enable_particles");
|
||||
menudata.liquid_finite = g_settings->getBool("liquid_finite");
|
||||
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, menudata.mip_map);
|
||||
menudata.creative_mode = g_settings->getBool("creative_mode");
|
||||
menudata.enable_damage = g_settings->getBool("enable_damage");
|
||||
menudata.password = cmd_args.get("password");
|
||||
|
||||
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
|
||||
|
||||
menudata.enable_public = g_settings->getBool("server_announce");
|
||||
// Default to selecting nothing
|
||||
menudata.selected_world = -1;
|
||||
// Get world listing for the menu
|
||||
|
||||
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
|
||||
// If there is only one world, select it
|
||||
if(worldspecs.size() == 1){
|
||||
menudata.selected_world = 0;
|
||||
}
|
||||
// Otherwise try to select according to selected_world_path
|
||||
else if(g_settings->exists("selected_world_path")){
|
||||
std::string trypath = g_settings->get("selected_world_path");
|
||||
for(u32 i=0; i<worldspecs.size(); i++){
|
||||
if(worldspecs[i].path == trypath){
|
||||
menudata.selected_world = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a world was commanded, append and select it
|
||||
if(commanded_world != ""){
|
||||
|
||||
std::string gameid = getWorldGameId(commanded_world, true);
|
||||
std::string name = _("[--world parameter]");
|
||||
if(gameid == ""){
|
||||
gameid = g_settings->get("default_game");
|
||||
name += " [new]";
|
||||
}
|
||||
WorldSpec spec(commanded_world, name, gameid);
|
||||
worldspecs.push_back(spec);
|
||||
menudata.selected_world = worldspecs.size()-1;
|
||||
//TODO find within worldspecs and set config
|
||||
}
|
||||
// Copy worldspecs to menu
|
||||
menudata.worlds = worldspecs;
|
||||
// Get game listing
|
||||
menudata.games = getAvailableGames();
|
||||
// If selected game doesn't exist, take first from list
|
||||
if(findSubgame(menudata.selected_game).id == "" &&
|
||||
!menudata.games.empty()){
|
||||
menudata.selected_game = menudata.games[0].id;
|
||||
}
|
||||
const SubgameSpec *menugame = getMenuGame(menudata);
|
||||
|
||||
MenuTextures menutextures;
|
||||
menutextures.update(driver, menugame, menudata.selected_tab);
|
||||
|
||||
if(skip_main_menu == false)
|
||||
{
|
||||
video::IVideoDriver* driver = device->getVideoDriver();
|
||||
float fps_max = g_settings->getFloat("fps_max");
|
||||
|
||||
infostream<<"Waiting for other menus"<<std::endl;
|
||||
while(device->run() && kill == false)
|
||||
{
|
||||
|
@ -1814,7 +1595,6 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
driver->beginScene(true, true,
|
||||
video::SColor(255,128,128,128));
|
||||
drawMenuBackground(driver, menutextures);
|
||||
guienv->drawAll();
|
||||
driver->endScene();
|
||||
// On some computers framerate doesn't seem to be
|
||||
|
@ -1823,170 +1603,40 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
infostream<<"Waited for other menus"<<std::endl;
|
||||
|
||||
GUIMainMenu *menu =
|
||||
new GUIMainMenu(guienv, guiroot, -1,
|
||||
&g_menumgr, &menudata, g_gamecallback);
|
||||
menu->allowFocusRemoval(true);
|
||||
GUIEngine* temp = new GUIEngine(device, guiroot, &g_menumgr,smgr,&menudata);
|
||||
|
||||
delete temp;
|
||||
//once finished you'll never end up here
|
||||
smgr->clear();
|
||||
kill = menudata.kill;
|
||||
|
||||
if(error_message != L"")
|
||||
{
|
||||
verbosestream<<"error_message = "
|
||||
<<wide_to_narrow(error_message)<<std::endl;
|
||||
|
||||
GUIMessageMenu *menu2 =
|
||||
new GUIMessageMenu(guienv, guiroot, -1,
|
||||
&g_menumgr, error_message.c_str());
|
||||
menu2->drop();
|
||||
error_message = L"";
|
||||
}
|
||||
|
||||
// Time is in milliseconds, for clouds
|
||||
u32 lasttime = device->getTimer()->getTime();
|
||||
|
||||
MenuMusicFetcher soundfetcher;
|
||||
ISoundManager *sound = NULL;
|
||||
#if USE_SOUND
|
||||
sound = createOpenALSoundManager(&soundfetcher);
|
||||
#endif
|
||||
if(!sound)
|
||||
sound = &dummySoundManager;
|
||||
SimpleSoundSpec spec;
|
||||
spec.name = "main_menu";
|
||||
spec.gain = 1;
|
||||
s32 handle = sound->playSound(spec, true);
|
||||
|
||||
infostream<<"Created main menu"<<std::endl;
|
||||
|
||||
while(device->run() && kill == false)
|
||||
{
|
||||
if(menu->getStatus() == true)
|
||||
break;
|
||||
|
||||
// Game can be selected in the menu
|
||||
menugame = getMenuGame(menudata);
|
||||
menutextures.update(driver, menugame, menu->getTab());
|
||||
// Clouds for the main menu
|
||||
bool cloud_menu_background = g_settings->getBool("menu_clouds");
|
||||
if(menugame){
|
||||
// If game has regular background and no overlay, don't use clouds
|
||||
if(cloud_menu_background && menutextures.background &&
|
||||
!menutextures.overlay){
|
||||
cloud_menu_background = false;
|
||||
}
|
||||
// If game game has overlay and no regular background, always draw clouds
|
||||
else if(menutextures.overlay && !menutextures.background){
|
||||
cloud_menu_background = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Time calc for the clouds
|
||||
f32 dtime=0; // in seconds
|
||||
if (cloud_menu_background) {
|
||||
u32 time = device->getTimer()->getTime();
|
||||
if(time > lasttime)
|
||||
dtime = (time - lasttime) / 1000.0;
|
||||
else
|
||||
dtime = 0;
|
||||
lasttime = time;
|
||||
}
|
||||
|
||||
//driver->beginScene(true, true, video::SColor(255,0,0,0));
|
||||
driver->beginScene(true, true, video::SColor(255,140,186,250));
|
||||
|
||||
if (cloud_menu_background) {
|
||||
// *3 otherwise the clouds would move very slowly
|
||||
g_menuclouds->step(dtime*3);
|
||||
g_menuclouds->render();
|
||||
g_menucloudsmgr->drawAll();
|
||||
drawMenuOverlay(driver, menutextures);
|
||||
drawMenuHeader(driver, menutextures);
|
||||
drawMenuFooter(driver, menutextures);
|
||||
} else {
|
||||
drawMenuBackground(driver, menutextures);
|
||||
drawMenuHeader(driver, menutextures);
|
||||
drawMenuFooter(driver, menutextures);
|
||||
}
|
||||
|
||||
guienv->drawAll();
|
||||
|
||||
driver->endScene();
|
||||
|
||||
// On some computers framerate doesn't seem to be
|
||||
// automatically limited
|
||||
if (cloud_menu_background) {
|
||||
// Time of frame without fps limit
|
||||
float busytime;
|
||||
u32 busytime_u32;
|
||||
// not using getRealTime is necessary for wine
|
||||
u32 time = device->getTimer()->getTime();
|
||||
if(time > lasttime)
|
||||
busytime_u32 = time - lasttime;
|
||||
else
|
||||
busytime_u32 = 0;
|
||||
busytime = busytime_u32 / 1000.0;
|
||||
|
||||
// FPS limiter
|
||||
u32 frametime_min = 1000./fps_max;
|
||||
|
||||
if(busytime_u32 < frametime_min) {
|
||||
u32 sleeptime = frametime_min - busytime_u32;
|
||||
device->sleep(sleeptime);
|
||||
}
|
||||
} else {
|
||||
sleep_ms(25);
|
||||
}
|
||||
}
|
||||
sound->stopSound(handle);
|
||||
if(sound != &dummySoundManager){
|
||||
delete sound;
|
||||
sound = NULL;
|
||||
}
|
||||
|
||||
// Save controls status
|
||||
menu->readInput(&menudata);
|
||||
|
||||
infostream<<"Dropping main menu"<<std::endl;
|
||||
|
||||
menu->drop();
|
||||
}
|
||||
|
||||
playername = wide_to_narrow(menudata.name);
|
||||
if (playername == "")
|
||||
playername = std::string("Guest") + itos(myrand_range(1000,9999));
|
||||
password = translatePassword(playername, menudata.password);
|
||||
//update worldspecs (necessary as new world may have been created)
|
||||
worldspecs = getAvailableWorlds();
|
||||
|
||||
if (menudata.name == "")
|
||||
menudata.name = std::string("Guest") + itos(myrand_range(1000,9999));
|
||||
else
|
||||
playername = menudata.name;
|
||||
|
||||
password = translatePassword(playername, narrow_to_wide(menudata.password));
|
||||
//infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
|
||||
|
||||
address = wide_to_narrow(menudata.address);
|
||||
int newport = stoi(wide_to_narrow(menudata.port));
|
||||
address = menudata.address;
|
||||
int newport = stoi(menudata.port);
|
||||
if(newport != 0)
|
||||
port = newport;
|
||||
|
||||
simple_singleplayer_mode = menudata.simple_singleplayer_mode;
|
||||
|
||||
// Save settings
|
||||
g_settings->setS32("selected_mainmenu_tab", menudata.selected_tab);
|
||||
g_settings->setS32("selected_serverlist", menudata.selected_serverlist);
|
||||
g_settings->set("selected_mainmenu_game", menudata.selected_game);
|
||||
g_settings->set("new_style_leaves", itos(menudata.fancy_trees));
|
||||
g_settings->set("smooth_lighting", itos(menudata.smooth_lighting));
|
||||
g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d));
|
||||
g_settings->set("opaque_water", itos(menudata.opaque_water));
|
||||
|
||||
g_settings->set("mip_map", itos(menudata.mip_map));
|
||||
g_settings->set("anisotropic_filter", itos(menudata.anisotropic_filter));
|
||||
g_settings->set("bilinear_filter", itos(menudata.bilinear_filter));
|
||||
g_settings->set("trilinear_filter", itos(menudata.trilinear_filter));
|
||||
|
||||
g_settings->setS32("enable_shaders", menudata.enable_shaders);
|
||||
g_settings->set("preload_item_visuals", itos(menudata.preload_item_visuals));
|
||||
g_settings->set("enable_particles", itos(menudata.enable_particles));
|
||||
g_settings->set("liquid_finite", itos(menudata.liquid_finite));
|
||||
|
||||
g_settings->set("creative_mode", itos(menudata.creative_mode));
|
||||
g_settings->set("enable_damage", itos(menudata.enable_damage));
|
||||
g_settings->set("server_announce", itos(menudata.enable_public));
|
||||
g_settings->set("name", playername);
|
||||
g_settings->set("address", address);
|
||||
g_settings->set("port", itos(port));
|
||||
if(menudata.selected_world != -1)
|
||||
|
||||
if((menudata.selected_world >= 0) &&
|
||||
(menudata.selected_world < worldspecs.size()))
|
||||
g_settings->set("selected_world_path",
|
||||
worldspecs[menudata.selected_world].path);
|
||||
|
||||
|
@ -2010,8 +1660,8 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
ServerListSpec server;
|
||||
server["name"] = menudata.servername;
|
||||
server["address"] = wide_to_narrow(menudata.address);
|
||||
server["port"] = wide_to_narrow(menudata.port);
|
||||
server["address"] = menudata.address;
|
||||
server["port"] = menudata.port;
|
||||
server["description"] = menudata.serverdescription;
|
||||
ServerList::insert(server);
|
||||
}
|
||||
|
@ -2022,30 +1672,7 @@ int main(int argc, char *argv[])
|
|||
infostream<<"Selected world: "<<worldspec.name
|
||||
<<" ["<<worldspec.path<<"]"<<std::endl;
|
||||
}
|
||||
|
||||
// Only refresh if so requested
|
||||
if(menudata.only_refresh){
|
||||
infostream<<"Refreshing menu"<<std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create new world if requested
|
||||
if(menudata.create_world_name != L"")
|
||||
{
|
||||
std::string path = porting::path_user + DIR_DELIM
|
||||
"worlds" + DIR_DELIM
|
||||
+ wide_to_narrow(menudata.create_world_name);
|
||||
// Create world if it doesn't exist
|
||||
if(!initializeWorld(path, menudata.create_world_gameid)){
|
||||
error_message = wgettext("Failed to initialize world");
|
||||
errorstream<<wide_to_narrow(error_message)<<std::endl;
|
||||
continue;
|
||||
}
|
||||
g_settings->set("selected_world_path", path);
|
||||
g_settings->set("selected_mainmenu_game", menudata.create_world_gameid);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If local game
|
||||
if(current_address == "")
|
||||
{
|
||||
|
@ -2085,8 +1712,10 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
// Break out of menu-game loop to shut down cleanly
|
||||
if(device->run() == false || kill == true)
|
||||
if(device->run() == false || kill == true) {
|
||||
g_settings->updateConfigFile(configpath.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
Run game
|
||||
|
@ -2138,11 +1767,11 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
}
|
||||
} // Menu-game loop
|
||||
|
||||
|
||||
|
||||
|
||||
g_menuclouds->drop();
|
||||
g_menucloudsmgr->drop();
|
||||
|
||||
|
||||
delete input;
|
||||
|
||||
/*
|
||||
|
|
13
src/map.cpp
13
src/map.cpp
|
@ -3237,17 +3237,18 @@ v2s16 ServerMap::getSectorPos(std::string dirname)
|
|||
{
|
||||
unsigned int x, y;
|
||||
int r;
|
||||
size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
|
||||
assert(spos != std::string::npos);
|
||||
if(dirname.size() - spos == 8)
|
||||
std::string component;
|
||||
fs::RemoveLastPathComponent(dirname, &component, 1);
|
||||
if(component.size() == 8)
|
||||
{
|
||||
// Old layout
|
||||
r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
|
||||
r = sscanf(component.c_str(), "%4x%4x", &x, &y);
|
||||
}
|
||||
else if(dirname.size() - spos == 3)
|
||||
else if(component.size() == 3)
|
||||
{
|
||||
// New layout
|
||||
r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
|
||||
fs::RemoveLastPathComponent(dirname, &component, 2);
|
||||
r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
|
||||
// Sign-extend the 12 bit values up to 16 bits...
|
||||
if(x&0x800) x|=0xF000;
|
||||
if(y&0x800) y|=0xF000;
|
||||
|
|
28
src/mods.cpp
28
src/mods.cpp
|
@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
*/
|
||||
|
||||
#include "mods.h"
|
||||
#include "main.h"
|
||||
#include "filesys.h"
|
||||
#include "strfnd.h"
|
||||
#include "log.h"
|
||||
|
@ -25,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "settings.h"
|
||||
#include "strfnd.h"
|
||||
#include <cctype>
|
||||
#include "convert_json.h"
|
||||
|
||||
static bool parseDependsLine(std::istream &is,
|
||||
std::string &dep, std::set<char> &symbols)
|
||||
|
@ -389,3 +391,29 @@ void ModConfiguration::resolveDependencies()
|
|||
// Step 4: write back list of unsatisfied mods
|
||||
m_unsatisfied_mods.assign(unsatisfied.begin(), unsatisfied.end());
|
||||
}
|
||||
|
||||
#if USE_CURL
|
||||
Json::Value getModstoreUrl(std::string url)
|
||||
{
|
||||
struct curl_slist *chunk = NULL;
|
||||
|
||||
bool special_http_header = true;
|
||||
|
||||
try{
|
||||
special_http_header = g_settings->getBool("modstore_disable_special_http_header");
|
||||
}
|
||||
catch(SettingNotFoundException &e) {
|
||||
}
|
||||
|
||||
if (special_http_header)
|
||||
chunk = curl_slist_append(chunk, "Accept: application/vnd.minetest.mmdb-v1+json");
|
||||
|
||||
Json::Value retval = fetchJsonValue(url,chunk);
|
||||
|
||||
if (chunk != NULL)
|
||||
curl_slist_free_all(chunk);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
68
src/mods.h
68
src/mods.h
|
@ -29,6 +29,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include <map>
|
||||
#include <exception>
|
||||
#include <list>
|
||||
#include "json/json.h"
|
||||
#include "config.h"
|
||||
|
||||
#if USE_CURL
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
#define MODNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_"
|
||||
|
||||
|
@ -154,4 +160,66 @@ private:
|
|||
|
||||
};
|
||||
|
||||
#if USE_CURL
|
||||
Json::Value getModstoreUrl(std::string url);
|
||||
#else
|
||||
inline Json::Value getModstoreUrl(std::string url) {
|
||||
return Json::Value();
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ModLicenseInfo {
|
||||
int id;
|
||||
std::string shortinfo;
|
||||
std::string url;
|
||||
};
|
||||
|
||||
struct ModAuthorInfo {
|
||||
int id;
|
||||
std::string username;
|
||||
};
|
||||
|
||||
struct ModStoreMod {
|
||||
int id;
|
||||
std::string title;
|
||||
std::string basename;
|
||||
ModAuthorInfo author;
|
||||
float rating;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
struct ModStoreCategoryInfo {
|
||||
int id;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct ModStoreVersionEntry {
|
||||
int id;
|
||||
std::string date;
|
||||
std::string file;
|
||||
bool approved;
|
||||
//ugly version number
|
||||
int mtversion;
|
||||
};
|
||||
|
||||
struct ModStoreModDetails {
|
||||
/* version_set?? */
|
||||
std::vector<ModStoreCategoryInfo> categories;
|
||||
ModAuthorInfo author;
|
||||
ModLicenseInfo license;
|
||||
int id;
|
||||
std::string title;
|
||||
std::string basename;
|
||||
std::string description;
|
||||
std::string repository;
|
||||
float rating;
|
||||
std::vector<std::string> depends;
|
||||
std::vector<std::string> softdeps;
|
||||
|
||||
std::string download_url;
|
||||
std::string screenshot_url;
|
||||
std::vector<ModStoreVersionEntry> versions;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "porting.h"
|
||||
#include "log.h"
|
||||
#include "json/json.h"
|
||||
#include "convert_json.h"
|
||||
#if USE_CURL
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
@ -68,35 +69,22 @@ std::vector<ServerListSpec> getLocal()
|
|||
|
||||
|
||||
#if USE_CURL
|
||||
|
||||
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
|
||||
std::vector<ServerListSpec> getOnline()
|
||||
{
|
||||
std::string liststring;
|
||||
CURL *curl;
|
||||
Json::Value root = fetchJsonValue((g_settings->get("serverlist_url")+"/list").c_str(),0);
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (curl)
|
||||
{
|
||||
CURLcode res;
|
||||
std::vector<ServerListSpec> serverlist;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, (g_settings->get("serverlist_url")+"/list").c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ServerList::WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &liststring);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK)
|
||||
errorstream<<"Serverlist at url "<<g_settings->get("serverlist_url")<<" not found (internet connection?)"<<std::endl;
|
||||
curl_easy_cleanup(curl);
|
||||
if (root.isArray()) {
|
||||
for (unsigned int i = 0; i < root.size(); i++)
|
||||
{
|
||||
if (root[i].isObject()) {
|
||||
serverlist.push_back(root[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ServerList::deSerializeJson(liststring);
|
||||
|
||||
return serverlist;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -189,30 +177,6 @@ std::string serialize(std::vector<ServerListSpec> serverlist)
|
|||
return liststring;
|
||||
}
|
||||
|
||||
std::vector<ServerListSpec> deSerializeJson(std::string liststring)
|
||||
{
|
||||
std::vector<ServerListSpec> serverlist;
|
||||
Json::Value root;
|
||||
Json::Reader reader;
|
||||
std::istringstream stream(liststring);
|
||||
if (!liststring.size()) {
|
||||
return serverlist;
|
||||
}
|
||||
if (!reader.parse( stream, root ) )
|
||||
{
|
||||
errorstream << "Failed to parse server list " << reader.getFormattedErrorMessages();
|
||||
return serverlist;
|
||||
}
|
||||
if (root["list"].isArray())
|
||||
for (unsigned int i = 0; i < root["list"].size(); i++)
|
||||
{
|
||||
if (root["list"][i].isObject()) {
|
||||
serverlist.push_back(root["list"][i]);
|
||||
}
|
||||
}
|
||||
return serverlist;
|
||||
}
|
||||
|
||||
std::string serializeJson(std::vector<ServerListSpec> serverlist)
|
||||
{
|
||||
Json::Value root;
|
||||
|
|
208
src/test.cpp
208
src/test.cpp
|
@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "settings.h"
|
||||
#include "log.h"
|
||||
#include "util/string.h"
|
||||
#include "filesys.h"
|
||||
#include "voxelalgorithms.h"
|
||||
#include "inventory.h"
|
||||
#include "util/numeric.h"
|
||||
|
@ -171,6 +172,212 @@ struct TestUtilities: public TestBase
|
|||
}
|
||||
};
|
||||
|
||||
struct TestPath: public TestBase
|
||||
{
|
||||
// adjusts a POSIX path to system-specific conventions
|
||||
// -> changes '/' to DIR_DELIM
|
||||
// -> absolute paths start with "C:\\" on windows
|
||||
std::string p(std::string path)
|
||||
{
|
||||
for(size_t i = 0; i < path.size(); ++i){
|
||||
if(path[i] == '/'){
|
||||
path.replace(i, 1, DIR_DELIM);
|
||||
i += std::string(DIR_DELIM).size() - 1; // generally a no-op
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if(path[0] == '\\')
|
||||
path = "C:" + path;
|
||||
#endif
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
std::string path, result, removed;
|
||||
|
||||
/*
|
||||
Test fs::IsDirDelimiter
|
||||
*/
|
||||
UASSERT(fs::IsDirDelimiter('/') == true);
|
||||
UASSERT(fs::IsDirDelimiter('A') == false);
|
||||
UASSERT(fs::IsDirDelimiter(0) == false);
|
||||
#ifdef _WIN32
|
||||
UASSERT(fs::IsDirDelimiter('\\') == true);
|
||||
#else
|
||||
UASSERT(fs::IsDirDelimiter('\\') == false);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Test fs::PathStartsWith
|
||||
*/
|
||||
{
|
||||
const int numpaths = 12;
|
||||
std::string paths[numpaths] = {
|
||||
"",
|
||||
p("/"),
|
||||
p("/home/user/minetest"),
|
||||
p("/home/user/minetest/bin"),
|
||||
p("/home/user/.minetest"),
|
||||
p("/tmp/dir/file"),
|
||||
p("/tmp/file/"),
|
||||
p("/tmP/file"),
|
||||
p("/tmp"),
|
||||
p("/tmp/dir"),
|
||||
p("/home/user2/minetest/worlds"),
|
||||
p("/home/user2/minetest/world"),
|
||||
};
|
||||
/*
|
||||
expected fs::PathStartsWith results
|
||||
0 = returns false
|
||||
1 = returns true
|
||||
2 = returns false on windows, false elsewhere
|
||||
3 = returns true on windows, true elsewhere
|
||||
4 = returns true if and only if
|
||||
FILESYS_CASE_INSENSITIVE is true
|
||||
*/
|
||||
int expected_results[numpaths][numpaths] = {
|
||||
{1,2,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,0,0,0,0,0,0,0,0},
|
||||
{1,1,0,0,1,0,0,0,0,0,0,0},
|
||||
{1,1,0,0,0,1,0,0,1,1,0,0},
|
||||
{1,1,0,0,0,0,1,4,1,0,0,0},
|
||||
{1,1,0,0,0,0,4,1,4,0,0,0},
|
||||
{1,1,0,0,0,0,0,0,1,0,0,0},
|
||||
{1,1,0,0,0,0,0,0,1,1,0,0},
|
||||
{1,1,0,0,0,0,0,0,0,0,1,0},
|
||||
{1,1,0,0,0,0,0,0,0,0,0,1},
|
||||
};
|
||||
|
||||
for (int i = 0; i < numpaths; i++)
|
||||
for (int j = 0; j < numpaths; j++){
|
||||
/*verbosestream<<"testing fs::PathStartsWith(\""
|
||||
<<paths[i]<<"\", \""
|
||||
<<paths[j]<<"\")"<<std::endl;*/
|
||||
bool starts = fs::PathStartsWith(paths[i], paths[j]);
|
||||
int expected = expected_results[i][j];
|
||||
if(expected == 0){
|
||||
UASSERT(starts == false);
|
||||
}
|
||||
else if(expected == 1){
|
||||
UASSERT(starts == true);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
else if(expected == 2){
|
||||
UASSERT(starts == false);
|
||||
}
|
||||
else if(expected == 3){
|
||||
UASSERT(starts == true);
|
||||
}
|
||||
#else
|
||||
else if(expected == 2){
|
||||
UASSERT(starts == true);
|
||||
}
|
||||
else if(expected == 3){
|
||||
UASSERT(starts == false);
|
||||
}
|
||||
#endif
|
||||
else if(expected == 4){
|
||||
UASSERT(starts == (bool)FILESYS_CASE_INSENSITIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Test fs::RemoveLastPathComponent
|
||||
*/
|
||||
UASSERT(fs::RemoveLastPathComponent("") == "");
|
||||
path = p("/home/user/minetest/bin/..//worlds/world1");
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 0);
|
||||
UASSERT(result == path);
|
||||
UASSERT(removed == "");
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 1);
|
||||
UASSERT(result == p("/home/user/minetest/bin/..//worlds"));
|
||||
UASSERT(removed == p("world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 2);
|
||||
UASSERT(result == p("/home/user/minetest/bin/.."));
|
||||
UASSERT(removed == p("worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 3);
|
||||
UASSERT(result == p("/home/user/minetest/bin"));
|
||||
UASSERT(removed == p("../worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 4);
|
||||
UASSERT(result == p("/home/user/minetest"));
|
||||
UASSERT(removed == p("bin/../worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 5);
|
||||
UASSERT(result == p("/home/user"));
|
||||
UASSERT(removed == p("minetest/bin/../worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 6);
|
||||
UASSERT(result == p("/home"));
|
||||
UASSERT(removed == p("user/minetest/bin/../worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 7);
|
||||
#ifdef _WIN32
|
||||
UASSERT(result == "C:");
|
||||
#else
|
||||
UASSERT(result == "");
|
||||
#endif
|
||||
UASSERT(removed == p("home/user/minetest/bin/../worlds/world1"));
|
||||
|
||||
/*
|
||||
Now repeat the test with a trailing delimiter
|
||||
*/
|
||||
path = p("/home/user/minetest/bin/..//worlds/world1/");
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 0);
|
||||
UASSERT(result == path);
|
||||
UASSERT(removed == "");
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 1);
|
||||
UASSERT(result == p("/home/user/minetest/bin/..//worlds"));
|
||||
UASSERT(removed == p("world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 2);
|
||||
UASSERT(result == p("/home/user/minetest/bin/.."));
|
||||
UASSERT(removed == p("worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 3);
|
||||
UASSERT(result == p("/home/user/minetest/bin"));
|
||||
UASSERT(removed == p("../worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 4);
|
||||
UASSERT(result == p("/home/user/minetest"));
|
||||
UASSERT(removed == p("bin/../worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 5);
|
||||
UASSERT(result == p("/home/user"));
|
||||
UASSERT(removed == p("minetest/bin/../worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 6);
|
||||
UASSERT(result == p("/home"));
|
||||
UASSERT(removed == p("user/minetest/bin/../worlds/world1"));
|
||||
result = fs::RemoveLastPathComponent(path, &removed, 7);
|
||||
#ifdef _WIN32
|
||||
UASSERT(result == "C:");
|
||||
#else
|
||||
UASSERT(result == "");
|
||||
#endif
|
||||
UASSERT(removed == p("home/user/minetest/bin/../worlds/world1"));
|
||||
|
||||
/*
|
||||
Test fs::RemoveRelativePathComponent
|
||||
*/
|
||||
path = p("/home/user/minetest/bin");
|
||||
result = fs::RemoveRelativePathComponents(path);
|
||||
UASSERT(result == path);
|
||||
path = p("/home/user/minetest/bin/../worlds/world1");
|
||||
result = fs::RemoveRelativePathComponents(path);
|
||||
UASSERT(result == p("/home/user/minetest/worlds/world1"));
|
||||
path = p("/home/user/minetest/bin/../worlds/world1/");
|
||||
result = fs::RemoveRelativePathComponents(path);
|
||||
UASSERT(result == p("/home/user/minetest/worlds/world1"));
|
||||
path = p(".");
|
||||
result = fs::RemoveRelativePathComponents(path);
|
||||
UASSERT(result == "");
|
||||
path = p("./subdir/../..");
|
||||
result = fs::RemoveRelativePathComponents(path);
|
||||
UASSERT(result == "");
|
||||
path = p("/a/b/c/.././../d/../e/f/g/../h/i/j/../../../..");
|
||||
result = fs::RemoveRelativePathComponents(path);
|
||||
UASSERT(result == p("/a/e"));
|
||||
}
|
||||
};
|
||||
|
||||
struct TestSettings: public TestBase
|
||||
{
|
||||
void Run()
|
||||
|
@ -1785,6 +1992,7 @@ void run_tests()
|
|||
|
||||
infostream<<"run_tests() started"<<std::endl;
|
||||
TEST(TestUtilities);
|
||||
TEST(TestPath);
|
||||
TEST(TestSettings);
|
||||
TEST(TestCompress);
|
||||
TEST(TestSerialization);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue