- Removed the terrain_pic and terrain_blockage arrays, which were redundant (though shorter). - Cleaned out some of the commented code in boe.graphics.cpp and boe.graphutil.cpp - Added a templated get function to cOutdoors::cWandering. In the dialog engine: - Important fields are now initialized to default values, as they should be. - The absence of required attributes is now recognized as an error - Added stack element to the DTD; no code support yet - Added fore attribute to the dialog element to specify default text colour; DTD updated and code support added. - Likewise with the def-key attribute on other clickable items besides buttons (which already had it) - Updated stylesheet to fall back on the fore attribute when colour is unspecified - When drawing default monster graphics, it uses m_start_pic instead of num as the index. This should be right, though it's untested. Unfortunately, the dialog engine is still unstable. git-svn-id: http://openexile.googlecode.com/svn/trunk@100 4ebdad44-0ea0-11de-aab3-ff745001d230
435 lines
11 KiB
C++
435 lines
11 KiB
C++
/*
|
|
* button.cpp
|
|
* BoE
|
|
*
|
|
* Created by Celtic Minstrel on 11/05/09.
|
|
*
|
|
*/
|
|
|
|
#include <Carbon/Carbon.h>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <stdexcept>
|
|
|
|
#include "dialog.h"
|
|
#include "graphtool.h"
|
|
|
|
#include <cmath>
|
|
|
|
extern GWorldPtr bg_gworld;
|
|
|
|
void cButton::attachFocusHandler(focus_callback_t f __attribute__((unused))) throw(xHandlerNotSupported){
|
|
throw xHandlerNotSupported(true);
|
|
}
|
|
|
|
void cButton::attachClickHandler(click_callback_t f) throw(){
|
|
onClick = f;
|
|
}
|
|
|
|
bool cButton::triggerClickHandler(cDialog& me, std::string id, eKeyMod mods, Point where){
|
|
if(onClick != NULL) return onClick(me,id,mods);
|
|
return false;
|
|
}
|
|
|
|
cButton::cButton(cDialog* parent) :
|
|
cControl(parent,CTRL_BTN),
|
|
wrapLabel(false),
|
|
fromList("none") {}
|
|
|
|
cButton::cButton(cDialog* parent,eControlType t) :
|
|
cControl(parent,t),
|
|
fromList("none"),
|
|
wrapLabel("true") {/* This constructor is only called for LEDs. TODO: Should wrapLabel be true for LEDs? */}
|
|
|
|
bool cButton::isClickable(){
|
|
return true;
|
|
}
|
|
|
|
void cButton::draw(){
|
|
GrafPtr old_port;
|
|
Rect from_rect, to_rect;
|
|
GWorldPtr from_gw, to_gw;
|
|
|
|
GetPort(&old_port);
|
|
SetPortWindowPort(parent->win);
|
|
|
|
if(visible){
|
|
TextFont(font_nums[GENEVA]);
|
|
if(foundSilom())TextFace(normal);
|
|
else TextFace(bold);
|
|
if(type == BTN_TINY) TextSize(9);
|
|
else if(type == BTN_PUSH) TextSize(10);
|
|
else TextSize(12);
|
|
from_gw = buttons[btnGW[type]];
|
|
from_rect = btnRects[btnGW[type]][depressed];
|
|
to_rect = frame;
|
|
rect_draw_some_item(from_gw,from_rect,to_rect,(Point){0,0}); // TODO: This originally drew to dest 2 (dialog window); does it still?
|
|
RGBForeColor(&parent->defTextClr);
|
|
char_win_draw_string(parent->win,to_rect,lbl.c_str(),1,8);
|
|
// TODO: Adjust string location as appropriate
|
|
// Tiny button string location should be shifted right 20 pixels (or possibly 18)
|
|
// Push button string should be centred below the button
|
|
// Others may need adjustments too, not sure
|
|
ForeColor(blackColor);
|
|
if(key.spec && key.k == key_enter) drawFrame(2,0); // frame default button, to provide a visual cue that it's the default
|
|
}else{
|
|
tileImage(frame,bg_gworld,bg[parent->bg]);
|
|
}
|
|
|
|
SetPort(old_port);
|
|
}
|
|
|
|
void cButton::setFormat(eFormat prop, short val) throw(xUnsupportedProp){
|
|
if(prop == TXT_WRAP) wrapLabel = val;
|
|
else throw xUnsupportedProp(prop);
|
|
if(isVisible()) draw();
|
|
}
|
|
|
|
short cButton::getFormat(eFormat prop) throw(xUnsupportedProp){
|
|
if(prop == TXT_WRAP) return wrapLabel;
|
|
else throw xUnsupportedProp(prop);
|
|
}
|
|
|
|
// Indices within the buttons array.
|
|
size_t cButton::btnGW[14] = {
|
|
0, // BTN_SM
|
|
1, // BTN_REG
|
|
2, // BTN_LG
|
|
4, // BTN_HELP
|
|
1, // BTN_LEFT
|
|
1, // BTN_RIGHT
|
|
1, // BTN_UP
|
|
1, // BTN_DOWN
|
|
5, // BTN_TINY
|
|
1, // BTN_DONE
|
|
3, // BTN_TALL
|
|
3, // BTN_TRAIT
|
|
6, // BTN_PUSH
|
|
5, // BTN_LED
|
|
};
|
|
|
|
GWorldPtr cButton::buttons[7] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
|
|
Rect cButton::btnRects[13][2];
|
|
|
|
void cButton::init(){
|
|
static const char*const buttonFiles[7] = {
|
|
"dlogbtnsm.png",
|
|
"dlogbtnmed.png",
|
|
"dlogbtnlg.png",
|
|
"dlogbtntall.png",
|
|
"dlogbtnhelp.png",
|
|
"dlogbtnled.png",
|
|
"dlogbtnred.png"
|
|
};
|
|
for(int i = 0; i < 7; i++)
|
|
buttons[i] = load_pict(buttonFiles[i]);
|
|
SetRect(&btnRects[BTN_SM][0],0,0,23,23);
|
|
SetRect(&btnRects[BTN_REG][0],0,0,63,23);
|
|
SetRect(&btnRects[BTN_LEFT][0],0,23,63,46);
|
|
SetRect(&btnRects[BTN_RIGHT][0],0,46,63,69);
|
|
SetRect(&btnRects[BTN_UP][0],0,69,63,92);
|
|
SetRect(&btnRects[BTN_DOWN][0],0,92,63,115);
|
|
SetRect(&btnRects[BTN_DONE][0],0,115,63,138);
|
|
SetRect(&btnRects[BTN_LG][0],0,0,104,23);
|
|
SetRect(&btnRects[BTN_HELP][0],0,0,16,13);
|
|
SetRect(&btnRects[BTN_TINY][0],42,0,56,10);
|
|
SetRect(&btnRects[BTN_TALL][0],0,0,63,40);
|
|
SetRect(&btnRects[BTN_TRAIT][0],0,40,63,80);
|
|
SetRect(&btnRects[BTN_PUSH][0],0,0,30,30);
|
|
for(int j = 0; j < 12; j++)
|
|
btnRects[j][1] = btnRects[j][0];
|
|
OffsetRect(&btnRects[BTN_SM][1],23,0);
|
|
OffsetRect(&btnRects[BTN_REG][1],63,0);
|
|
OffsetRect(&btnRects[BTN_LEFT][1],63,0);
|
|
OffsetRect(&btnRects[BTN_RIGHT][1],63,0);
|
|
OffsetRect(&btnRects[BTN_UP][1],63,0);
|
|
OffsetRect(&btnRects[BTN_DOWN][1],63,0);
|
|
OffsetRect(&btnRects[BTN_DONE][1],63,0);
|
|
OffsetRect(&btnRects[BTN_LG][1],104,0);
|
|
OffsetRect(&btnRects[BTN_HELP][1],16,0);
|
|
OffsetRect(&btnRects[BTN_TINY][1],0,10);
|
|
OffsetRect(&btnRects[BTN_TALL][1],63,0);
|
|
OffsetRect(&btnRects[BTN_TRAIT][1],63,0);
|
|
OffsetRect(&btnRects[BTN_PUSH][1],30,0);
|
|
}
|
|
|
|
void cButton::finalize(){
|
|
for(int i = 0; i < 7; i++)
|
|
DisposeGWorld(buttons[i]);
|
|
}
|
|
|
|
Rect cLed::ledRects[3][2];
|
|
|
|
void cLed::init(){
|
|
Rect baseLed = {0,0,10,14};
|
|
for(int i = 0; i < 3; i++)
|
|
for(int j = 0; j < 2; j++){
|
|
ledRects[i][j] = baseLed;
|
|
OffsetRect(&ledRects[i][j],i * 14, j * 10);
|
|
}
|
|
}
|
|
|
|
cLed::cLed(cDialog* parent) :
|
|
cButton(parent,CTRL_LED),
|
|
state(led_off),
|
|
textFont(SILOM),
|
|
textSize(10),
|
|
color(parent->defTextClr) {}
|
|
|
|
void cLed::attachClickHandler(click_callback_t f) throw(){
|
|
onClick = f;
|
|
}
|
|
|
|
void cLed::attachFocusHandler(focus_callback_t f) throw(){
|
|
onFocus = f;
|
|
}
|
|
|
|
bool cLed::triggerFocusHandler(cDialog& me, std::string id, bool losing){
|
|
if(onFocus != NULL) return onFocus(me,id,losing);
|
|
return true;
|
|
}
|
|
|
|
bool cLed::triggerClickHandler(cDialog& me, std::string id, eKeyMod mods, Point where){
|
|
bool result;
|
|
eLedState oldState = state;
|
|
if(onClick != NULL) result = onClick(me,id,mods);
|
|
else{ // simple state toggle
|
|
switch(state){
|
|
case led_red:
|
|
case led_green:
|
|
state = led_off;
|
|
break;
|
|
case led_off:
|
|
state = led_red;
|
|
}
|
|
result = true;
|
|
}
|
|
if(!triggerFocusHandler(me,id, oldState != led_off)){
|
|
result = false;
|
|
state = oldState;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void cLed::setFormat(eFormat prop __attribute__((unused)), short val __attribute__((unused))) throw(xUnsupportedProp){
|
|
throw xUnsupportedProp(prop);
|
|
}
|
|
|
|
short cLed::getFormat(eFormat prop __attribute__((unused))) throw(xUnsupportedProp){
|
|
throw xUnsupportedProp(prop);
|
|
}
|
|
|
|
void cLed::draw(){
|
|
GrafPtr old_port;
|
|
Rect from_rect, to_rect;
|
|
GWorldPtr from_gw, to_gw;
|
|
|
|
GetPort(&old_port);
|
|
SetPortWindowPort(parent->win);
|
|
|
|
if(visible){
|
|
TextFont(font_nums[GENEVA]);
|
|
if(foundSilom())TextFace(normal);
|
|
else TextFace(bold);
|
|
TextSize(9);
|
|
from_gw = buttons[btnGW[BTN_LED]];
|
|
from_rect = ledRects[state][depressed];
|
|
to_rect = frame;
|
|
rect_draw_some_item(from_gw,from_rect,to_rect,(Point){0,0});
|
|
RGBForeColor(&parent->defTextClr);
|
|
char_win_draw_string(parent->win,to_rect,lbl.c_str(),1,8);
|
|
// TODO: Adjust string location as appropriate
|
|
// String location should be shifted right 20 pixels (or possibly 18)
|
|
ForeColor(blackColor);
|
|
}else{
|
|
tileImage(frame,bg_gworld,bg[parent->bg]);
|
|
}
|
|
|
|
SetPort(old_port);
|
|
}
|
|
|
|
cLedGroup::cLedGroup(cDialog* parent) :
|
|
cControl(parent,CTRL_GROUP),
|
|
fromList("none") {}
|
|
|
|
cButton::~cButton() {}
|
|
|
|
cLed::~cLed() {}
|
|
|
|
cLedGroup::~cLedGroup(){
|
|
ledIter iter = choices.begin();
|
|
while(iter != choices.end()){
|
|
delete iter->second;
|
|
iter++;
|
|
}
|
|
}
|
|
|
|
void cLedGroup::recalcRect(){
|
|
ledIter iter = choices.begin();
|
|
while(iter != choices.end()){
|
|
if(iter->second->frame.right > frame.right)
|
|
frame.right = iter->second->frame.right;
|
|
if(iter->second->frame.bottom > frame.bottom)
|
|
frame.bottom = iter->second->frame.bottom;
|
|
iter++;
|
|
}
|
|
frame.right += 6;
|
|
frame.bottom += 6;
|
|
}
|
|
|
|
/** A click handler is called whenever a click is received, even on the currently selected element. */
|
|
void cLedGroup::attachClickHandler(click_callback_t f) throw() {
|
|
onClick = f;
|
|
}
|
|
|
|
/** A focus handler is called when the currently selected element changes. */
|
|
void cLedGroup::attachFocusHandler(focus_callback_t f) throw() {
|
|
onFocus = f;
|
|
}
|
|
|
|
void cLed::setState(eLedState to){
|
|
state = to;
|
|
}
|
|
|
|
eLedState cLed::getState(){
|
|
return state;
|
|
}
|
|
|
|
bool cLedGroup::triggerClickHandler(cDialog& me, std::string id, eKeyMod mods, Point where){
|
|
std::string which_clicked;
|
|
ledIter iter = choices.begin();
|
|
while(iter != choices.end()){
|
|
if(iter->second->visible && PtInRect(where,&iter->second->frame)){
|
|
if(iter->second->handleClick())
|
|
which_clicked = iter->first;
|
|
}
|
|
iter++;
|
|
}
|
|
|
|
if(which_clicked == "") return false;
|
|
|
|
if(choices[which_clicked]->triggerClickHandler(me,which_clicked,mods,where)){
|
|
eLedState a, b;
|
|
a = choices[curSelect]->getState();
|
|
b = choices[which_clicked]->getState();
|
|
choices[curSelect]->setState(led_off);
|
|
choices[which_clicked]->setState(led_red);
|
|
if(!choices[curSelect]->triggerFocusHandler(me,curSelect,true)){
|
|
choices[curSelect]->setState(a);
|
|
choices[which_clicked]->setState(b);
|
|
return false;
|
|
}
|
|
if(!choices[which_clicked]->triggerFocusHandler(me,which_clicked,false)){
|
|
choices[curSelect]->setState(a);
|
|
choices[which_clicked]->setState(b);
|
|
return false;
|
|
}
|
|
curSelect = which_clicked;
|
|
}else return false;
|
|
|
|
return triggerFocusHandler(me,id,false);
|
|
}
|
|
|
|
bool cLedGroup::triggerFocusHandler(cDialog& me, std::string id, bool losingFocus){
|
|
if(onFocus != NULL) return onFocus(me,id,losingFocus);
|
|
return true;
|
|
}
|
|
|
|
void cLedGroup::disable(std::string id) {
|
|
// TODO: Implement this
|
|
}
|
|
|
|
void cLedGroup::enable(std::string id) {
|
|
// TODO: Implement this
|
|
}
|
|
|
|
void cLedGroup::show(std::string id){
|
|
choices[id]->show();
|
|
}
|
|
|
|
void cLedGroup::hide(std::string id){
|
|
choices[id]->hide();
|
|
}
|
|
|
|
void cLedGroup::setFormat(eFormat prop __attribute__((unused)), short val __attribute__((unused))) throw(xUnsupportedProp) {
|
|
throw xUnsupportedProp(prop);
|
|
}
|
|
|
|
short cLedGroup::getFormat(eFormat prop __attribute__((unused))) throw(xUnsupportedProp) {
|
|
throw xUnsupportedProp(prop);
|
|
}
|
|
|
|
bool cLedGroup::isClickable(){
|
|
return true;
|
|
}
|
|
|
|
cLed& cLedGroup::operator[](std::string id){
|
|
ledIter iter = choices.find(id);
|
|
if(iter == choices.end()) throw std::invalid_argument(id + " does not exist in the ledgroup.");
|
|
return *(iter->second);
|
|
}
|
|
|
|
void cLedGroup::setSelected(std::string id){
|
|
if(id == "") { // deselect all
|
|
eLedState was = choices[curSelect]->getState();
|
|
choices[curSelect]->setState(led_off);
|
|
if(choices[curSelect]->triggerFocusHandler(*parent,curSelect,true))
|
|
curSelect = "";
|
|
else
|
|
choices[curSelect]->setState(was);
|
|
return;
|
|
}
|
|
|
|
ledIter iter = choices.find(id);
|
|
if(iter == choices.end()) throw std::invalid_argument(id + " does not exist in the ledgroup.");
|
|
|
|
if(curSelect == ""){
|
|
if(iter->second->triggerFocusHandler(*parent,curSelect,false)){
|
|
iter->second->setState(led_red);
|
|
curSelect = iter->first;
|
|
}
|
|
}else{
|
|
eLedState a, b;
|
|
a = choices[curSelect]->getState();
|
|
b = iter->second->getState();
|
|
choices[curSelect]->setState(led_off);
|
|
iter->second->setState(led_red);
|
|
if(!choices[curSelect]->triggerFocusHandler(*parent,curSelect,true)){
|
|
choices[curSelect]->setState(a);
|
|
iter->second->setState(b);
|
|
return;
|
|
}
|
|
if(!iter->second->triggerFocusHandler(*parent,curSelect,false)){
|
|
choices[curSelect]->setState(a);
|
|
iter->second->setState(b);
|
|
return;
|
|
}
|
|
curSelect = iter->first;
|
|
}
|
|
}
|
|
|
|
std::string cLedGroup::getSelected(){
|
|
return curSelect;
|
|
}
|
|
|
|
std::string cLedGroup::getPrevSelection(){
|
|
return prevSelect;
|
|
}
|
|
|
|
void cLedGroup::draw(){
|
|
ledIter iter = choices.begin();
|
|
while(iter != choices.end()){
|
|
iter->second->draw();
|
|
iter++;
|
|
}
|
|
}
|
|
|
|
void cButton::setType(eBtnType newType){
|
|
if(type == BTN_LED) return; // can't change type
|
|
type = newType;
|
|
}
|
|
|
|
eBtnType cButton::getType(){
|
|
return type;
|
|
}
|