window.cpp

Go to the documentation of this file.
00001 /* $Id: window.cpp 26681 2008-05-18 06:05:59Z mordante $ */
00002 /*
00003    Copyright (C) 2007 - 2008 by Mark de Wever <koraq@xs4all.nl>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 //! @file window.cpp
00016 //! Implementation of window.hpp.
00017 
00018 #include "gui/widgets/window.hpp"
00019 
00020 #include "config.hpp"
00021 #include "cursor.hpp"
00022 #include "font.hpp"
00023 #include "log.hpp"
00024 #include "serialization/parser.hpp"
00025 #include "variable.hpp"
00026 #include "sdl_utils.hpp"
00027 
00028 #include <cassert>
00029 
00030 #define DBG_G LOG_STREAM_INDENT(debug, gui)
00031 #define LOG_G LOG_STREAM_INDENT(info, gui)
00032 #define WRN_G LOG_STREAM_INDENT(warn, gui)
00033 #define ERR_G LOG_STREAM_INDENT(err, gui)
00034 
00035 #define DBG_G_D LOG_STREAM_INDENT(debug, gui_draw)
00036 #define LOG_G_D LOG_STREAM_INDENT(info, gui_draw)
00037 #define WRN_G_D LOG_STREAM_INDENT(warn, gui_draw)
00038 #define ERR_G_D LOG_STREAM_INDENT(err, gui_draw)
00039 
00040 #define DBG_G_E LOG_STREAM_INDENT(debug, gui_event)
00041 #define LOG_G_E LOG_STREAM_INDENT(info, gui_event)
00042 #define WRN_G_E LOG_STREAM_INDENT(warn, gui_event)
00043 #define ERR_G_E LOG_STREAM_INDENT(err, gui_event)
00044 
00045 #define DBG_G_P LOG_STREAM_INDENT(debug, gui_parse)
00046 #define LOG_G_P LOG_STREAM_INDENT(info, gui_parse)
00047 #define WRN_G_P LOG_STREAM_INDENT(warn, gui_parse)
00048 #define ERR_G_P LOG_STREAM_INDENT(err, gui_parse)
00049 
00050 
00051 namespace gui2{
00052 
00053 twindow::twindow(CVideo& video, 
00054         const int x, const int y, const int w, const int h,
00055         const bool automatic_placement, 
00056         const unsigned horizontal_placement,
00057         const unsigned vertical_placement) :
00058     tpanel(),
00059     tevent_handler(),
00060     video_(video),
00061     status_(NEW),
00062     retval_(0),
00063     need_layout_(true),
00064     tooltip_(),
00065     help_popup_(),
00066     automatic_placement_(automatic_placement),
00067     horizontal_placement_(horizontal_placement),
00068     vertical_placement_(vertical_placement)
00069 {
00070     // We load the config in here as exception.
00071     load_config();
00072 
00073     set_size(::create_rect(x, y, w, h));
00074 
00075     tooltip_.set_definition("default");
00076     tooltip_.set_visible(false);
00077 
00078     help_popup_.set_definition("default");
00079     help_popup_.set_visible(false);
00080 }
00081 
00082 int twindow::show(const bool restore, void* /*flip_function*/)
00083 {
00084     log_scope2(gui_draw, "Window: show.");  
00085 
00086     assert(status_ == NEW);
00087 
00088     // We cut a piece of the screen and use that, that way all coordinates
00089     // are relative to the window.
00090     SDL_Rect rect = get_rect();
00091     surface restorer = get_surface_portion(video_.getSurface(), rect);
00092     surface screen;
00093 
00094     // Start our loop drawing will happen here as well.
00095     for(status_ = SHOWING; status_ != REQUEST_CLOSE; ) {
00096         process_events();
00097 
00098         if(status_ == REQUEST_CLOSE) {
00099             break;
00100         }
00101 
00102         if(dirty() || need_layout_) {
00103             if(need_layout_) {
00104                 screen = make_neutral_surface(restorer);
00105             }
00106             draw(screen);
00107         }
00108 
00109         // delay until it's our frame see display.ccp code for how to do that
00110         SDL_Delay(10);
00111         flip();
00112     }
00113 
00114     // restore area
00115     if(restore) {
00116         rect = get_rect();
00117         SDL_BlitSurface(restorer, 0, video_.getSurface(), &rect);
00118         update_rect(get_rect());
00119         flip();
00120     }
00121 
00122     return retval_;
00123 }
00124 
00125 void twindow::layout(const SDL_Rect position)
00126 {
00127     need_layout_ = false;
00128 
00129     DBG_G << "Window: layout area " << position.x
00130         << ',' << position.y << " x " << position.w 
00131         << ',' << position.h << ".\n";
00132 
00133     set_client_size(position); 
00134     need_layout_ = false;
00135 }
00136 
00137 //! Inherited from tpanel.
00138 void twindow::draw(surface& surface)
00139 {
00140     const bool draw_foreground = need_layout_;
00141     if(need_layout_) {
00142         DBG_G << "Window: layout client area.\n";
00143         layout(get_client_rect());
00144 
00145         canvas(0).draw();
00146         blit_surface(canvas(0).surf(), 0, surface, 0);
00147     }
00148     
00149     for(tgrid::iterator itor = begin(); itor != end(); ++itor) {
00150         if(! *itor || !itor->dirty()) {
00151             continue;
00152         }
00153 
00154         log_scope2(gui_draw, "Window: draw child.");
00155 
00156         itor->draw(surface);
00157     }
00158     if(draw_foreground) {
00159         canvas(1).draw();
00160         blit_surface(canvas(1).surf(), 0, surface, 0);
00161     }
00162     if(tooltip_.dirty()) {
00163         tooltip_.draw(surface);
00164     }
00165     if(help_popup_.dirty()) {
00166         help_popup_.draw(surface);
00167     }
00168 
00169     SDL_Rect rect = get_rect();
00170     SDL_BlitSurface(surface, 0, video_.getSurface(), &rect);
00171     update_rect(get_rect());
00172     set_dirty(false);
00173 }
00174 
00175 void twindow::flip()
00176 {
00177     // fixme we need to add the option to either call
00178     // video_.flip() or display.flip()
00179     
00180     const surface frameBuffer = get_video_surface();
00181     
00182     cursor::draw(frameBuffer);
00183     video_.flip();
00184     cursor::undraw(frameBuffer);
00185 }
00186 
00187 void twindow::window_resize(tevent_handler&, 
00188         const unsigned new_width, const unsigned new_height)
00189 {
00190     settings::screen_width = new_width;
00191     settings::screen_height = new_height;
00192     need_layout_ = true;
00193 }
00194 
00195 SDL_Rect twindow::get_client_rect() const
00196 {
00197     const twindow_definition::tresolution* conf = dynamic_cast<const twindow_definition::tresolution*>(config());
00198     assert(conf);
00199 
00200     SDL_Rect result = get_rect();
00201     result.x = conf->left_border;
00202     result.y = conf->top_border;
00203     result.w -= conf->left_border + conf->right_border;
00204     result.h -= conf->top_border + conf->bottom_border;
00205 
00206     // FIXME validate for an available client area.
00207     
00208     return result;
00209 
00210 }
00211 
00212 void twindow::recalculate_size()
00213 {
00214     if(automatic_placement_) {
00215         
00216         tpoint size = get_best_size();
00217         size.x = size.x < settings::screen_width ? size.x : settings::screen_width;
00218         size.y = size.y < settings::screen_height ? size.y : settings::screen_height;
00219 
00220         tpoint position(0, 0);
00221         switch(horizontal_placement_) {
00222             case tgrid::HORIZONTAL_ALIGN_LEFT :
00223                 // Do nothing
00224                 break;
00225             case tgrid::HORIZONTAL_ALIGN_CENTER :
00226                 position.x = (settings::screen_width - size.x) / 2;
00227                 break;
00228             case tgrid::HORIZONTAL_ALIGN_RIGHT :
00229                 position.x = settings::screen_width - size.x;
00230                 break;
00231             default :
00232                 assert(false);
00233         }
00234         switch(vertical_placement_) {
00235             case tgrid::VERTICAL_ALIGN_TOP :
00236                 // Do nothing
00237                 break;
00238             case tgrid::VERTICAL_ALIGN_CENTER :
00239                 position.y = (settings::screen_height - size.y) / 2;
00240                 break;
00241             case tgrid::VERTICAL_ALIGN_BOTTOM :
00242                 position.y = settings::screen_height - size.y;
00243                 break;
00244             default :
00245                 assert(false);
00246         }
00247 
00248         set_size(create_rect(position, size));
00249     }
00250 }
00251 
00252 void twindow::do_show_tooltip(const tpoint& location, const t_string& tooltip)
00253 {
00254     DBG_G << "Showing tooltip message: '" << tooltip << "'.\n";
00255 
00256     assert(!tooltip.empty());
00257 
00258     twidget* widget = find_widget(location, true);
00259     assert(widget);
00260     
00261     const SDL_Rect widget_rect = widget->get_rect();
00262     const SDL_Rect client_rect = get_client_rect();
00263 
00264     tooltip_.set_label(tooltip);
00265     const tpoint size = tooltip_.get_best_size();
00266 
00267     SDL_Rect tooltip_rect = {0, 0, size.x, size.y};
00268 
00269     // Find the best position to place the widget
00270     if(widget_rect.y - size.y > 0) {
00271         // put above
00272         tooltip_rect.y = widget_rect.y - size.y;
00273     } else {
00274         //put below no test
00275         tooltip_rect.y = widget_rect.y + widget_rect.h;
00276     }
00277 
00278     if(widget_rect.x + size.x < client_rect.w) {
00279         // Directly above the mouse
00280         tooltip_rect.x = widget_rect.x;
00281     } else {
00282         // shift left, no test
00283         tooltip_rect.x = client_rect.w - size.x;
00284     }
00285 
00286     tooltip_.set_size(tooltip_rect);
00287     tooltip_.set_visible();
00288 }
00289 
00290 void twindow::do_show_help_popup(const tpoint& location, const t_string& help_popup)
00291 {
00292     // Note copy past of twindow::do_show_tooltip except that the help may be empty.
00293     DBG_G << "Showing help message: '" << help_popup << "'.\n";
00294 
00295     if(help_popup.empty()) {
00296         return;
00297     }
00298     twidget* widget = find_widget(location, true);
00299     assert(widget);
00300     
00301     const SDL_Rect widget_rect = widget->get_rect();
00302     const SDL_Rect client_rect = get_client_rect();
00303 
00304     help_popup_.set_label(help_popup);
00305     const tpoint size = help_popup_.get_best_size();
00306 
00307     SDL_Rect help_popup_rect = {0, 0, size.x, size.y};
00308 
00309     // Find the best position to place the widget
00310     if(widget_rect.y - size.y > 0) {
00311         // put above
00312         help_popup_rect.y = widget_rect.y - size.y;
00313     } else {
00314         //put below no test
00315         help_popup_rect.y = widget_rect.y + widget_rect.h;
00316     }
00317 
00318     if(widget_rect.x + size.x < client_rect.w) {
00319         // Directly above the mouse
00320         help_popup_rect.x = widget_rect.x;
00321     } else {
00322         // shift left, no test
00323         help_popup_rect.x = client_rect.w - size.x;
00324     }
00325 
00326     help_popup_.set_size(help_popup_rect);
00327     help_popup_.set_visible();
00328 }
00329 
00330 } // namespace gui2
00331 

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs