"Patch to reports to handle multiple images & strings per report ...

...each with their own tooltips." (patch by John B. Messerly)
This commit is contained in:
Pauli Manninen 2004-04-05 16:37:20 +00:00
parent 6d02c13ed1
commit 577d087f78
3 changed files with 113 additions and 153 deletions

View file

@ -674,7 +674,7 @@ void display::draw_report(reports::TYPE report_num)
const theme::status_item* const item = theme_.get_status_item(reports::report_name(report_num));
if(item != NULL) {
const reports::report& report = reports::generate_report(report_num,map_,
reports::report report = reports::generate_report(report_num,map_,
units_, teams_,
teams_[viewing_team()],
currentTeam_+1,activeTeam_+1,
@ -705,7 +705,7 @@ void display::draw_report(reports::TYPE report_num)
//if the rectangle is present, and we are blitting text, then
//we need to backup the surface. (Images generally won't need backing
//up unless they are transperant, but that is done later)
if(rect.w > 0 && rect.h > 0 && report.text.empty() == false) {
if(rect.w > 0 && rect.h > 0) {
surf.assign(get_surface_portion(screen_.getSurface(),rect));
if(reportSurfaces_[report_num] == NULL) {
std::cerr << "Could not backup background for report!\n";
@ -719,109 +719,60 @@ void display::draw_report(reports::TYPE report_num)
SDL_Rect area = rect;
// Code for handling a report with multiple tooltips in different areas of the text
// XXX figure out if prefix/postfix makes sense for these reports, and if so how
// should we support it?
if(report.text.size() > 1) {
int x = rect.x, y = rect.y;
for(size_t i = 0; i < report.text.size(); ++i) {
std::string text = report.text[i];
std::string tooltip = (i < report.tooltip.size() ? report.tooltip[i] : "");
area = font::draw_text(this,rect,item->font_size(),font::NORMAL_COLOUR,text,x,y);
if(text != "" && *(text.end()-1) == '\n') {
x = area.x;
y = area.y + area.h;
} else {
x = area.x + area.w;
y = area.y;
}
if(tooltip.empty() == false) {
tooltips::add_tooltip(area,tooltip);
}
}
// Skip single-tooltip report code and image drawing code
return;
}
std::string text = report.text.size() ? report.text[0] : "";
std::string tooltip = report.tooltip.size() ? report.tooltip[0] : "";
if(text.empty() == false) {
if(!report.empty()) {
// Add prefix, postfix elements. Make sure that they get the same tooltip as the guys
// around them.
std::string str = item->prefix();
int nchop;
//if there are formatting directives on the front of the report,
//move them to the front of the string
for(nchop = 0; nchop != text.size() && font::is_format_char(text[nchop]); ++nchop) {
str.insert(str.begin(),text[nchop]);
if(str.empty() == false) {
report.insert(report.begin(), reports::element(str,"",report.begin()->tooltip));
}
str = item->postfix();
if(str.empty() == false) {
report.push_back(reports::element(str,"",report.end()->tooltip));
}
str += text.substr(nchop) + item->postfix();
area = font::draw_text(this,rect,item->font_size(),font::NORMAL_COLOUR,str,rect.x,rect.y);
}
if(tooltip.empty() == false) {
tooltips::add_tooltip(area,tooltip);
}
if(report.image.empty() == false) {
//check if it's a table of images or a standalone image
if((report.image.find_first_of(",") == -1) &&
(report.image.find_first_of(";") == -1)) {
scoped_sdl_surface img(image::get_image(report.image,image::UNSCALED));
if(img == NULL) {
std::cerr << "could not find image for report: '" << report.image << "'\n";
return;
}
draw_image_for_report(img,surf,rect);
// Loop through and display each report element
size_t tallest = 0;
for(reports::report::iterator i = report.begin(); i != report.end(); ++i) {
if(i->text.empty() == false) {
// Draw a text element
area = font::draw_text(this,rect,item->font_size(),font::NORMAL_COLOUR,i->text,x,y);
if(area.h > tallest) tallest = area.h;
if(i->text[i->text.size() - 1] == '\n') {
x = rect.x;
y += tallest;
tallest = 0;
} else {
//draw a table of images...
//first back up the current area for later restoration
surf.assign(get_surface_portion(screen_.getSurface(),rect));
//each image may have a seperate tooltip, so seperate the tooltips
tooltips::clear_tooltips(rect);
int x = rect.x, y = rect.y;
const std::vector<std::string> rows = config::split(report.image,';');
const std::vector<std::string> tooltip_rows = config::split(tooltip,';');
std::vector<std::string>::const_iterator current_tooltip = tooltip_rows.begin();
for(std::vector<std::string>::const_iterator row = rows.begin(); row != rows.end(); ++row) {
size_t tallest_image = 0;
std::vector<std::string> cols = config::split(*row);
for(std::vector<std::string>::const_iterator col = cols.begin(); col != cols.end(); ++col) {
SDL_Rect clip_rect = rect;
scoped_sdl_surface image(image::get_image(*col,image::UNSCALED));
if(image == NULL) {
std::cerr << "could not find image for report: '" << *col << "'\n";
return;
}
blit_surface(x,y,image,NULL,&clip_rect);
if(image->h > tallest_image)
tallest_image = image->h;
SDL_Rect tooltip_rect = {x,y,image->w,image->h};
if(current_tooltip != tooltip_rows.end()) {
if(*current_tooltip != "") {
tooltips::add_tooltip(tooltip_rect,*current_tooltip);
}
++current_tooltip;
}
x += image->w;
x += area.w;
}
} else if(i->image.empty() == false) {
//first back up the current area for later restoration
//surf.assign(get_surface_portion(screen_.getSurface(),rect));
x = rect.x;
y += tallest_image;
// Draw an image element
scoped_sdl_surface img(image::get_image(i->image,image::UNSCALED));
if(img == NULL) {
std::cerr << "could not find image for report: '" << i->image << "'\n";
continue;
}
area.x = x;
area.y = y;
area.w = minimum<int>(rect.w + rect.x - x, img->w);
area.h = minimum<int>(rect.h + rect.y - y, img->h);
draw_image_for_report(img,surf,area);
if(area.h > tallest) tallest = area.h;
x += area.w;
} else {
// No text or image, skip this element
continue;
}
if(i->tooltip.empty() == false) {
tooltips::add_tooltip(area,i->tooltip);
}
}
}

View file

@ -33,13 +33,18 @@ void report::add_text(std::stringstream& text, std::stringstream& tooltip) {
}
void report::add_text(const std::string& text, const std::string& tooltip) {
this->text.push_back(text);
this->tooltip.push_back(tooltip);
this->push_back(element(text,"",tooltip));
}
void report::set_tooltip(const std::string& tooltip) {
this->tooltip.clear();
this->tooltip.push_back(tooltip);
void report::add_image(std::stringstream& image, std::stringstream& tooltip) {
add_image(image.str(), tooltip.str());
// Clear the streams
image.str("");
tooltip.str("");
}
void report::add_image(const std::string& image, const std::string& tooltip) {
this->push_back(element("",image,tooltip));
}
report generate_report(TYPE type, const gamemap& map, const unit_map& units,
@ -79,55 +84,47 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
switch(type) {
case UNIT_DESCRIPTION:
return report(u->second.description());
case UNIT_TYPE: {
report res(u->second.type().language_name());
res.set_tooltip(u->second.type().unit_description());
return res;
}
case UNIT_TYPE:
return report(u->second.type().language_name(),"",u->second.type().unit_description());
case UNIT_LEVEL:
str << u->second.type().level();
break;
case UNIT_TRAITS: {
report res(u->second.traits_description());
res.set_tooltip(u->second.modification_description("trait"));
return res;
}
case UNIT_TRAITS:
return report(u->second.traits_description(),"",u->second.modification_description("trait"));
case UNIT_STATUS: {
std::stringstream unit_status;
std::stringstream tooltip;
report res;
if(map.on_board(loc) && u->second.invisible(map.underlying_terrain(map[loc.x][loc.y]),status.get_time_of_day().lawful_bonus,loc,units,teams)) {
unit_status << "misc/invisible.png,";
tooltip << string_table["invisible"] << ": " <<
string_table["invisible_description"] << ";";
unit_status << "misc/invisible.png";
tooltip << string_table["invisible"] << ": " << string_table["invisible_description"];
res.add_image(unit_status,tooltip);
}
if(u->second.has_flag("slowed")) {
unit_status << "misc/slowed.png,";
tooltip << string_table["slowed"] << ": " <<
string_table["slowed_description"] << ";";
unit_status << "misc/slowed.png";
tooltip << string_table["slowed"] << ": " << string_table["slowed_description"];
res.add_image(unit_status,tooltip);
}
if(u->second.has_flag("poisoned")) {
unit_status << "misc/poisoned.png,";
tooltip << string_table["poisoned"] << ": " <<
string_table["poisoned_description"] << ";";
unit_status << "misc/poisoned.png";
tooltip << string_table["poisoned"] << ": " << string_table["poisoned_description"];
res.add_image(unit_status,tooltip);
}
if(u->second.has_flag("stone")) {
unit_status << "misc/stone.png,";
tooltip << string_table["stone"] << ": " <<
string_table["stone_description"] << ";";
unit_status << "misc/stone.png";
tooltip << string_table["stone"] << ": " << string_table["stone_description"];
res.add_image(unit_status,tooltip);
}
report res("",unit_status.str());
res.set_tooltip(tooltip.str());
return res;
}
case UNIT_ALIGNMENT: {
const std::string& align = unit_type::alignment_description(u->second.type().alignment());
report res(translate_string(align));
res.set_tooltip(string_table[align + "_description"]);
return res;
return report(translate_string(align),"",string_table[align + "_description"]);
}
case UNIT_ABILITIES: {
report res;
std::stringstream tooltip;
const std::vector<std::string>& abilities = u->second.type().abilities();
for(std::vector<std::string>::const_iterator i = abilities.begin(); i != abilities.end(); ++i) {
@ -135,11 +132,10 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
if(i+1 != abilities.end())
str << ",";
tooltip << string_table[*i + "_description"] << "\n\n";
tooltip << string_table[*i + "_description"];
res.add_text(str,tooltip);
}
report res(str.str());
res.set_tooltip(tooltip.str());
return res;
}
case UNIT_HP:
@ -181,11 +177,11 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
str << (lang_weapon.empty() ? at_it->name():lang_weapon) << " ("
<< (lang_type.empty() ? at_it->type():lang_type) << ")\n";
res.add_text(str, tooltip);
res.add_text(str,tooltip);
str << (lang_special.empty() ? at_it->special():lang_special) << "\n";
tooltip << string_table["weapon_special_" + at_it->special() + "_description"];
res.add_text(str, tooltip);
res.add_text(str,tooltip);
str << at_it->damage() << "-" << at_it->num_attacks() << " -- "
<< (at_it->range() == attack_type::SHORT_RANGE ?
@ -199,18 +195,17 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
tooltip << ", " << at_it->hexes() << " " << string_table["hexes"];
}
str << "\n";
res.add_text(str, tooltip);
res.add_text(str,tooltip);
}
return res;
}
case UNIT_IMAGE:
return report("",u->second.type().image());
return report("",u->second.type().image(),"");
case UNIT_PROFILE:
return report("",u->second.type().image_profile());
return report("",u->second.type().image_profile(),"");
case TIME_OF_DAY: {
const time_of_day& tod = timeofday_at(status,units,mouseover);
report res("",tod.image);
std::stringstream tooltip;
tooltip << font::LARGE_TEXT << translate_string_default(tod.id,tod.name) << "\n"
@ -219,8 +214,8 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
<< translate_string("neutral") << " " << string_table["units"] << ": " << "0%\n"
<< translate_string("chaotic") << " " << string_table["units"] << ": "
<< (tod.lawful_bonus < 0 ? "+" : "") << (tod.lawful_bonus*-1) << "%";
res.set_tooltip(tooltip.str());
return res;
return report("",tod.image,tooltip.str());
}
case TURN:
str << status.turn() << "/" << status.number_of_turns() << "\n";
@ -295,7 +290,7 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
case SIDE_PLAYING: {
char buf[50];
sprintf(buf,"terrain/flag-team%d.png",playing_side);
return report("",buf);
return report("",buf,"");
}
case OBSERVERS: {
@ -307,9 +302,7 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
str << *i << "\n";
}
report res("",game_config::observer_image);
res.set_tooltip(str.str());
return res;
return report("",game_config::observer_image,str.str());
}
}

View file

@ -25,21 +25,37 @@ namespace reports {
const std::string& report_name(TYPE type);
struct report {
struct element {
// Invariant: either text or image should be empty
// It would be okay to create a class for this, but it's a pretty simple
// invariant so I left it like the original report class.
std::string image;
std::vector<std::string> text, tooltip;
std::string text;
std::string tooltip;
element() {}
explicit element(const std::string& text) : text(text) {}
element(const std::string& text, const std::string& image, const std::string& tooltip) :
text(text), image(image), tooltip(tooltip) {}
bool operator==(const element& o) const {
return o.text == text && o.image == image && o.tooltip == tooltip;
}
bool operator!=(const element& o) const { return !(o == *this); }
};
struct report : public std::vector<element> {
report() {}
explicit report(const std::string& text) { this->text.push_back(text); }
report(const std::string& text, const std::string& image) : image(image) { this->text.push_back(text); }
bool empty() const { return text.empty() && image.empty(); }
bool operator==(const report& o) const { return o.text == text && o.image == image && o.tooltip == tooltip; }
bool operator!=(const report& o) const { return !(o == *this); }
explicit report(const std::string& text) { this->push_back(element(text)); }
report(const std::string& text, const std::string& image, const std::string& tooltip) {
this->push_back(element(text, image, tooltip));
}
// Convenience functions
void add_text(std::stringstream& text, std::stringstream& tooltip);
void add_text(const std::string& text, const std::string& tooltip);
void set_tooltip(const std::string& tooltip);
void add_image(const std::string& image, const std::string& tooltip);
void add_image(std::stringstream& image, std::stringstream& tooltip);
};
report generate_report(TYPE type, const gamemap& map, const unit_map& units,