Get the game to compile, at least
- Scenario and PC editors still don't link - Copy files stage set up in the Common project - Scenario and PC editors now placed in Scenario Editor subfolder in the output directory - Disabled some totally useless warnings - "About" menuitem now considered to belong to "Help" menu (even on Mac code) as far as the handlers are concerned - Dialog string filter is now a function instead of a custom iterator - Modal session now requires parent window as additional parameter - Preferences and menus work! Cursors still need some work. - Since Visual Studio has no way of showing program output that I can find, stdout and stderr are now redirected to a file.
This commit is contained in:
@@ -10,6 +10,9 @@
|
||||
#define BOE_CURSORS_H
|
||||
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
enum cursor_type {
|
||||
wand_curs = 0,
|
||||
@@ -43,7 +46,7 @@ enum cursor_type {
|
||||
class Cursor {
|
||||
void* ptr;
|
||||
public:
|
||||
Cursor(std::string imgPath, float hotSpotX, float hotSpotY);
|
||||
Cursor(fs::path imgPath, float hotSpotX, float hotSpotY);
|
||||
~Cursor();
|
||||
void apply();
|
||||
};
|
||||
|
@@ -11,23 +11,6 @@
|
||||
#include <string>
|
||||
#include "restypes.hpp"
|
||||
|
||||
cursor_type current_cursor = sword_curs;
|
||||
cursor_type arrow_curs[3][3] = {
|
||||
{NW_curs, N_curs, NE_curs},
|
||||
{W_curs,wait_curs,E_curs},
|
||||
{SW_curs, S_curs, SE_curs},
|
||||
};
|
||||
|
||||
const std::string cursors[25] = {
|
||||
"wand", "eyedropper", "brush", "spraycan",
|
||||
"eraser", "topleft", "bottomright", "hand",
|
||||
"NW", "N", "NE",
|
||||
"W", "wait", "E",
|
||||
"SW", "S", "SE",
|
||||
"sword", "boot", "drop", "target",
|
||||
"talk", "key", "look", "watch",
|
||||
};
|
||||
|
||||
static NSImage* imageFromURL(CFURLRef url){
|
||||
CGImageSourceRef imageSource = CGImageSourceCreateWithURL(url, NULL);
|
||||
CGImageRef theImage = nil;
|
||||
|
141
src/tools/cursors.win.cpp
Normal file
141
src/tools/cursors.win.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
|
||||
#include "cursors.h"
|
||||
#include <Windows.h>
|
||||
#include <exception>
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include "restypes.hpp"
|
||||
|
||||
extern cursor_type current_cursor;
|
||||
extern sf::RenderWindow mainPtr;
|
||||
|
||||
const std::string cursors[25] = {
|
||||
"wand", "eyedropper", "brush", "spraycan",
|
||||
"eraser", "topleft", "bottomright", "hand",
|
||||
"NW", "N", "NE",
|
||||
"W", "wait", "E",
|
||||
"SW", "S", "SE",
|
||||
"sword", "boot", "drop", "target",
|
||||
"talk", "key", "look", "watch",
|
||||
};
|
||||
|
||||
static const COLORREF clrMagenta = RGB(255, 0, 255);
|
||||
|
||||
// This function adapted from <http://web.archive.org/web/20130502044728/http://marknelson.us/2002/07/01/rendering-transparent-gifs-revisited/>
|
||||
// It loads an image from a file and replaces transparency with magenta.
|
||||
// This is probably undesirable in the general case, but since we only expect transparent GIFs, it should work out.
|
||||
HBITMAP LoadPicture(std::string filename) {
|
||||
sf::Image gif;
|
||||
gif.loadFromFile(filename);
|
||||
HDC dc = CreateCompatibleDC(NULL);
|
||||
HBITMAP bmp = CreateCompatibleBitmap(dc, gif.getSize().x, gif.getSize().y);
|
||||
SelectObject(dc, &bmp);
|
||||
// Not exactly efficient, but it gets the job done.
|
||||
for(int x = 0; x < gif.getSize().x; x++) {
|
||||
for(int y = 0; y < gif.getSize().y; y++) {
|
||||
sf::Color clr = gif.getPixel(x, y);
|
||||
if(clr == sf::Color::Transparent)
|
||||
SetPixel(dc, x, y, clrMagenta);
|
||||
else SetPixel(dc, x, y, RGB(clr.r, clr.g, clr.b));
|
||||
}
|
||||
}
|
||||
DeleteDC(dc);
|
||||
return bmp;
|
||||
}
|
||||
|
||||
// This function taken from <http://www.codeproject.com/Articles/5220/Creating-a-color-cursor-from-a-bitmap>
|
||||
void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, HBITMAP& hAndMaskBitmap, HBITMAP& hXorMaskBitmap) {
|
||||
HDC hDC = GetDC(NULL);
|
||||
HDC hMainDC = CreateCompatibleDC(hDC);
|
||||
HDC hAndMaskDC = CreateCompatibleDC(hDC);
|
||||
HDC hXorMaskDC = CreateCompatibleDC(hDC);
|
||||
|
||||
//Get the dimensions of the source bitmap
|
||||
BITMAP bm;
|
||||
GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
|
||||
|
||||
hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
|
||||
hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
|
||||
|
||||
//Select the bitmaps to DC
|
||||
HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
|
||||
HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
|
||||
HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
|
||||
|
||||
//Scan each pixel of the souce bitmap and create the masks
|
||||
COLORREF MainBitPixel;
|
||||
for(int x = 0; x<bm.bmWidth; ++x) {
|
||||
for(int y = 0; y<bm.bmHeight; ++y) {
|
||||
MainBitPixel = GetPixel(hMainDC, x, y);
|
||||
if(MainBitPixel == clrTransparent) {
|
||||
SetPixel(hAndMaskDC, x, y, RGB(255, 255, 255));
|
||||
SetPixel(hXorMaskDC, x, y, RGB(0, 0, 0));
|
||||
} else {
|
||||
SetPixel(hAndMaskDC, x, y, RGB(0, 0, 0));
|
||||
SetPixel(hXorMaskDC, x, y, MainBitPixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SelectObject(hMainDC, hOldMainBitmap);
|
||||
SelectObject(hAndMaskDC, hOldAndMaskBitmap);
|
||||
SelectObject(hXorMaskDC, hOldXorMaskBitmap);
|
||||
|
||||
DeleteDC(hXorMaskDC);
|
||||
DeleteDC(hAndMaskDC);
|
||||
DeleteDC(hMainDC);
|
||||
|
||||
ReleaseDC(NULL, hDC);
|
||||
}
|
||||
|
||||
Cursor::Cursor(fs::path imgPath, float hotSpotX, float hotSpotY) {
|
||||
HBITMAP cursorImage = LoadPicture(imgPath.string()), cursorAnd, cursorXor;
|
||||
if(cursorImage == NULL) {
|
||||
std::string error = "Error loading cursor from " + imgPath.string();
|
||||
throw std::exception(error.c_str());
|
||||
}
|
||||
GetMaskBitmaps(cursorImage, clrMagenta, cursorAnd, cursorXor);
|
||||
|
||||
ICONINFO iconinfo = {0};
|
||||
iconinfo.fIcon = FALSE;
|
||||
iconinfo.xHotspot = hotSpotX;
|
||||
iconinfo.yHotspot = hotSpotY;
|
||||
iconinfo.hbmMask = cursorAnd;
|
||||
iconinfo.hbmColor = cursorXor;
|
||||
|
||||
HCURSOR hCursor = CreateIconIndirect(&iconinfo);
|
||||
ptr = &hCursor;
|
||||
DeleteObject(cursorImage);
|
||||
DeleteObject(cursorAnd);
|
||||
DeleteObject(cursorXor);
|
||||
}
|
||||
|
||||
Cursor::~Cursor() {
|
||||
HCURSOR* curs = (HCURSOR*)ptr;
|
||||
DestroyIcon(*curs);
|
||||
}
|
||||
|
||||
void Cursor::apply() {
|
||||
HCURSOR* curs = (HCURSOR*)ptr;
|
||||
SetCursor(*curs);
|
||||
// TODO: This ensures the cursor stays set when the mouse moves. Is it necessary, though?
|
||||
SetClassLong(mainPtr.getSystemHandle(), GCL_HCURSOR, (LONG)(*curs));
|
||||
}
|
||||
|
||||
void obscureCursor() {
|
||||
SetCursor(NULL);
|
||||
}
|
||||
|
||||
void set_cursor(cursor_type which_c) {
|
||||
if(which_c != watch_curs)
|
||||
current_cursor = which_c;
|
||||
if(which_c == text_curs) {
|
||||
SetCursor(LoadCursor(NULL, IDC_IBEAM));
|
||||
} else {
|
||||
Cursor& curs = *ResMgr::get<CursorRsrc>(cursors[which_c]);
|
||||
curs.apply();
|
||||
}
|
||||
}
|
||||
|
||||
void restore_cursor() {
|
||||
set_cursor(current_cursor);
|
||||
}
|
@@ -22,6 +22,7 @@
|
||||
#include "porting.h"
|
||||
#include "restypes.hpp"
|
||||
#include "tarball.hpp"
|
||||
#include "cursors.h"
|
||||
|
||||
bool cur_scen_is_mac = true, mac_is_intel;
|
||||
extern sf::Texture items_gworld,tiny_obj_gworld,fields_gworld,roads_gworld,boom_gworld,missiles_gworld;
|
||||
@@ -43,6 +44,14 @@ static bool load_town_talk(fs::path town_base, short which_town, cSpeech& the_ta
|
||||
static bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there, bool must_port);
|
||||
static bool load_party_v2(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there);
|
||||
|
||||
// Cursors included here so that they needn't be unnecessarily duplicated in platform-specific files
|
||||
cursor_type current_cursor = sword_curs;
|
||||
cursor_type arrow_curs[3][3] = {
|
||||
{NW_curs, N_curs, NE_curs},
|
||||
{W_curs, wait_curs, E_curs},
|
||||
{SW_curs, S_curs, SE_curs},
|
||||
};
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
void init_directories(const char* exec_path) {
|
||||
@@ -54,7 +63,7 @@ void init_directories(const char* exec_path) {
|
||||
#endif
|
||||
progDir = progDir.parent_path();
|
||||
if(progDir.filename() == "Scenario Editor") progDir = progDir.parent_path();
|
||||
std::cout << progDir << '\n';
|
||||
std::cout << progDir << std::endl;
|
||||
// Initialize the resource manager paths
|
||||
ResMgr::pushPath<ImageRsrc>(progDir/"Scenario Editor"/"graphics.exd"/"mac");
|
||||
ResMgr::pushPath<CursorRsrc>(progDir/"Scenario Editor"/"graphics.exd"/"mac"/"cursors");
|
||||
|
@@ -68,7 +68,7 @@ void init_graph_tool(){
|
||||
fin.read(vbuf, size);
|
||||
|
||||
if(!maskShader.loadFromMemory(vbuf, fbuf)) {
|
||||
fprintf(stderr,"Error: Failed to load shaders from %s\nVertex:\n%s\nFragment:\n%s",shaderPath.c_str(),vbuf,fbuf);
|
||||
fprintf(stderr,"Error: Failed to load shaders from %s\nVertex:\n%s\nFragment:\n%s",shaderPath.string().c_str(),vbuf,fbuf);
|
||||
}
|
||||
delete[] fbuf;
|
||||
delete[] vbuf;
|
||||
|
133
src/tools/prefs.win.cpp
Normal file
133
src/tools/prefs.win.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
#include "prefs.hpp"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
std::map<std::string,boost::any> prefs;
|
||||
using iarray = std::vector<int>;
|
||||
static bool prefsLoaded = false, prefsDirty = false;
|
||||
|
||||
void set_pref(std::string keypath, bool value) {
|
||||
prefsDirty = true;
|
||||
prefs[keypath] = value;
|
||||
}
|
||||
|
||||
bool get_bool_pref(std::string keypath, bool fallback) {
|
||||
if(prefs.find(keypath) == prefs.end()) return fallback;
|
||||
if(prefs[keypath].type() == typeid(bool)) return boost::any_cast<bool>(prefs[keypath]);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
void set_pref(std::string keypath, int value) {
|
||||
prefsDirty = true;
|
||||
prefs[keypath] = value;
|
||||
}
|
||||
|
||||
int get_int_pref(std::string keypath, int fallback) {
|
||||
if(prefs.find(keypath) == prefs.end()) return fallback;
|
||||
if(prefs[keypath].type() == typeid(int)) return boost::any_cast<int>(prefs[keypath]);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
void append_iarray_pref(std::string keypath, int value) {
|
||||
prefsDirty = true;
|
||||
if(prefs.find(keypath) == prefs.end() || prefs[keypath].type() != typeid(iarray))
|
||||
prefs[keypath] = iarray{value};
|
||||
else {
|
||||
iarray& arr = boost::any_cast<iarray>(prefs[keypath]);
|
||||
arr.push_back(value);
|
||||
prefs[keypath] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> get_iarray_pref(std::string keypath) {
|
||||
if(prefs.find(keypath) == prefs.end()) return {};
|
||||
if(prefs[keypath].type() == typeid(iarray)) return boost::any_cast<iarray>(prefs[keypath]);
|
||||
return {};
|
||||
}
|
||||
|
||||
void clear_pref(std::string keypath) {
|
||||
prefsDirty = true;
|
||||
auto iter = prefs.find(keypath);
|
||||
if(iter != prefs.end()) prefs.erase(iter);
|
||||
}
|
||||
|
||||
static bool save_prefs(fs::path fpath) {
|
||||
if(!prefsDirty) return true;
|
||||
fs::create_directories(fpath.parent_path());
|
||||
std::ofstream fout(fpath.string().c_str());
|
||||
for(auto& kv : prefs) {
|
||||
if(kv.second.type() == typeid(iarray)) {
|
||||
iarray& arr = boost::any_cast<iarray>(kv.second);
|
||||
fout << kv.first << " = [";
|
||||
for(int i : arr) fout << i << ' ';
|
||||
fout.seekp(-1,std::ios::cur); // To overwrite the final space written in the loop
|
||||
fout << ']' << std::endl;
|
||||
} else if(kv.second.type() == typeid(bool))
|
||||
fout << kv.first << " = " << std::boolalpha << boost::any_cast<bool>(kv.second) << std::endl;
|
||||
else if(kv.second.type() == typeid(int))
|
||||
fout << kv.first << " = " << boost::any_cast<int>(kv.second) << std::endl;
|
||||
else printf("Warning: Unknown preference value type, skipping...\n");
|
||||
if(!fout) {
|
||||
perror("Error writing preferences");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
prefsDirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load_prefs(fs::path fpath) {
|
||||
prefsDirty = false;
|
||||
std::map<std::string,boost::any> temp_prefs;
|
||||
std::ifstream fin(fpath.string().c_str());
|
||||
std::string line;
|
||||
while(std::getline(fin, line)) {
|
||||
if(!fin) {
|
||||
perror("Error reading preferences");
|
||||
return false;
|
||||
}
|
||||
if(line[0] == '#') continue;
|
||||
int eq = line.find_first_of('=');
|
||||
if(eq == std::string::npos) {
|
||||
printf("Error reading preferences: line is not a comment and lacks an = sign:\n\t%s\n", line.c_str());
|
||||
return false;
|
||||
}
|
||||
int key_end = line.find_last_not_of(' ', eq - 1), val_beg = line.find_first_not_of(' ', eq + 1);
|
||||
if(val_beg == std::string::npos) {
|
||||
printf("Error reading preferences: line is missing value:\n\t%s\n", line.c_str());
|
||||
return false;
|
||||
}
|
||||
if(key_end == std::string::npos) {
|
||||
printf("Error reading preferences: line is missing key:\n\t%s\n", line.c_str());
|
||||
return false;
|
||||
}
|
||||
std::string key = line.substr(0, key_end + 1), val = line.substr(val_beg);
|
||||
if(val == "true") temp_prefs[key] = true;
|
||||
else if(val == "false") temp_prefs[key] = false;
|
||||
else if(val[0] == '[') {
|
||||
int arr_end = val.find_first_of(']');
|
||||
std::istringstream arr_vals(val.substr(1, arr_end - 1));
|
||||
int i = 0;
|
||||
iarray vals;
|
||||
while(arr_vals >> i) vals.push_back(i);
|
||||
temp_prefs[key] = vals;
|
||||
} else temp_prefs[key] = boost::lexical_cast<int>(val);
|
||||
}
|
||||
prefs.swap(temp_prefs);
|
||||
return prefsLoaded = true;
|
||||
}
|
||||
|
||||
extern fs::path tempDir;
|
||||
bool sync_prefs() {
|
||||
fs::path prefsPath = tempDir.parent_path() / "bladesprefs.ini";
|
||||
if(prefsLoaded) return save_prefs(prefsPath);
|
||||
else return load_prefs(prefsPath);
|
||||
}
|
@@ -59,7 +59,7 @@ namespace ResMgr {
|
||||
std::stack<fs::path> tmpPaths = resPaths();
|
||||
while(!tmpPaths.empty()) {
|
||||
fs::path thisPath = tmpPaths.top()/path;
|
||||
printf("Testing %s...\n",thisPath.c_str());
|
||||
printf("Testing %s...\n",thisPath.string().c_str());
|
||||
if(fs::exists(thisPath)) {
|
||||
pathFound()[path] = tmpPaths.top();
|
||||
return thisPath;
|
||||
@@ -165,7 +165,7 @@ namespace ResMgr {
|
||||
/// @tparam type The type of resource the path applies to.
|
||||
/// @param path The path at which resources of this type may be found.
|
||||
template<typename type> void pushPath(fs::path path) {
|
||||
printf("Pushing path %s in %s...\n",path.c_str(),__FUNCTION__);
|
||||
printf("Pushing path %s in %s...\n",path.string().c_str(),__FUNCTION__);
|
||||
resPool<type>::resPaths().push(path);
|
||||
if(resPool<type>::resPaths().empty()) printf("A problem occurred.\n");
|
||||
}
|
||||
|
@@ -34,11 +34,15 @@ std::string get_clipboard();
|
||||
|
||||
void beep();
|
||||
|
||||
// Calculates how much of the window is occupied by the menubar
|
||||
int getMenubarHeight();
|
||||
|
||||
class ModalSession {
|
||||
void* session;
|
||||
sf::Window& parent;
|
||||
public:
|
||||
void pumpEvents();
|
||||
ModalSession(sf::Window& win);
|
||||
ModalSession(sf::Window& win, sf::Window& parent);
|
||||
~ModalSession();
|
||||
};
|
||||
|
||||
|
@@ -145,6 +145,11 @@ void beep() {
|
||||
NSBeep();
|
||||
}
|
||||
|
||||
int getMenubarHeight() {
|
||||
// Mac menubar isn't in the window, so we return 0 here.
|
||||
return 0;
|
||||
}
|
||||
|
||||
NSOpenPanel* dlg_get_scen;
|
||||
NSOpenPanel* dlg_get_game;
|
||||
NSSavePanel* dlg_put_scen;
|
||||
|
222
src/tools/winutil.win.cpp
Normal file
222
src/tools/winutil.win.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
|
||||
#include "winutil.h"
|
||||
#include <Windows.h>
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
|
||||
extern sf::RenderWindow mainPtr;
|
||||
OPENFILENAME getParty, getScen, putParty, putScen;
|
||||
|
||||
// TODO: I'm sure there's a better way to do this (maybe one that's keyboard layout agnostic)
|
||||
// The proper way would involve use of the TextEntered event
|
||||
char keyToChar(sf::Keyboard::Key key, bool isShift) {
|
||||
using kb = sf::Keyboard;
|
||||
switch(key) {
|
||||
case kb::A: return isShift ? 'A' : 'a';
|
||||
case kb::B: return isShift ? 'B' : 'b';
|
||||
case kb::C: return isShift ? 'C' : 'c';
|
||||
case kb::D: return isShift ? 'D' : 'd';
|
||||
case kb::E: return isShift ? 'E' : 'e';
|
||||
case kb::F: return isShift ? 'F' : 'f';
|
||||
case kb::G: return isShift ? 'G' : 'g';
|
||||
case kb::H: return isShift ? 'H' : 'h';
|
||||
case kb::I: return isShift ? 'I' : 'i';
|
||||
case kb::J: return isShift ? 'J' : 'j';
|
||||
case kb::K: return isShift ? 'K' : 'k';
|
||||
case kb::L: return isShift ? 'L' : 'l';
|
||||
case kb::M: return isShift ? 'M' : 'm';
|
||||
case kb::N: return isShift ? 'N' : 'n';
|
||||
case kb::O: return isShift ? 'O' : 'o';
|
||||
case kb::P: return isShift ? 'P' : 'p';
|
||||
case kb::Q: return isShift ? 'Q' : 'q';
|
||||
case kb::R: return isShift ? 'R' : 'r';
|
||||
case kb::S: return isShift ? 'S' : 's';
|
||||
case kb::T: return isShift ? 'T' : 't';
|
||||
case kb::U: return isShift ? 'U' : 'u';
|
||||
case kb::V: return isShift ? 'V' : 'v';
|
||||
case kb::W: return isShift ? 'W' : 'w';
|
||||
case kb::X: return isShift ? 'X' : 'x';
|
||||
case kb::Y: return isShift ? 'Y' : 'y';
|
||||
case kb::Z: return isShift ? 'Z' : 'z';
|
||||
case kb::Num1: return isShift ? '!' : '1';
|
||||
case kb::Num2: return isShift ? '@' : '2';
|
||||
case kb::Num3: return isShift ? '#' : '3';
|
||||
case kb::Num4: return isShift ? '$' : '4';
|
||||
case kb::Num5: return isShift ? '%' : '5';
|
||||
case kb::Num6: return isShift ? '^' : '6';
|
||||
case kb::Num7: return isShift ? '&' : '7';
|
||||
case kb::Num8: return isShift ? '*' : '8';
|
||||
case kb::Num9: return isShift ? '(' : '9';
|
||||
case kb::Num0: return isShift ? ')' : '0';
|
||||
case kb::Tilde: return isShift ? '~' : '`';
|
||||
case kb::Dash: return isShift ? '_' : '-';
|
||||
case kb::Equal: return isShift ? '+' : '=';
|
||||
case kb::LBracket: return isShift ? '{' : '[';
|
||||
case kb::RBracket: return isShift ? '}' : ']';
|
||||
case kb::SemiColon: return isShift ? ':' : ';';
|
||||
case kb::Quote: return isShift ? '"' : '\'';
|
||||
case kb::Comma: return isShift ? '<' : ',';
|
||||
case kb::Period: return isShift ? '>' : '.';
|
||||
case kb::Slash: return isShift ? '?' : '/';
|
||||
case kb::BackSlash: return isShift ? '|' : '\\';
|
||||
case kb::Tab: return '\t';
|
||||
case kb::Space: return ' ';
|
||||
case kb::Return: return '\n';
|
||||
case kb::BackSpace: return '\b';
|
||||
case kb::Delete: return '\x7f';
|
||||
case kb::Numpad0: return '0';
|
||||
case kb::Numpad1: return '1';
|
||||
case kb::Numpad2: return '2';
|
||||
case kb::Numpad3: return '3';
|
||||
case kb::Numpad4: return '4';
|
||||
case kb::Numpad5: return '5';
|
||||
case kb::Numpad6: return '6';
|
||||
case kb::Numpad7: return '7';
|
||||
case kb::Numpad8: return '8';
|
||||
case kb::Numpad9: return '9';
|
||||
// TODO: Should have Equal here, but SFML doesn't distinguish between normal and keybad equal :/
|
||||
// Ditto for the decimal point.
|
||||
case kb::Divide: return '/';
|
||||
case kb::Multiply: return '*';
|
||||
case kb::Subtract: return '-';
|
||||
case kb::Add: return '+';
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void makeFrontWindow(sf::Window& win) {
|
||||
HWND win_handle = win.getSystemHandle();
|
||||
BringWindowToTop(win_handle);
|
||||
}
|
||||
|
||||
void setWindowFloating(sf::Window& win, bool floating) {
|
||||
HWND win_handle = win.getSystemHandle();
|
||||
UINT flags = SWP_NOMOVE | SWP_NOSIZE;
|
||||
HWND newPos = floating ? HWND_TOPMOST : HWND_TOP;
|
||||
// The flags param specifies that these 0's are ignored.
|
||||
SetWindowPos(win_handle, newPos, 0, 0, 0, 0, flags);
|
||||
}
|
||||
|
||||
void init_fileio() {
|
||||
OPENFILENAME base_dlg;
|
||||
memset(&base_dlg, 0, sizeof(OPENFILENAME));
|
||||
// Common values
|
||||
base_dlg.lStructSize = sizeof(OPENFILENAME);
|
||||
base_dlg.hwndOwner = mainPtr.getSystemHandle();
|
||||
base_dlg.nFilterIndex = 1;
|
||||
base_dlg.Flags = OFN_DONTADDTORECENT | OFN_ENABLESIZING | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
|
||||
getParty = getScen = putParty = putScen = base_dlg;
|
||||
// Open saved game dialog
|
||||
getParty.lpstrFilter = LPCTSTR("Blades of Exile Saved Games\0*.exg\0Legacy Saved Games\0*.mac;*.boe;*.SAV\0");
|
||||
getParty.lpstrTitle = LPCTSTR("Load Game");
|
||||
getParty.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
|
||||
// Open scenario dialog
|
||||
getScen.lpstrFilter = LPCTSTR("Blades of Exile Scenarios\0*.boes\0Legacy or Unpacked Scenarios\0*.exs\0");
|
||||
getScen.lpstrTitle = LPCTSTR("Open Scenario");
|
||||
// Save game dialog
|
||||
putParty.lpstrFilter = LPCTSTR("Blades of Exile Saved Games\0*.exg\0");
|
||||
putParty.lpstrTitle = LPCTSTR("Save Game");
|
||||
putParty.Flags |= OFN_OVERWRITEPROMPT;
|
||||
// Save scenario dialog
|
||||
putScen.lpstrFilter = LPCTSTR("Blades of Exile Scenario\0*.boes\0");
|
||||
putScen.lpstrTitle = LPCTSTR("Save Scenario");
|
||||
}
|
||||
|
||||
static std::string runFileDlog(OPENFILENAME& dlg, const std::string& file, bool save) {
|
||||
size_t sz = std::max<size_t>(MAX_PATH, file.length()) + 1;
|
||||
char* path = new char[sz];
|
||||
std::copy(file.begin(), file.end(), path);
|
||||
std::fill(path + file.length(), path + sz, 0);
|
||||
|
||||
putParty.lpstrFile = path;
|
||||
putParty.nMaxFile = sz - 1;
|
||||
putParty.nFileOffset = file.find_last_of('\\');
|
||||
if(putParty.nFileOffset == std::string::npos)
|
||||
putParty.nFileOffset = 0;
|
||||
else putParty.nFileOffset++;
|
||||
putParty.nFileExtension = file.find_last_of('.');
|
||||
if(putParty.nFileExtension == std::string::npos)
|
||||
putParty.nFileExtension = 0;
|
||||
else putParty.nFileExtension++;
|
||||
|
||||
if(save) GetSaveFileName(&dlg);
|
||||
else GetOpenFileName(&dlg);
|
||||
|
||||
std::string result = putParty.lpstrFile;
|
||||
putParty.lpstrFile = NULL;
|
||||
putParty.nMaxFile = 0;
|
||||
delete path;
|
||||
putParty.Flags &= ~OFN_EXTENSIONDIFFERENT;
|
||||
putParty.Flags &= ~OFN_READONLY;
|
||||
return result;
|
||||
}
|
||||
|
||||
fs::path nav_get_party() {
|
||||
return runFileDlog(getParty, "Blades of Exile Save.exg", false);
|
||||
}
|
||||
|
||||
fs::path nav_put_party(fs::path def) {
|
||||
return runFileDlog(putParty, def.string(), true);
|
||||
}
|
||||
|
||||
fs::path nav_get_scenario() {
|
||||
return runFileDlog(getScen, "", false);
|
||||
}
|
||||
|
||||
fs::path nav_put_scenario(fs::path def) {
|
||||
return runFileDlog(putScen, def.string(), true);
|
||||
}
|
||||
|
||||
void set_clipboard(std::string text) {
|
||||
if(text.empty()) return;
|
||||
if(!OpenClipboard(mainPtr.getSystemHandle())) return;
|
||||
HGLOBAL hData = (char*) GlobalAlloc(GMEM_MOVEABLE, text.length() + 1);
|
||||
char* data = (char*)GlobalLock(hData);
|
||||
std::copy(text.c_str(), text.c_str() + text.length(), data);
|
||||
data[text.length()] = 0;
|
||||
GlobalUnlock(hData);
|
||||
EmptyClipboard();
|
||||
SetClipboardData(CF_TEXT, hData);
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
std::string get_clipboard() {
|
||||
if(!OpenClipboard(NULL)) return "";
|
||||
HGLOBAL hData = GetClipboardData(CF_TEXT);
|
||||
char* data = (char*) GlobalLock(hData);
|
||||
std::string contents(data);
|
||||
GlobalUnlock(hData);
|
||||
CloseClipboard();
|
||||
return contents;
|
||||
}
|
||||
|
||||
void beep() {
|
||||
MessageBeep(-1);
|
||||
}
|
||||
|
||||
// TODO: Implement modal session.
|
||||
// It seems that Windows doesn't have anything similar to the Mac modal session, so I might have to somehow simulate it myself.
|
||||
void ModalSession::pumpEvents() {
|
||||
HWND win_handle = (HWND)session;
|
||||
}
|
||||
|
||||
ModalSession::ModalSession(sf::Window& win, sf::Window& parent) : parent(parent) {
|
||||
session = win.getSystemHandle();
|
||||
EnableWindow(parent.getSystemHandle(), false);
|
||||
}
|
||||
|
||||
ModalSession::~ModalSession() {
|
||||
HWND win_handle = (HWND)session;
|
||||
EnableWindow(parent.getSystemHandle(), true);
|
||||
RedrawWindow(parent.getSystemHandle(), NULL, NULL, RDW_NOCHILDREN | RDW_UPDATENOW);
|
||||
}
|
||||
|
||||
void set_up_apple_events() {
|
||||
// TODO: Probably nothing to do here on Windows?
|
||||
// Basically what might possibly happen here is to set up stuff to handle dragging a file onto the application icon.
|
||||
// The Mac version also handles requests from the operating system for the application to quit.
|
||||
}
|
||||
|
||||
int getMenubarHeight() {
|
||||
return GetSystemMetrics(SM_CYMENU);
|
||||
}
|
Reference in New Issue
Block a user