(Scenario Editor is unaffected by this commit.) - Menubar converted to a .xib file - Don't include the Info.plist in "Copy Files" stage - Several more dialogs converted; as before, the source resources have had their resource name changed to the new filename - One more converted STR# has been included There were several functions in the PC Editor code that also existed in the BoE game code. I've moved these into the pc.editors.cpp file, so that there's only one copy of each. - display_alchemy() functions changed signatures - moved keyToChar() function into a common file (winutil) - Several constants and globals moved to pc.editors.cpp Supporting changes to dialog framework: - New formatting option to set the frame style; this because the PC editor uses a different frame style in some contexts - Added global default dialog background setting --> This was necessary to correctly set the default text colour --> Will also be needed for the scenario editor, which uses a different default background Other changes: - Add option to load_scenario to skip loading the strings - Fix for crash in soundtool in the event of initialization before playing the first sound
336 lines
9.2 KiB
C++
336 lines
9.2 KiB
C++
/*
|
|
* control.cpp
|
|
* BoE
|
|
*
|
|
* Created by Celtic Minstrel on 11/05/09.
|
|
*
|
|
*/
|
|
|
|
#include "control.h"
|
|
#include <sstream>
|
|
#include "dialog.h"
|
|
#include "soundtool.h"
|
|
#include "button.h"
|
|
#include "graphtool.h"
|
|
#include "restypes.hpp"
|
|
#include "mathutil.h"
|
|
|
|
extern bool play_sounds;
|
|
|
|
void cControl::setText(std::string l){
|
|
lbl = l;
|
|
}
|
|
|
|
std::string cControl::getText(){
|
|
return lbl;
|
|
}
|
|
|
|
RECT cControl::getBounds() {
|
|
return frame;
|
|
}
|
|
|
|
void cControl::setBounds(RECT newFrame) {
|
|
frame = newFrame;
|
|
}
|
|
|
|
void cControl::relocate(location to) {
|
|
frame.offset(to.x - frame.left, to.y - frame.top);
|
|
}
|
|
|
|
const char* xHandlerNotSupported::focusMsg = "This control cannot handle focus events.\n";
|
|
const char* xHandlerNotSupported::clickMsg = "This control cannot handle click events.\n";
|
|
|
|
xHandlerNotSupported::xHandlerNotSupported(bool isFocus){
|
|
this->isFocus = isFocus;
|
|
}
|
|
const char* xHandlerNotSupported::what(){
|
|
if(isFocus) return focusMsg;
|
|
else return clickMsg;
|
|
}
|
|
|
|
xUnsupportedProp::xUnsupportedProp(eFormat prop) throw(){
|
|
whichProp = prop;
|
|
msg = NULL;
|
|
}
|
|
xUnsupportedProp::~xUnsupportedProp() throw(){
|
|
if(msg != NULL) delete msg;
|
|
}
|
|
const char* xUnsupportedProp::what() throw(){
|
|
if(msg == NULL){
|
|
msg = new char[62];
|
|
std::string s;
|
|
switch(whichProp){
|
|
case TXT_FRAME:
|
|
s = "TXT_FRAME";
|
|
break;
|
|
case TXT_FRAMESTYLE:
|
|
s = "TXT_FRAMESTYLE";
|
|
break;
|
|
case TXT_FONT:
|
|
s = "TXT_FONT";
|
|
break;
|
|
case TXT_SIZE:
|
|
s = "TXT_SIZE";
|
|
break;
|
|
case TXT_WRAP:
|
|
s = "TXT_WRAP";
|
|
break;
|
|
}
|
|
// TODO: Support colour, which doesn't use the setFormat function
|
|
sprintf(msg,"Format property %s not valid for this control.\n",s.c_str());
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
eKeyMod operator + (eKeyMod lhs, eKeyMod rhs){
|
|
if(lhs == rhs) return lhs;
|
|
else if(lhs == mod_none) return rhs;
|
|
else if(lhs == mod_alt){
|
|
if(rhs == mod_shift || rhs == mod_altshift) return mod_altshift;
|
|
else if(rhs == mod_ctrl || rhs == mod_altctrl) return mod_altctrl;
|
|
else if(rhs == mod_shiftctrl || rhs == mod_all) return mod_all;
|
|
else return mod_alt;
|
|
}else if(lhs == mod_shift){
|
|
if(rhs == mod_alt || rhs == mod_altshift) return mod_altshift;
|
|
else if(rhs == mod_ctrl || rhs == mod_shiftctrl) return mod_shiftctrl;
|
|
else if(rhs == mod_altctrl || rhs == mod_all) return mod_all;
|
|
else return mod_shift;
|
|
}else if(lhs == mod_ctrl){
|
|
if(rhs == mod_alt || rhs == mod_altctrl) return mod_altctrl;
|
|
else if(rhs == mod_shift || rhs == mod_shiftctrl) return mod_shiftctrl;
|
|
else if(rhs == mod_altshift || rhs == mod_all) return mod_all;
|
|
else return mod_ctrl;
|
|
}else return rhs + lhs;
|
|
}
|
|
|
|
eKeyMod operator - (eKeyMod lhs, eKeyMod rhs){
|
|
if(lhs == rhs || lhs == mod_none || rhs == mod_all) return mod_none;
|
|
else if(rhs == mod_none) return lhs;
|
|
else if(lhs == mod_all){
|
|
if(rhs == mod_alt) return mod_shiftctrl;
|
|
else if(rhs == mod_shift) return mod_altctrl;
|
|
else if(rhs == mod_ctrl) return mod_altshift;
|
|
else if(rhs == mod_altshift) return mod_ctrl;
|
|
else if(rhs == mod_altctrl) return mod_shift;
|
|
else if(rhs == mod_shiftctrl) return mod_alt;
|
|
else return mod_all;
|
|
}else if(lhs == mod_shiftctrl){
|
|
if(rhs == mod_shift || rhs == mod_altshift) return mod_ctrl;
|
|
else if(rhs == mod_ctrl || rhs == mod_altctrl) return mod_shift;
|
|
else return mod_shiftctrl;
|
|
}else if(lhs == mod_altctrl){
|
|
if(rhs == mod_alt || rhs == mod_altshift) return mod_ctrl;
|
|
else if(rhs == mod_ctrl || rhs == mod_shiftctrl) return mod_alt;
|
|
else return mod_altctrl;
|
|
}else if(lhs == mod_altshift){
|
|
if(rhs == mod_alt || rhs == mod_altctrl) return mod_shift;
|
|
else if(rhs == mod_shift || rhs == mod_shiftctrl) return mod_alt;
|
|
else return mod_altshift;
|
|
}else if(lhs == mod_alt && (rhs == mod_altshift || rhs == mod_altctrl))
|
|
return mod_none;
|
|
else if(lhs == mod_shift && (rhs == mod_altshift || rhs == mod_shiftctrl))
|
|
return mod_none;
|
|
else if(lhs == mod_ctrl && (rhs == mod_altctrl || rhs == mod_shiftctrl))
|
|
return mod_none;
|
|
else return lhs;
|
|
}
|
|
|
|
eKeyMod& operator += (eKeyMod&lhs, eKeyMod rhs){
|
|
lhs = lhs + rhs;
|
|
return lhs;
|
|
}
|
|
|
|
eKeyMod& operator -= (eKeyMod&lhs, eKeyMod rhs){
|
|
lhs = lhs - rhs;
|
|
return lhs;
|
|
}
|
|
|
|
bool operator== (cKey a, cKey b){
|
|
if(a.spec != b.spec) return false;
|
|
if(a.mod != b.mod) return false;
|
|
return a.spec ? a.k == b.k : (a.c == 0 ? false : a.c == b.c);
|
|
}
|
|
|
|
bool mod_contains(eKeyMod mods, eKeyMod mod) {
|
|
if((mods & mod) != 0) return true;
|
|
return false;
|
|
}
|
|
|
|
void cControl::show(){
|
|
visible = true;
|
|
}
|
|
|
|
void cControl::hide(){
|
|
visible = false;
|
|
}
|
|
|
|
bool cControl::isVisible(){
|
|
if(!parent || parent->dialogNotToast)
|
|
return visible;
|
|
else return false;
|
|
}
|
|
|
|
cKey cControl::getAttachedKey() {
|
|
return key;
|
|
}
|
|
|
|
void cControl::setActive(bool active) {
|
|
depressed = active;
|
|
}
|
|
|
|
bool cControl::handleClick(){
|
|
sf::Event e;
|
|
bool done = false, clicked = false;
|
|
inWindow->setActive();
|
|
depressed = true;
|
|
while(!done){
|
|
if(parent) parent->draw();
|
|
else {
|
|
// TODO: This only redraws this one control; should probably redraw the entire dialog? But what if there is no dialog?
|
|
draw();
|
|
inWindow->display();
|
|
}
|
|
if(!inWindow->pollEvent(e)) continue;
|
|
if(e.type == sf::Event::MouseButtonReleased){
|
|
done = true;
|
|
clicked = frame.contains(e.mouseButton.x, e.mouseButton.y);
|
|
depressed = false;
|
|
} else if(e.type == sf::Event::MouseMoved){
|
|
depressed = frame.contains(e.mouseMove.x, e.mouseMove.y);
|
|
}
|
|
}
|
|
if (play_sounds) {
|
|
if(typeid(this) == typeid(cLed*))
|
|
play_sound(34);
|
|
else play_sound(37);
|
|
sf::sleep(time_in_ticks(6));
|
|
}
|
|
else sf::sleep(time_in_ticks(14));
|
|
if(parent) parent->draw();
|
|
else {
|
|
// TODO: This only redraws this one control; should probably redraw the entire dialog? But what if there is no dialog?
|
|
draw();
|
|
inWindow->display();
|
|
}
|
|
return clicked;
|
|
}
|
|
|
|
static unsigned char applyShift(unsigned char c){
|
|
static const char afterShift[] = {
|
|
' ', '!', '"', '#', '$', '%', '&', '"', '(', ')', '*', '+', '<', '_', '>', '?',
|
|
')', '!', '@', '#', '$', '%', '^', '&', '*', '(', ':', ':', '<', '+', '>', '?',
|
|
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '^', '_',
|
|
'~', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~',
|
|
};
|
|
return afterShift[c - ' '];
|
|
}
|
|
|
|
static unsigned char removeShift(unsigned char c){
|
|
static const char afterUnShift[] = {
|
|
' ', '1', '\'','3', '4', '5', '7', '\'','9', '0', '8', '=', ',', '-', '.', '/',
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';', ';', ',', '=', '.', '/',
|
|
'2', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\',']', '6', '-',
|
|
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\',']', '`',
|
|
};
|
|
return afterUnShift[c - ' '];
|
|
}
|
|
|
|
void cControl::setTextToKey(){
|
|
if(key.spec); // TODO: Handle this case
|
|
else{
|
|
unsigned char c = key.c;
|
|
if(key.mod - mod_shift != key.mod) c = applyShift(c);
|
|
else c = removeShift(c);
|
|
if(key.mod - mod_ctrl != key.mod) lbl = "^" + c;
|
|
else if(key.mod - mod_alt != key.mod) lbl = "*" + c;
|
|
else lbl = c;
|
|
}
|
|
if(isVisible()) draw();
|
|
}
|
|
|
|
void cControl::attachKey(cKey key){
|
|
this->key = key;
|
|
}
|
|
|
|
void cControl::detachKey(){
|
|
this->key.spec = false;
|
|
this->key.c = 0;
|
|
}
|
|
|
|
cControl::cControl(eControlType t, cDialog& p) : parent(&p), inWindow(&p.win), type(t), visible(true), key({false, 0, mod_none}), frameStyle(0) {}
|
|
|
|
cControl::cControl(eControlType t, sf::RenderWindow& p) : parent(NULL), inWindow(&p), type(t), visible(true), key({false, 0, mod_none}), frameStyle(0) {}
|
|
|
|
bool cControl::triggerClickHandler(cDialog& __attribute__((unused)), std::string __attribute__((unused)), eKeyMod __attribute__((unused)), location __attribute__((unused))){
|
|
return true;
|
|
}
|
|
|
|
bool cControl::triggerFocusHandler(cDialog& me __attribute__((unused)), std::string id __attribute__((unused)), bool losingFocus __attribute__((unused))){
|
|
return true;
|
|
}
|
|
|
|
std::string cControl::font_nums[4] = {"Dungeon", "Geneva", "Silom", "MaidenWord"};
|
|
|
|
void cControl::init(){
|
|
// Check if Silom is available
|
|
// TODO: Ultimately, I'd like to distribute all needed fonts with the game, rendering this unnecessary
|
|
try {
|
|
ResMgr::get<FontRsrc>("Silom");
|
|
found_silom = true;
|
|
} catch(ResMgr::xResMgrErr) {
|
|
found_silom = false;
|
|
}
|
|
}
|
|
|
|
void cControl::drawFrame(short amt, bool med_or_lt){
|
|
// dk_gray had a 0..65535 component of 12287, and med_gray had a 0..65535 component of 24574
|
|
static sf::Color lt_gray = {224,224,224},dk_gray = {48,48,48},med_gray = {96,96,96};
|
|
RECT rect = frame, ul_rect;
|
|
|
|
inWindow->setActive();
|
|
|
|
rect.inset(-amt,-amt);
|
|
ul_rect = rect;
|
|
ul_rect.left -= 1;
|
|
ul_rect.top -= 1;
|
|
|
|
frame_rect(*inWindow, rect, med_or_lt ? med_gray : lt_gray);
|
|
clip_rect(*inWindow, ul_rect);
|
|
frame_rect(*inWindow, rect, dk_gray);
|
|
undo_clip(*inWindow);
|
|
}
|
|
|
|
bool cControl::found_silom;
|
|
|
|
bool cControl::foundSilom(){
|
|
return found_silom;
|
|
}
|
|
|
|
cControl::~cControl() {}
|
|
|
|
eControlType cControl::getType(){
|
|
return type;
|
|
}
|
|
|
|
void cControl::setTextToNum(long what){
|
|
std::ostringstream sout;
|
|
sout << what;
|
|
setText(sout.str());
|
|
}
|
|
|
|
long cControl::getTextAsNum(){
|
|
std::istringstream sin(getText());
|
|
long n;
|
|
sin >> n;
|
|
return n;
|
|
}
|
|
|
|
bool cControl::hasKey(){
|
|
if(key.spec) return true;
|
|
return key.c != 0;
|
|
}
|