mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-14 13:00:55 +00:00
GUI2: Port over most of the canvas cleanup
Text is still drawing clipped because otherwise Credits crashes. It has bugs because the viewport is too large, but at least it doesn't crash.
This commit is contained in:
parent
0f6da374e0
commit
8efd9d43f2
|
@ -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<int>(clip_x), static_cast<int>(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<unsigned>(rect.w) <= w_ && static_cast<unsigned>(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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<unsigned> 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<unsigned> x1_; /**< The start x coordinate of the line. */
|
||||
typed_formula<unsigned> y1_; /**< The start y coordinate of the line. */
|
||||
typed_formula<unsigned> x2_; /**< The end x coordinate of the line. */
|
||||
typed_formula<unsigned> y2_; /**< The end y coordinate of the line. */
|
||||
|
||||
/** The color of the line. */
|
||||
typed_formula<color_t> 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<int> x_; /**< The x coordinate of the rectangle. */
|
||||
typed_formula<int> y_; /**< The y coordinate of the rectangle. */
|
||||
typed_formula<int> 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<int> 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<unsigned> x_, /**< The center x coordinate of the circle. */
|
||||
y_, /**< The center y coordinate of the circle. */
|
||||
radius_; /**< The radius of the circle. */
|
||||
typed_formula<unsigned> x_; /**< The center x coordinate of the circle. */
|
||||
typed_formula<unsigned> y_; /**< The center y coordinate of the circle. */
|
||||
|
||||
/** The radius of the circle. */
|
||||
typed_formula<unsigned> radius_;
|
||||
|
||||
/** The border color of the circle. */
|
||||
typed_formula<color_t> border_color_, fill_color_; /**< The fill color of the circle. */
|
||||
typed_formula<color_t> border_color_;
|
||||
|
||||
/** The fill color of the circle. */
|
||||
typed_formula<color_t> 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<unsigned> 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<unsigned> x_; /**< The x coordinate of the image. */
|
||||
typed_formula<unsigned> y_; /**< The y coordinate of the image. */
|
||||
typed_formula<unsigned> w_; /**< The width of the image. */
|
||||
typed_formula<unsigned> 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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*/)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user