diff --git a/src/gui/core/canvas.cpp b/src/gui/core/canvas.cpp index d4adc4b57fb..0b83b69e010 100644 --- a/src/gui/core/canvas.cpp +++ b/src/gui/core/canvas.cpp @@ -57,10 +57,7 @@ line_shape::line_shape(const config& cfg) } } -void line_shape::draw( - const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) +void line_shape::draw(wfl::map_formula_callable& variables) { /** * @todo formulas are now recalculated every draw cycle which is a bit silly @@ -68,69 +65,18 @@ void line_shape::draw( * flag or do the calculation in a separate routine. */ - const unsigned x1 = draw_location.x + x1_(variables) - portion_to_draw.x; - const unsigned y1 = draw_location.y + y1_(variables) - portion_to_draw.y; - const unsigned x2 = draw_location.x + x2_(variables) - portion_to_draw.x; - const unsigned y2 = draw_location.y + y2_(variables) - portion_to_draw.y; + const unsigned x1 = x1_(variables); + const unsigned y1 = y1_(variables); + const unsigned x2 = x2_(variables); + const unsigned y2 = y2_(variables); - DBG_GUI_D << "Line: draw from " << x1 << ',' << y1 << " to " << x2 << ',' << y2 - << " within bounds {" << portion_to_draw.x << ", " << portion_to_draw.y - << ", " << portion_to_draw.w << ", " << portion_to_draw.h << "}.\n"; + DBG_GUI_D << "Line: draw from " << x1 << ',' << y1 << " to " << x2 << ',' << y2 << ".\n"; // @todo FIXME respect the thickness. draw::line(x1, y1, x2, y2, color_(variables)); } -/***** ***** ***** Base class for rectangular shapes ***** ***** *****/ - -rect_bounded_shape::rect_bounded_shape(const config& cfg) - : shape(cfg) - , x_(cfg["x"]) - , y_(cfg["y"]) - , w_(cfg["w"]) - , h_(cfg["h"]) -{ -} - -rect_bounded_shape::calculated_rects rect_bounded_shape::calculate_rects(const SDL_Rect& view_bounds, wfl::map_formula_callable& variables) const -{ - // Formulas are recalculated every draw cycle, even if there hasn't been a resize. - - const unsigned x = x_(variables); - const unsigned y = y_(variables); - const unsigned w = w_(variables); - const unsigned h = h_(variables); - - const auto dst_on_widget = sdl::create_rect(x, y, w, h); - - SDL_Rect clip_on_widget; - if(!SDL_IntersectRect(&dst_on_widget, &view_bounds, &clip_on_widget)) { - DBG_GUI_D << "Text: Clipping view_bounds resulted in an empty intersection, nothing to do.\n"; - return {true, dst_on_widget, {}, {}, {}, {}}; - } - - auto unclipped_around_viewport = dst_on_widget; - unclipped_around_viewport.x -= view_bounds.x; - unclipped_around_viewport.y -= view_bounds.y; - - auto clip_in_shape = clip_on_widget; - clip_in_shape.x -= x; - clip_in_shape.y -= y; - - auto dst_in_viewport = clip_on_widget; - dst_in_viewport.x -= view_bounds.x; - dst_in_viewport.y -= view_bounds.y; - - DBG_GUI_D << "Calculate_rects: from " << x << ',' << y << " width " << w << " height " << h << "\n" - << " view_bounds {" << view_bounds.x << ", " << view_bounds.y << ", " - << view_bounds.w << ", " << view_bounds.h << "}.\n" - << " dst_in_viewport {" << dst_in_viewport.x << ", " << dst_in_viewport.y << ", " - << dst_in_viewport.w << ", " << dst_in_viewport.h << "}.\n"; - - return {false, dst_on_widget, clip_on_widget, clip_in_shape, unclipped_around_viewport, dst_in_viewport}; -} - /***** ***** ***** ***** ***** Rectangle ***** ***** ***** ***** *****/ rectangle_shape::rectangle_shape(const config& cfg) @@ -150,49 +96,43 @@ rectangle_shape::rectangle_shape(const config& cfg) } } -void rectangle_shape::draw( - const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) +void rectangle_shape::draw(wfl::map_formula_callable& variables) { - const auto rects = calculate_rects(portion_to_draw, variables); - if(rects.empty) { - DBG_GUI_D << "Rectangle: nothing to draw" << std::endl; - return; - } + const int x = x_(variables); + const int y = y_(variables); + const int w = w_(variables); + const int h = h_(variables); const color_t fill_color = fill_color_(variables); - const color_t border_color = border_color_(variables); - SDL_Rect r = rects.unclipped_around_viewport; - r.x += draw_location.x; - r.y += draw_location.y; - - DBG_GUI_D << "Rectangle: draw at " << r - << " with bounds " << portion_to_draw << std::endl; // Fill the background, if applicable if(!fill_color.null()) { DBG_GUI_D << "fill " << fill_color << std::endl; draw::set_color(fill_color); - SDL_Rect area = r; - area.x += border_thickness_; - area.y += border_thickness_; - area.w -= 2 * border_thickness_; - area.h -= 2 * border_thickness_; + + const SDL_Rect area { + x + border_thickness_, + y + border_thickness_, + w - (border_thickness_ * 2), + h - (border_thickness_ * 2) + }; draw::fill(area); } + const color_t border_color = border_color_(variables); + // Draw the border draw::set_color(border_color); DBG_GUI_D << "border thickness " << border_thickness_ << ", colour " << border_color << std::endl; for(int i = 0; i < border_thickness_; ++i) { - SDL_Rect dimensions = r; - dimensions.x += i; - dimensions.y += i; - dimensions.w -= 2 * i; - dimensions.h -= 2 * i; + const SDL_Rect dimensions { + x + i, + y + i, + w - (i * 2), + h - (i * 2) + }; draw::rect(dimensions); } @@ -218,23 +158,15 @@ round_rectangle_shape::round_rectangle_shape(const config& cfg) } } -void round_rectangle_shape::draw( - const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) +void round_rectangle_shape::draw(wfl::map_formula_callable& variables) { - // TODO: highdpi - need to double check this - const auto rects = calculate_rects(portion_to_draw, variables); - const int x = draw_location.x + rects.unclipped_around_viewport.x; - const int y = draw_location.y + rects.unclipped_around_viewport.y; - const int w = rects.unclipped_around_viewport.w; - const int h = rects.unclipped_around_viewport.h; + const int x = x_(variables); + const int y = y_(variables); + const int w = w_(variables); + const int h = h_(variables); const int r = r_(variables); - DBG_GUI_D << "Rounded Rectangle: draw from " << x << ',' << y << " width " << w - << " height " - << " within bounds {" << portion_to_draw.x << ", " << portion_to_draw.y - << ", " << portion_to_draw.w << ", " << portion_to_draw.h << "}.\n"; + DBG_GUI_D << "Rounded Rectangle: draw from " << x << ',' << y << " width " << w << " height " << h << ".\n"; const color_t fill_color = fill_color_(variables); @@ -256,6 +188,7 @@ void round_rectangle_shape::draw( // Draw the border draw::set_color(border_color); + for(int i = 0; i < border_thickness_; ++i) { draw::line(x + r, y + i, x + w - r, y + i); draw::line(x + r, y + h - i, x + w - r, y + h - i); @@ -287,10 +220,7 @@ circle_shape::circle_shape(const config& cfg) } } -void circle_shape::draw( - const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) +void circle_shape::draw(wfl::map_formula_callable& variables) { /** * @todo formulas are now recalculated every draw cycle which is a bit @@ -298,13 +228,11 @@ void circle_shape::draw( * extra flag or do the calculation in a separate routine. */ - const int x = draw_location.x + x_(variables) - portion_to_draw.x; - const int y = draw_location.y + y_(variables) - portion_to_draw.y; + const int x = x_(variables); + const int y = y_(variables); const unsigned radius = radius_(variables); - DBG_GUI_D << "Circle: drawn at " << x << ',' << y << " radius " << radius - << " within bounds {" << portion_to_draw.x << ", " << portion_to_draw.y - << ", " << portion_to_draw.w << ", " << portion_to_draw.h << "}.\n"; + DBG_GUI_D << "Circle: drawn at " << x << ',' << y << " radius " << radius << ".\n"; const color_t fill_color = fill_color_(variables); if(!fill_color.null() && radius) { @@ -347,10 +275,7 @@ void image_shape::dimension_validation(unsigned value, const std::string& name, ); } -void image_shape::draw( - const SDL_Rect& /*portion_to_draw*/, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) +void image_shape::draw(wfl::map_formula_callable& variables) { DBG_GUI_D << "Image: draw.\n"; @@ -406,33 +331,24 @@ void image_shape::draw( local_variables.add("clip_y", wfl::variant(clip_y)); // Execute the provided actions for this context. - wfl::variant(variables.fake_ptr()) - .execute_variant(actions_formula_.evaluate(local_variables)); + wfl::variant(variables.fake_ptr()).execute_variant(actions_formula_.evaluate(local_variables)); // If w or h is 0, assume it means the whole image. if (!w) { w = tex.w(); } if (!h) { h = tex.h(); } - // The image is to be placed at (x,y,w,h) in widget space. - int x = clip_x; - int y = clip_y; - // Convert this to draw space. - x += draw_location.x; - y += draw_location.y; - const SDL_Rect adjusted_draw_loc{x, y, w, h}; - - // TODO: highdpi - clipping? + const SDL_Rect dst_rect { static_cast(clip_x), static_cast(clip_y), w, h }; // What to do with the image depends on whether we need to tile it or not. - switch (resize_mode_) { - case (resize_mode::tile): - draw::tiled(tex, adjusted_draw_loc, false, mirror_(variables)); + switch(resize_mode_) { + case resize_mode::tile: + draw::tiled(tex, dst_rect, false, mirror_(variables)); break; - case (resize_mode::tile_center): - draw::tiled(tex, adjusted_draw_loc, true, mirror_(variables)); + case resize_mode::tile_center: + draw::tiled(tex, dst_rect, true, mirror_(variables)); break; case resize_mode::tile_highres: - draw::tiled_highres(tex, adjusted_draw_loc, false, mirror_(variables)); + draw::tiled_highres(tex, dst_rect, false, mirror_(variables)); break; case resize_mode::stretch: // Stretching is identical to scaling in terms of handling. @@ -442,9 +358,9 @@ void image_shape::draw( // Handling is otherwise identical to sharp scaling. case resize_mode::scale_sharp: if(mirror_(variables)) { - draw::flipped(tex, adjusted_draw_loc); + draw::flipped(tex, dst_rect); } else { - draw::blit(tex, adjusted_draw_loc); + draw::blit(tex, dst_rect); } break; default: @@ -467,8 +383,7 @@ image_shape::resize_mode image_shape::get_resize_mode(const std::string& resize_ return resize_mode::scale_sharp; } else { if(!resize_mode.empty() && resize_mode != "scale") { - ERR_GUI_E << "Invalid resize mode '" << resize_mode - << "' falling back to 'scale'.\n"; + ERR_GUI_E << "Invalid resize mode '" << resize_mode << "' falling back to 'scale'.\n"; } return resize_mode::scale; } @@ -501,10 +416,7 @@ text_shape::text_shape(const config& cfg) } } -void text_shape::draw( - const SDL_Rect& area_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) +void text_shape::draw(wfl::map_formula_callable& variables) { assert(variables.has_key("text")); @@ -525,7 +437,6 @@ void text_shape::draw( .set_link_color(link_color_(variables)) .set_text(text, text_markup_(variables)); - // TODO: highdpi - determine how the font interface should work. Probably the way it is used here is fine. But the pixel scaling could theoretically be abstracted. text_renderer.set_family_class(font_family_) .set_font_size(font_size_(variables)) .set_font_style(font_style_) @@ -545,16 +456,22 @@ void text_shape::draw( local_variables.add("text_width", wfl::variant(tw)); local_variables.add("text_height", wfl::variant(th)); - const auto rects = calculate_rects(area_to_draw, local_variables); + const int x = x_(local_variables); + const int y = y_(local_variables); + const int w = w_(local_variables); + const int h = h_(local_variables); + SDL_Rect dst_rect{x, y, w, h}; - if(rects.empty) { - DBG_GUI_D << "Text: Clipping to area_to_draw resulted in an empty intersection, nothing to do.\n"; - return; - } + // Get the visible portion of text. + SDL_Rect visible = sdl::intersect_rects(draw::get_clip(), dst_rect); + + // Get the source region of text for clipping. + SDL_Rect clip_in = visible; + clip_in.x -= x; + clip_in.y -= y; // Source region for high-dpi text needs to have pixel scale applied. const int pixel_scale = CVideo::get_singleton().get_pixel_scale(); - SDL_Rect clip_in = rects.clip_in_shape; clip_in.x *= pixel_scale; clip_in.y *= pixel_scale; clip_in.w *= pixel_scale; @@ -568,15 +485,8 @@ void text_shape::draw( return; } - // Final output - place clipped texture appropriately - SDL_Rect text_draw_location = draw_location; - text_draw_location.x += rects.dst_in_viewport.x; - text_draw_location.x += rects.clip_in_shape.x; - text_draw_location.y += rects.dst_in_viewport.y; - text_draw_location.y += rects.clip_in_shape.y; - text_draw_location.w = rects.dst_in_viewport.w; - text_draw_location.h = rects.dst_in_viewport.h; - draw::blit(tex, text_draw_location); + // TODO: highdpi - this /should/ be fine. But, in some cases (Credits) the maximum viewport height is exceeded. This is bad, but at least it shows something and doesn't crash. + draw::blit(tex, visible); } /***** ***** ***** ***** ***** CANVAS ***** ***** ***** ***** *****/ @@ -601,28 +511,7 @@ canvas::canvas(canvas&& c) noexcept { } -// TODO: highdpi - draw location specification needs to be completely reworked -void canvas::draw(const SDL_Rect& area_to_draw, const SDL_Rect& draw_location) -{ - log_scope2(log_gui_draw, "Canvas: drawing."); - - // TODO: highdpi - clipping? - - // Draw background. - if (blur_depth_ && blur_texture_) { - draw::blit(blur_texture_, draw_location, area_to_draw); - } - - // draw items - for(auto& shape : shapes_) { - lg::scope_logger inner_scope_logging_object__(log_gui_draw, "Canvas: draw shape."); - - // TODO: highdpi - check if child routines benefit from knowing area_to_draw - shape->draw(area_to_draw, draw_location, variables_); - } -} - -void canvas::blit(SDL_Rect rect) +void canvas::draw() { // This early-return has to come before the `validate(rect.w <= w_)` check, as during the boost_unit_tests execution // the debug_clock widget will have no shapes, 0x0 size, yet be given a larger rect to draw. @@ -631,43 +520,26 @@ void canvas::blit(SDL_Rect rect) return; } - CVideo& video = CVideo::get_singleton(); - - VALIDATE(rect.w >= 0 && rect.h >= 0, _("Area to draw has negative size")); - VALIDATE(static_cast(rect.w) <= w_ && static_cast(rect.h) <= h_, - _("Area to draw is larger than widget size")); - - // If the widget is partly off-screen, this might get called with - // surf width=1000, height=1000 - // rect={-1, 2, 330, 440} - // - // From those, as the first column is off-screen: - // rect_clipped_to_parent={0, 2, 329, 440} - // area_to_draw={1, 0, 329, 440} - SDL_Rect parent {0, 0, video.draw_area().w, video.draw_area().h}; - SDL_Rect rect_clipped_to_parent; - if(!SDL_IntersectRect(&rect, &parent, &rect_clipped_to_parent)) { - DBG_GUI_D << "Area to draw is completely outside parent.\n"; - return; - } // TODO: highdpi - it is assumed this will never move after blit if(blur_depth_ && !blur_texture_) { // Cache a blurred image of whatever is underneath. - surface s = video.read_pixels_low_res(&rect); + SDL_Rect rect = draw::get_viewport(); + surface s = CVideo::get_singleton().read_pixels_low_res(&rect); s = blur_surface(s, blur_depth_); blur_texture_ = texture(s); } - SDL_Rect area_to_draw { - std::max(0, -rect.x), - std::max(0, -rect.y), - rect_clipped_to_parent.w, - rect_clipped_to_parent.h - }; + // Draw blurred background. + // TODO: highdpi - this should be able to be removed at some point with shaders + if(blur_depth_ && blur_texture_) { + draw::blit(blur_texture_); + } - // `area_to_draw` is the portion of the widget to render, - // `rect` is the offset to render at. - draw(area_to_draw, rect); + // Draw items + for(auto& shape : shapes_) { + const lg::scope_logger inner_scope_logging_object__{log_gui_draw, "Canvas: draw shape."}; + shape->draw(variables_); + } } void canvas::parse_cfg(const config& cfg) diff --git a/src/gui/core/canvas.hpp b/src/gui/core/canvas.hpp index 0acaf599413..6506d39840d 100644 --- a/src/gui/core/canvas.hpp +++ b/src/gui/core/canvas.hpp @@ -63,15 +63,11 @@ public: /** * Draws the canvas. * - * @param portion_to_draw The portion of the shape to draw, in canvas-local coordinates - * @param draw_location The location of the canvas on the screen, in draw coordinates. * @param variables The canvas can have formulas in it's * definition, this parameter contains the values * for these formulas. */ - virtual void draw(const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) = 0; + virtual void draw(wfl::map_formula_callable& variables) = 0; bool immutable() const { @@ -91,26 +87,13 @@ public: canvas& operator=(const canvas&) = delete; canvas(canvas&& c) noexcept; - private: - /** - * Internal part of the blit() function - does the actual drawing. - * - * @param area_to_draw Currently-visible part of the widget, in widget-local coordinates. - * Any area outside here won't be blitted to the parent. - * @param draw_location Where to draw the widget on the screen, in draw coordinates. - */ - void draw(const SDL_Rect& area_to_draw, const SDL_Rect& draw_location); - - public: /** * Draw the canvas' shapes onto the screen. * * It makes sure the image on the canvas is up to date. Also executes the * pre-blitting functions. - * - * @param rect Where to blit to, in drawing coordinates. */ - void blit(SDL_Rect rect); + void draw(); /** * Sets the config. diff --git a/src/gui/core/canvas_private.hpp b/src/gui/core/canvas_private.hpp index d005eaf415b..fec4715f0c0 100644 --- a/src/gui/core/canvas_private.hpp +++ b/src/gui/core/canvas_private.hpp @@ -16,8 +16,8 @@ #include "gui/core/canvas.hpp" #include "gui/auxiliary/typed_formula.hpp" -namespace gui2 { - +namespace gui2 +{ /** * @ingroup GUICanvasWML * @@ -68,7 +68,8 @@ namespace gui2 { * * Drawing outside this area will result in unpredictable results including crashing. (That should be fixed, when encountered.) */ -class line_shape : public canvas::shape { +class line_shape : public canvas::shape +{ public: /** * Constructor. @@ -77,15 +78,13 @@ public: */ explicit line_shape(const config& cfg); - void draw(const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) override; + void draw(wfl::map_formula_callable& variables) override; private: - typed_formula x1_, /**< The start x coordinate of the line. */ - y1_, /**< The start y coordinate of the line. */ - x2_, /**< The end x coordinate of the line. */ - y2_; /**< The end y coordinate of the line. */ + typed_formula x1_; /**< The start x coordinate of the line. */ + typed_formula y1_; /**< The start y coordinate of the line. */ + typed_formula x2_; /**< The end x coordinate of the line. */ + typed_formula y2_; /**< The end y coordinate of the line. */ /** The color of the line. */ typed_formula color_; @@ -114,48 +113,23 @@ private: * w | @ref guivartype_f_unsigned "f_unsigned"|0 |The width of the rectangle. * h | @ref guivartype_f_unsigned "f_unsigned"|0 |The height of the rectangle. */ -class rect_bounded_shape : public canvas::shape { +class rect_bounded_shape : public canvas::shape +{ protected: /** * Constructor. * * @param cfg The config object to define the rectangle. */ - explicit rect_bounded_shape(const config& cfg); + explicit rect_bounded_shape(const config& cfg) + : shape(cfg) + , x_(cfg["x"]) + , y_(cfg["y"]) + , w_(cfg["w"]) + , h_(cfg["h"]) + { + } - /** - * Where to draw, calculated from the x,y,w,h formulas but with different reference points used - * as the origin of the co-ordinate system. - */ - struct calculated_rects { - /** - * True if there was no intersection between dst_on_widget and the viewport. If true, the - * data in the SDL_Rects must be ignored. - */ - bool empty; - /** In the co-ordinate system that the WML uses, and unaffected by the view_bounds */ - SDL_Rect dst_on_widget; - /** Intersection of dst_on_widget with view_bounds, in the co-ordinate system that the WML uses. */ - SDL_Rect clip_on_widget; - /** - * Intersection of view_bounds with the shape, in co-ordinates with the shape's top-left at - * (0,0). For a text_shape, this co-ordinate system corresponds to the co-ordinates of the - * Cairo surface that Pango draws on. - */ - SDL_Rect clip_in_shape; - /** - * Translation of dst_on_widget to the viewport's co-ordinates. Here (0,0) corresponds to - * view_bounds's top-left. Will often have negative values for x and y, and widths or - * heights larger than the viewport's size. - */ - SDL_Rect unclipped_around_viewport; - /** Where to draw, in the co-ordinates of the viewport, and restricted to the view_bounds. */ - SDL_Rect dst_in_viewport; - }; - - calculated_rects calculate_rects(const SDL_Rect& view_bounds, wfl::map_formula_callable& variables) const; - -private: typed_formula x_; /**< The x coordinate of the rectangle. */ typed_formula y_; /**< The y coordinate of the rectangle. */ typed_formula w_; /**< The width of the rectangle. */ @@ -179,7 +153,8 @@ private: * * Variables: see line_shape */ -class rectangle_shape : public rect_bounded_shape { +class rectangle_shape : public rect_bounded_shape +{ public: /** * Constructor. @@ -188,9 +163,7 @@ public: */ explicit rectangle_shape(const config& cfg); - void draw(const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) override; + void draw(wfl::map_formula_callable& variables) override; private: /** @@ -229,7 +202,8 @@ private: * fill_color | @ref guivartype_color "color" |"" |The color of the interior; if omitted it's not drawn. * debug | @ref guivartype_string "string" |"" |Debug message to show upon creation; this message is not stored. */ -class round_rectangle_shape : public rect_bounded_shape { +class round_rectangle_shape : public rect_bounded_shape +{ public: /** * Constructor. @@ -238,9 +212,7 @@ public: */ explicit round_rectangle_shape(const config& cfg); - void draw(const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) override; + void draw(wfl::map_formula_callable& variables) override; private: typed_formula r_; /**< The radius of the corners. */ @@ -287,7 +259,8 @@ private: * * Drawing outside the area will result in unpredictable results including crashing. (That should be fixed, when encountered.) */ -class circle_shape : public canvas::shape { +class circle_shape : public canvas::shape +{ public: /** * Constructor. @@ -296,17 +269,20 @@ public: */ explicit circle_shape(const config& cfg); - void draw(const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) override; + void draw( wfl::map_formula_callable& variables) override; private: - typed_formula x_, /**< The center x coordinate of the circle. */ - y_, /**< The center y coordinate of the circle. */ - radius_; /**< The radius of the circle. */ + typed_formula x_; /**< The center x coordinate of the circle. */ + typed_formula y_; /**< The center y coordinate of the circle. */ + + /** The radius of the circle. */ + typed_formula radius_; /** The border color of the circle. */ - typed_formula border_color_, fill_color_; /**< The fill color of the circle. */ + typed_formula border_color_; + + /** The fill color of the circle. */ + typed_formula fill_color_; /** The border thickness of the circle. */ unsigned int border_thickness_; @@ -337,7 +313,8 @@ private: * * Also the general variables are available, see line_shape */ -class image_shape : public canvas::shape { +class image_shape : public canvas::shape +{ public: /** * Constructor. @@ -347,15 +324,13 @@ public: */ image_shape(const config& cfg, wfl::action_function_symbol_table& functions); - void draw(const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) override; + void draw(wfl::map_formula_callable& variables) override; private: - typed_formula x_, /**< The x coordinate of the image. */ - y_, /**< The y coordinate of the image. */ - w_, /**< The width of the image. */ - h_; /**< The height of the image. */ + typed_formula x_; /**< The x coordinate of the image. */ + typed_formula y_; /**< The y coordinate of the image. */ + typed_formula w_; /**< The width of the image. */ + typed_formula h_; /**< The height of the image. */ // TODO: highdpi - none of these cached items are ever used. Why is this here? @@ -432,7 +407,8 @@ private: * text_height | @ref guivartype_unsigned "unsigned" |The height of the rendered text. * Also the general variables are available, see line_shape */ -class text_shape : public rect_bounded_shape { +class text_shape : public rect_bounded_shape +{ public: /** * Constructor. @@ -441,9 +417,7 @@ public: */ explicit text_shape(const config& cfg); - void draw(const SDL_Rect& portion_to_draw, - const SDL_Rect& draw_location, - wfl::map_formula_callable& variables) override; + void draw(wfl::map_formula_callable& variables) override; private: /** The text font family. */ diff --git a/src/gui/widgets/panel.cpp b/src/gui/widgets/panel.cpp index f08b1e9196b..99feef6b75e 100644 --- a/src/gui/widgets/panel.cpp +++ b/src/gui/widgets/panel.cpp @@ -65,18 +65,16 @@ unsigned panel::get_state() const return 0; } -void panel::impl_draw_background(int x_offset, int y_offset) +void panel::impl_draw_background(int /*x_offset*/, int /*y_offset*/) { DBG_GUI_D << LOG_HEADER << " size " << get_rectangle() << ".\n"; - - get_canvas(0).blit(calculate_blitting_rectangle(x_offset, y_offset)); + get_canvas(0).draw(); } -void panel::impl_draw_foreground(int x_offset, int y_offset) +void panel::impl_draw_foreground(int /*x_offset*/, int /*y_offset*/) { DBG_GUI_D << LOG_HEADER << " size " << get_rectangle() << ".\n"; - - get_canvas(1).blit(calculate_blitting_rectangle(x_offset, y_offset)); + get_canvas(1).draw(); } point panel::border_space() const diff --git a/src/gui/widgets/styled_widget.cpp b/src/gui/widgets/styled_widget.cpp index a50a93574eb..7c5fb0513f5 100644 --- a/src/gui/widgets/styled_widget.cpp +++ b/src/gui/widgets/styled_widget.cpp @@ -431,12 +431,12 @@ int styled_widget::get_text_maximum_height() const return get_height() - config_->text_extra_height; } -void styled_widget::impl_draw_background(int x_offset, int y_offset) +void styled_widget::impl_draw_background(int /*x_offset*/, int /*y_offset*/) { DBG_GUI_D << LOG_HEADER << " label '" << debug_truncate(label_) << "' size " << get_rectangle() << ".\n"; - get_canvas(get_state()).blit(calculate_blitting_rectangle(x_offset, y_offset)); + get_canvas(get_state()).draw(); } void styled_widget::impl_draw_foreground(int /*x_offset*/, int /*y_offset*/) diff --git a/src/gui/widgets/widget.cpp b/src/gui/widgets/widget.cpp index 1cf8a9de1fc..81c08811687 100644 --- a/src/gui/widgets/widget.cpp +++ b/src/gui/widgets/widget.cpp @@ -351,8 +351,7 @@ void widget::set_linked_group(const std::string& linked_group) /***** ***** ***** ***** Drawing functions. ***** ***** ***** *****/ -SDL_Rect widget::calculate_blitting_rectangle(const int x_offset, - const int y_offset) +SDL_Rect widget::calculate_blitting_rectangle(const int x_offset, const int y_offset) const { SDL_Rect result = get_rectangle(); result.x += x_offset; @@ -360,10 +359,19 @@ SDL_Rect widget::calculate_blitting_rectangle(const int x_offset, return result; } -SDL_Rect widget::calculate_clipping_rectangle(const int x_offset, - const int y_offset) +SDL_Rect widget::calculate_clipping_rectangle(const int x_offset, const int y_offset) const { - SDL_Rect result = clipping_rectangle_; + SDL_Rect result; + switch(get_drawing_action()) { + case redraw_action::none: + return sdl::empty_rect; + case redraw_action::partly: + result = clipping_rectangle_; + break; + case redraw_action::full: + result = get_rectangle(); + break; + } result.x += x_offset; result.y += y_offset; return result; @@ -373,44 +381,52 @@ void widget::draw_background(int x_offset, int y_offset) { assert(visible_ == visibility::visible); - if(redraw_action_ == redraw_action::partly) { - const SDL_Rect clipping_rectangle - = calculate_clipping_rectangle(x_offset, y_offset); - auto clipper = draw::set_clip(clipping_rectangle); - draw_debug_border(x_offset, y_offset); - impl_draw_background(x_offset, y_offset); - } else { - draw_debug_border(x_offset, y_offset); - impl_draw_background(x_offset, y_offset); + if(get_drawing_action() == redraw_action::none) { + return; } + + SDL_Rect dest = calculate_blitting_rectangle(x_offset, y_offset); + SDL_Rect clip = calculate_clipping_rectangle(x_offset, y_offset); + clip.x -= dest.x; clip.y -= dest.y; + auto view_setter = draw::set_viewport(dest); + auto clip_setter = draw::reduce_clip(clip); + + draw_debug_border(x_offset, y_offset); + impl_draw_background(x_offset, y_offset); } void widget::draw_children(int x_offset, int y_offset) { assert(visible_ == visibility::visible); - if(redraw_action_ == redraw_action::partly) { - const SDL_Rect clipping_rectangle - = calculate_clipping_rectangle(x_offset, y_offset); - auto clipper = draw::set_clip(clipping_rectangle); - impl_draw_children(x_offset, y_offset); - } else { - impl_draw_children(x_offset, y_offset); + if(get_drawing_action() == redraw_action::none) { + return; } + + SDL_Rect dest = calculate_blitting_rectangle(x_offset, y_offset); + SDL_Rect clip = calculate_clipping_rectangle(x_offset, y_offset); + clip.x -= dest.x; clip.y -= dest.y; + auto view_setter = draw::set_viewport(dest); + auto clip_setter = draw::reduce_clip(clip); + + impl_draw_children(x_offset, y_offset); } void widget::draw_foreground(int x_offset, int y_offset) { assert(visible_ == visibility::visible); - if(redraw_action_ == redraw_action::partly) { - const SDL_Rect clipping_rectangle - = calculate_clipping_rectangle(x_offset, y_offset); - auto clipper = draw::set_clip(clipping_rectangle); - impl_draw_foreground(x_offset, y_offset); - } else { - impl_draw_foreground(x_offset, y_offset); + if(get_drawing_action() == redraw_action::none) { + return; } + + SDL_Rect dest = calculate_blitting_rectangle(x_offset, y_offset); + SDL_Rect clip = calculate_clipping_rectangle(x_offset, y_offset); + clip.x -= dest.x; clip.y -= dest.y; + auto view_setter = draw::set_viewport(dest); + auto clip_setter = draw::reduce_clip(clip); + + impl_draw_foreground(x_offset, y_offset); } void widget::populate_dirty_list(window& caller, diff --git a/src/gui/widgets/widget.hpp b/src/gui/widgets/widget.hpp index 95b79d33b5d..654f1d34f63 100644 --- a/src/gui/widgets/widget.hpp +++ b/src/gui/widgets/widget.hpp @@ -531,8 +531,7 @@ public: * * @returns The drawing rectangle. */ - SDL_Rect calculate_blitting_rectangle(const int x_offset, - const int y_offset); + SDL_Rect calculate_blitting_rectangle(const int x_offset, const int y_offset) const; /** * Calculates the clipping rectangle of the widget. @@ -546,8 +545,7 @@ public: * * @returns The clipping rectangle. */ - SDL_Rect calculate_clipping_rectangle(const int x_offset, - const int y_offset); + SDL_Rect calculate_clipping_rectangle(const int x_offset, const int y_offset) const; /** * Draws the background of a widget.