00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "SDL.h"
00019 #include "SDL_keysym.h"
00020
00021 #include "editor_palettes.hpp"
00022 #include "editor_layout.hpp"
00023 #include "../config.hpp"
00024 #include "../sdl_utils.hpp"
00025 #include "../serialization/string_utils.hpp"
00026 #include "../image.hpp"
00027 #include "../reports.hpp"
00028 #include "../gettext.hpp"
00029 #include "../tooltips.hpp"
00030 #include "../util.hpp"
00031 #include "../video.hpp"
00032
00033 #include <cassert>
00034
00035 namespace map_editor {
00036
00037 static bool is_invalid_terrain(t_translation::t_terrain c) {
00038 return (c == t_translation::VOID_TERRAIN || c == t_translation::FOGGED);
00039 }
00040
00041 terrain_group::terrain_group(const config& cfg, display& gui):
00042 id(cfg["id"]), name(cfg["name"]),
00043 button(gui.video(), "", gui::button::TYPE_CHECK, cfg["icon"])
00044 {
00045 }
00046
00047 terrain_palette::terrain_palette(display &gui, const size_specs &sizes,
00048 const gamemap &map, const config& cfg)
00049 : gui::widget(gui.video()), size_specs_(sizes), gui_(gui), tstart_(0),
00050 checked_group_btn_(0), map_(map),
00051 top_button_(gui.video(), "", gui::button::TYPE_PRESS, "uparrow-button"),
00052 bot_button_(gui.video(), "", gui::button::TYPE_PRESS, "downarrow-button")
00053 {
00054
00055
00056 terrains_ = map_.get_terrain_list();
00057 terrains_.erase(std::remove_if(terrains_.begin(), terrains_.end(), is_invalid_terrain),
00058 terrains_.end());
00059
00060
00061 const config::child_list& groups = cfg.get_children("editor_group");
00062 config::child_list::const_iterator g_itor = groups.begin();
00063 for(; g_itor != groups.end(); ++ g_itor) {
00064 terrain_groups_.push_back(terrain_group(**g_itor, gui));
00065
00066
00067 if(terrain_groups_.back().id == "all") {
00068 terrain_groups_.back().button.set_check(true);
00069 checked_group_btn_ = &terrain_groups_.back().button;
00070 }
00071 }
00072
00073 assert(checked_group_btn_ != 0);
00074
00075
00076 t_translation::t_list::const_iterator t_itor = terrains_.begin();
00077 for(; t_itor != terrains_.end(); ++t_itor) {
00078 const terrain_type& t_info = map_.get_terrain_info(*t_itor);
00079
00080
00081 if (t_info.is_combined())
00082 continue;
00083
00084
00085 const std::vector<std::string>& key =
00086 utils::split(t_info.editor_group());
00087
00088 for(std::vector<std::string>::const_iterator k_itor = key.begin();
00089 k_itor != key.end(); ++k_itor)
00090 {
00091 terrain_map_[*k_itor].push_back(*t_itor);
00092 }
00093
00094
00095 terrain_map_["all"].push_back(*t_itor);
00096 }
00097
00098
00099 terrains_ = terrain_map_["all"];
00100
00101 if(terrains_.empty()) {
00102 std::cerr << "No terrain found.\n";
00103 }
00104 else {
00105 selected_fg_terrain_ = terrains_[0];
00106 selected_bg_terrain_ = terrains_[0];
00107 }
00108 update_report();
00109
00110 }
00111
00112 void terrain_palette::adjust_size() {
00113
00114 scroll_top();
00115 const size_t button_height = 24;
00116 const size_t button_palette_padding = 8;
00117
00118
00119
00120 const size_t group_button_height = 24;
00121 const size_t group_button_padding = 2;
00122 const size_t group_buttons_per_row = 5;
00123
00124
00125 size_t group_rows = terrain_groups_.size() / group_buttons_per_row;
00126 if(terrain_groups_.size() % group_buttons_per_row != 0) {
00127 ++group_rows;
00128 }
00129 const size_t group_height = group_rows * (group_button_height + group_button_padding);
00130
00131 SDL_Rect rect = { size_specs_.palette_x, size_specs_.palette_y, size_specs_.palette_w, size_specs_.palette_h };
00132 set_location(rect);
00133 top_button_y_ = size_specs_.palette_y + group_height ;
00134 button_x_ = size_specs_.palette_x + size_specs_.palette_w/2 - button_height/2;
00135 terrain_start_ = top_button_y_ + button_height + button_palette_padding;
00136 const size_t space_for_terrains = size_specs_.palette_h - (button_height + button_palette_padding) * 2 - group_height;
00137 rect.y = terrain_start_;
00138 rect.h = space_for_terrains;
00139 bg_register(rect);
00140 const unsigned terrains_fitting =
00141 static_cast<unsigned> (space_for_terrains / size_specs_.terrain_space) *
00142 size_specs_.terrain_width;
00143 const unsigned total_terrains = num_terrains();
00144 nterrains_ = minimum<int>(terrains_fitting, total_terrains);
00145 bot_button_y_ = size_specs_.palette_y + (nterrains_ / size_specs_.terrain_width) * size_specs_.terrain_space + \
00146 button_palette_padding * size_specs_.terrain_width + button_height + group_height;
00147 top_button_.set_location(button_x_, top_button_y_);
00148 bot_button_.set_location(button_x_, bot_button_y_);
00149
00150 size_t top = size_specs_.palette_y;
00151 size_t left = size_specs_.palette_x - 8;
00152 for(size_t i = 0; i < terrain_groups_.size(); ++i) {
00153 terrain_groups_[i].button.set_location(left, top);
00154 if(i % group_buttons_per_row == (group_buttons_per_row - 1)) {
00155 left = size_specs_.palette_x - 8;
00156 top += group_button_height + group_button_padding;
00157 } else {
00158 left += group_button_height + group_button_padding;
00159 }
00160 }
00161
00162 set_dirty();
00163 }
00164
00165 void terrain_palette::set_dirty(bool dirty) {
00166 widget::set_dirty(dirty);
00167 if (dirty) {
00168 top_button_.set_dirty();
00169 bot_button_.set_dirty();
00170 for(size_t i = 0; i < terrain_groups_.size(); ++i) {
00171 terrain_groups_[i].button.set_dirty();
00172 }
00173 }
00174 }
00175
00176 void terrain_palette::scroll_down() {
00177 if(tstart_ + nterrains_ + size_specs_.terrain_width <= num_terrains()) {
00178 tstart_ += size_specs_.terrain_width;
00179 bg_restore();
00180 set_dirty();
00181 }
00182 else if (tstart_ + nterrains_ + (num_terrains() % size_specs_.terrain_width) <= num_terrains()) {
00183 tstart_ += num_terrains() % size_specs_.terrain_width;
00184 bg_restore();
00185 set_dirty();
00186 }
00187 }
00188
00189 void terrain_palette::scroll_up() {
00190 unsigned int decrement = size_specs_.terrain_width;
00191 if (tstart_ + nterrains_ == num_terrains() && num_terrains() % size_specs_.terrain_width != 0) {
00192 decrement = num_terrains() % size_specs_.terrain_width;
00193 }
00194 if(tstart_ >= decrement) {
00195 bg_restore();
00196 set_dirty();
00197 tstart_ -= decrement;
00198 }
00199 }
00200
00201 void terrain_palette::scroll_top() {
00202 tstart_ = 0;
00203 bg_restore();
00204 set_dirty();
00205 }
00206
00207 void terrain_palette::scroll_bottom() {
00208 unsigned int old_start = num_terrains();
00209 while (old_start != tstart_) {
00210 old_start = tstart_;
00211 scroll_down();
00212 }
00213 }
00214
00215 void terrain_palette::set_group(const std::string& id)
00216 {
00217 terrains_ = terrain_map_[id];
00218 if(terrains_.empty()) {
00219 std::cerr << "No terrain found.\n";
00220 }
00221 scroll_top();
00222 }
00223
00224 t_translation::t_terrain terrain_palette::selected_fg_terrain() const
00225 {
00226 return selected_fg_terrain_;
00227 }
00228
00229 t_translation::t_terrain terrain_palette::selected_bg_terrain() const
00230 {
00231 return selected_bg_terrain_;
00232 }
00233
00234 void terrain_palette::select_fg_terrain(t_translation::t_terrain terrain)
00235 {
00236 if (selected_fg_terrain_ != terrain) {
00237 set_dirty();
00238 selected_fg_terrain_ = terrain;
00239 update_report();
00240 }
00241 }
00242
00243 void terrain_palette::select_bg_terrain(t_translation::t_terrain terrain)
00244 {
00245 if (selected_bg_terrain_ != terrain) {
00246 set_dirty();
00247 selected_bg_terrain_ = terrain;
00248 update_report();
00249 }
00250 }
00251
00252
00253
00254 void terrain_palette::update_selected_terrains(void)
00255 {
00256 set_dirty();
00257 update_report();
00258 }
00259
00260 std::string terrain_palette::get_terrain_string(const t_translation::t_terrain t)
00261 {
00262 std::stringstream str;
00263 const std::string& name = map_.get_terrain_info(t).name();
00264 const t_translation::t_list& underlying = map_.underlying_union_terrain(t);
00265 str << name;
00266 if(underlying.size() != 1 || underlying[0] != t) {
00267 str << " (";
00268 for(t_translation::t_list::const_iterator i = underlying.begin();
00269 i != underlying.end(); ++i) {
00270
00271 str << map_.get_terrain_info(*i).name();
00272 if(i+1 != underlying.end()) {
00273 str << ",";
00274 }
00275 }
00276 str << ")";
00277 }
00278 return str.str();
00279 }
00280
00281 void terrain_palette::left_mouse_click(const int mousex, const int mousey) {
00282 int tselect = tile_selected(mousex, mousey);
00283 if(tselect >= 0) {
00284 select_fg_terrain(terrains_[tstart_+tselect]);
00285 gui_.invalidate_game_status();
00286 }
00287 }
00288
00289 void terrain_palette::right_mouse_click(const int mousex, const int mousey) {
00290 int tselect = tile_selected(mousex, mousey);
00291 if(tselect >= 0) {
00292 select_bg_terrain(terrains_[tstart_+tselect]);
00293 gui_.invalidate_game_status();
00294 }
00295 }
00296
00297 size_t terrain_palette::num_terrains() const {
00298 return terrains_.size();
00299 }
00300
00301 void terrain_palette::draw() {
00302 draw(false);
00303 }
00304
00305 void terrain_palette::handle_event(const SDL_Event& event) {
00306 if (event.type == SDL_MOUSEMOTION) {
00307
00308 if (point_in_rect(event.button.x, event.button.y, location())) {
00309 if (!focus(&event)) {
00310 set_focus(true);
00311 }
00312 }
00313
00314 else {
00315 if (focus(&event)) {
00316 set_focus(false);
00317 }
00318 }
00319 }
00320 if (!focus(&event)) {
00321 return;
00322 }
00323 int mousex, mousey;
00324 SDL_GetMouseState(&mousex,&mousey);
00325 const SDL_MouseButtonEvent mouse_button_event = event.button;
00326 if (mouse_button_event.type == SDL_MOUSEBUTTONDOWN) {
00327 if (mouse_button_event.button == SDL_BUTTON_LEFT) {
00328 left_mouse_click(mousex, mousey);
00329 }
00330 if (mouse_button_event.button == SDL_BUTTON_RIGHT) {
00331 right_mouse_click(mousex, mousey);
00332 }
00333 if (mouse_button_event.button == SDL_BUTTON_WHEELUP) {
00334 scroll_up();
00335 }
00336 if (mouse_button_event.button == SDL_BUTTON_WHEELDOWN) {
00337 scroll_down();
00338 }
00339 }
00340 if (mouse_button_event.type == SDL_MOUSEBUTTONUP) {
00341 if (mouse_button_event.button == SDL_BUTTON_LEFT) {
00342 }
00343 }
00344 }
00345
00346 void terrain_palette::draw(bool force) {
00347
00348 if (top_button_.pressed()) {
00349 scroll_up();
00350 }
00351 if (bot_button_.pressed()) {
00352 scroll_down();
00353 }
00354 for(size_t i = 0; i < terrain_groups_.size(); ++i) {
00355 if(terrain_groups_[i].button.pressed()) {
00356 if(&terrain_groups_[i].button == checked_group_btn_) {
00357 checked_group_btn_->set_check(true);
00358 } else {
00359 checked_group_btn_->set_check(false);
00360 checked_group_btn_ = &terrain_groups_[i].button;
00361 set_group(terrain_groups_[i].id);
00362 }
00363 break;
00364 }
00365 }
00366 if (!dirty() && !force) {
00367 return;
00368 }
00369 unsigned int starting = tstart_;
00370 unsigned int ending = starting + nterrains_;
00371 SDL_Surface* const screen = gui_.video().getSurface();
00372 if(ending > num_terrains()){
00373 ending = num_terrains();
00374 }
00375 const SDL_Rect &loc = location();
00376 int y = terrain_start_;
00377 for(unsigned int counter = starting; counter < ending; counter++){
00378 const t_translation::t_terrain terrain = terrains_[counter];
00379 const t_translation::t_terrain base_terrain = map_.get_terrain_info(terrain).default_base();
00380
00381 const int counter_from_zero = counter - starting;
00382 SDL_Rect dstrect;
00383 dstrect.x = loc.x + (counter_from_zero % size_specs_.terrain_width) * size_specs_.terrain_space;
00384 dstrect.y = y;
00385 dstrect.w = size_specs_.terrain_size;
00386 dstrect.h = size_specs_.terrain_size;
00387
00388
00389 if(base_terrain != t_translation::NONE_TERRAIN) {
00390 const std::string base_filename = "terrain/" + map_.get_terrain_info(base_terrain).editor_image() + ".png";
00391 surface base_image(image::get_image(base_filename));
00392
00393 if(base_image == NULL) {
00394 std::cerr << "image for terrain " << counter << ": '" << base_filename << "' not found\n";
00395 return;
00396 }
00397
00398 if(static_cast<unsigned>(base_image->w) != size_specs_.terrain_size ||
00399 static_cast<unsigned>(base_image->h) != size_specs_.terrain_size) {
00400
00401 base_image.assign(scale_surface(base_image,
00402 size_specs_.terrain_size, size_specs_.terrain_size));
00403 }
00404
00405 SDL_BlitSurface(base_image, NULL, screen, &dstrect);
00406 }
00407
00408 const std::string filename = "terrain/" + map_.get_terrain_info(terrain).editor_image() + ".png";
00409 surface image(image::get_image(filename));
00410 if(image == NULL) {
00411 std::cerr << "image for terrain " << counter << ": '" << filename << "' not found\n";
00412 return;
00413 }
00414
00415 if(static_cast<unsigned>(image->w) != size_specs_.terrain_size ||
00416 static_cast<unsigned>(image->h) != size_specs_.terrain_size) {
00417
00418 image.assign(scale_surface(image,
00419 size_specs_.terrain_size, size_specs_.terrain_size));
00420 }
00421
00422 SDL_BlitSurface(image, NULL, screen, &dstrect);
00423
00424 SDL_Surface* const screen = gui_.video().getSurface();
00425 Uint32 color;
00426 if (terrain == selected_bg_terrain() && terrain == selected_fg_terrain()) {
00427 color = SDL_MapRGB(screen->format,0xFF,0x00,0xFF);
00428 }
00429 else if (terrain == selected_bg_terrain()) {
00430 color = SDL_MapRGB(screen->format,0x00,0x00,0xFF);
00431 }
00432 else if (terrain == selected_fg_terrain()) {
00433 color = SDL_MapRGB(screen->format,0xFF,0x00,0x00);
00434 }
00435 else {
00436 color = SDL_MapRGB(screen->format,0x00,0x00,0x00);
00437 }
00438 draw_rectangle(dstrect.x, dstrect.y, image->w, image->h, color, screen);
00439 if (counter_from_zero % size_specs_.terrain_width == size_specs_.terrain_width - 1)
00440 y += size_specs_.terrain_space;
00441 }
00442 update_rect(loc);
00443 set_dirty(false);
00444 }
00445
00446 int terrain_palette::tile_selected(const int x, const int y) const {
00447 for(unsigned int i = 0; i != nterrains_; i++) {
00448 const int px = size_specs_.palette_x + (i % size_specs_.terrain_width) * size_specs_.terrain_space;
00449 const int py = terrain_start_ + (i / size_specs_.terrain_width) * size_specs_.terrain_space;
00450 const int pw = size_specs_.terrain_space;
00451 const int ph = size_specs_.terrain_space;
00452
00453 if(x > px && x < px + pw && y > py && y < py + ph) {
00454 return i;
00455 }
00456 }
00457 return -1;
00458 }
00459
00460 void terrain_palette::update_report() {
00461 const std::string msg = std::string(_("FG")) + ": "
00462 + get_terrain_string(selected_fg_terrain()) + "\n"
00463 + std::string(_("BG")) +
00464 ": " + get_terrain_string(selected_bg_terrain());
00465 gui_.set_report_content(reports::SELECTED_TERRAIN, msg);
00466 }
00467
00468 void terrain_palette::load_tooltips()
00469 {
00470 for(size_t i = 0; i < terrain_groups_.size(); ++i) {
00471 const std::string& text = terrain_groups_[i].name;
00472 if(text !="") {
00473 const SDL_Rect tooltip_rect = terrain_groups_[i].button.location();
00474 tooltips::add_tooltip(tooltip_rect, text);
00475 }
00476 }
00477 }
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 brush_bar::brush_bar(display &gui, const size_specs &sizes)
00488 : gui::widget(gui.video()), size_specs_(sizes), gui_(gui), selected_(0), total_brush_(3),
00489 size_(30) {
00490 adjust_size();
00491 }
00492
00493 void brush_bar::adjust_size() {
00494 set_location(size_specs_.brush_x, size_specs_.brush_y);
00495 set_measurements(size_ * total_brush_ + (total_brush_ - 1) * size_specs_.brush_padding, size_);
00496 set_dirty();
00497 }
00498
00499 unsigned int brush_bar::selected_brush_size() {
00500 return selected_ + 1;
00501 }
00502
00503 void brush_bar::select_brush_size(int new_size) {
00504 assert(new_size > 0 && new_size <= total_brush_);
00505 selected_ = new_size - 1;
00506 }
00507
00508 void brush_bar::left_mouse_click(const int mousex, const int mousey) {
00509 int index = selected_index(mousex, mousey);
00510 if(index >= 0) {
00511 if (static_cast<unsigned>(index) != selected_) {
00512 set_dirty();
00513 selected_ = index;
00514 }
00515 }
00516 }
00517
00518 void brush_bar::handle_event(const SDL_Event& event) {
00519 if (event.type == SDL_MOUSEMOTION) {
00520
00521 if (point_in_rect(event.button.x, event.button.y, location())) {
00522 if (!focus(&event)) {
00523 set_focus(true);
00524 }
00525 }
00526
00527 else {
00528 if (focus(&event)) {
00529 set_focus(false);
00530 }
00531 }
00532 }
00533 if (!focus(&event)) {
00534 return;
00535 }
00536 int mousex, mousey;
00537 SDL_GetMouseState(&mousex,&mousey);
00538 const SDL_MouseButtonEvent mouse_button_event = event.button;
00539 if (mouse_button_event.type == SDL_MOUSEBUTTONDOWN) {
00540 if (mouse_button_event.button == SDL_BUTTON_LEFT) {
00541 left_mouse_click(mousex, mousey);
00542 }
00543 }
00544 }
00545
00546 void brush_bar::draw() {
00547 draw(false);
00548 }
00549
00550 void brush_bar::draw(bool force) {
00551 if (!dirty() && !force) {
00552 return;
00553 }
00554 const SDL_Rect loc = location();
00555 int x = loc.x;
00556
00557
00558 SDL_Surface* const screen = gui_.video().getSurface();
00559 for (int i = 1; i <= total_brush_; i++) {
00560 std::stringstream filename;
00561 filename << "editor/brush-" << i << ".png";
00562 surface image(image::get_image(filename.str()));
00563 if (image == NULL) {
00564 std::cerr << "Image " << filename.str() << " not found." << std::endl;
00565 continue;
00566 }
00567 if (static_cast<unsigned>(image->w) != size_ ||
00568 static_cast<unsigned>(image->h) != size_) {
00569
00570 image.assign(scale_surface(image, size_, size_));
00571 }
00572 SDL_Rect dstrect;
00573 dstrect.x = x;
00574 dstrect.y = size_specs_.brush_y;
00575 dstrect.w = image->w;
00576 dstrect.h = image->h;
00577 SDL_BlitSurface(image, NULL, screen, &dstrect);
00578 const Uint32 color = static_cast<unsigned>(i) == selected_brush_size() ?
00579 SDL_MapRGB(screen->format,0xFF,0x00,0x00) :
00580 SDL_MapRGB(screen->format,0x00,0x00,0x00);
00581 draw_rectangle(dstrect.x, dstrect.y, image->w, image->h, color, screen);
00582 x += image->w + size_specs_.brush_padding;
00583 }
00584 update_rect(loc);
00585 set_dirty(false);
00586 }
00587
00588 int brush_bar::selected_index(const int x, const int y) const {
00589 const int bar_x = size_specs_.brush_x;
00590 const int bar_y = size_specs_.brush_y;
00591
00592 if ((x < bar_x || static_cast<unsigned>(x) > bar_x + size_ * total_brush_ +
00593 total_brush_ * size_specs_.brush_padding) ||
00594 (y < bar_y || static_cast<unsigned>(y) > bar_y + size_)) {
00595
00596 return -1;
00597 }
00598
00599 for(int i = 0; i < total_brush_; i++) {
00600 const int px = bar_x + size_ * i + i * size_specs_.brush_padding;
00601
00602 if(x >= px && static_cast<unsigned>(x) <= px + size_ &&
00603 y >= bar_y && static_cast<unsigned>(y) <= bar_y + size_) {
00604
00605 return i;
00606 }
00607 }
00608 return -1;
00609 }
00610
00611 }
00612