GUI2 Canvas: Implement rounded rectangle shape
Currently it's outline only.
This commit is contained in:
parent
fe098418f7
commit
76dcfcb32f
2 changed files with 175 additions and 16 deletions
|
@ -376,6 +376,17 @@
|
|||
default=0
|
||||
[/key]
|
||||
[/tag]
|
||||
[tag]
|
||||
name="round_rectangle"
|
||||
min="0"
|
||||
max="-1"
|
||||
super="generic/state/draw/rectangle"
|
||||
[key]
|
||||
name="corner_radius"
|
||||
type="f_unsigned"
|
||||
default=0
|
||||
[/key]
|
||||
[/tag]
|
||||
[tag]
|
||||
name="text"
|
||||
min="0"
|
||||
|
|
|
@ -143,7 +143,9 @@ static void draw_line(surface& canvas,
|
|||
* @param x_center The x coordinate of the center of the circle to draw.
|
||||
* @param y_center The y coordinate of the center of the circle to draw.
|
||||
* @param radius The radius of the circle to draw.
|
||||
* @tparam octants A bitfield indicating which octants to draw, starting at twelve o'clock and moving clockwise.
|
||||
*/
|
||||
template<unsigned int octants = 0xff>
|
||||
static void draw_circle(surface& canvas,
|
||||
SDL_Renderer* renderer,
|
||||
color_t color,
|
||||
|
@ -157,10 +159,10 @@ static void draw_circle(surface& canvas,
|
|||
<< " with radius " << radius << " canvas width " << w
|
||||
<< " canvas height " << canvas->h << ".\n";
|
||||
|
||||
assert((x_center + radius) < canvas->w);
|
||||
assert((x_center - radius) >= 0);
|
||||
assert((y_center + radius) < canvas->h);
|
||||
assert((y_center - radius) >= 0);
|
||||
if(octants & 0x0f) assert((x_center + radius) < canvas->w);
|
||||
if(octants & 0xf0) assert((x_center - radius) >= 0);
|
||||
if(octants & 0x3c) assert((y_center + radius) < canvas->h);
|
||||
if(octants & 0xc3) assert((y_center - radius) >= 0);
|
||||
|
||||
set_renderer_color(renderer, color);
|
||||
|
||||
|
@ -174,15 +176,15 @@ static void draw_circle(surface& canvas,
|
|||
std::vector<SDL_Point> points;
|
||||
|
||||
while(!(y > x)) {
|
||||
points.push_back({x_center + x, y_center + y});
|
||||
points.push_back({x_center + x, y_center - y});
|
||||
points.push_back({x_center - x, y_center + y});
|
||||
points.push_back({x_center - x, y_center - y});
|
||||
if(octants & 0x04) points.push_back({x_center + x, y_center + y});
|
||||
if(octants & 0x02) points.push_back({x_center + x, y_center - y});
|
||||
if(octants & 0x20) points.push_back({x_center - x, y_center + y});
|
||||
if(octants & 0x40) points.push_back({x_center - x, y_center - y});
|
||||
|
||||
points.push_back({x_center + y, y_center + x});
|
||||
points.push_back({x_center + y, y_center - x});
|
||||
points.push_back({x_center - y, y_center + x});
|
||||
points.push_back({x_center - y, y_center - x});
|
||||
if(octants & 0x08) points.push_back({x_center + y, y_center + x});
|
||||
if(octants & 0x01) points.push_back({x_center + y, y_center - x});
|
||||
if(octants & 0x10) points.push_back({x_center - y, y_center + x});
|
||||
if(octants & 0x80) points.push_back({x_center - y, y_center - x});
|
||||
|
||||
d += 2 * y + 1;
|
||||
++y;
|
||||
|
@ -670,13 +672,13 @@ private:
|
|||
* w & f_unsigned & 0 & The width of the rectangle. $
|
||||
* h & f_unsigned & 0 & The height of the rectangle. $
|
||||
* border_thickness & unsigned & 0 &
|
||||
* The thickness of the border if the
|
||||
* The thickness of the border; if the
|
||||
* thickness is zero it's not drawn. $
|
||||
* border_color & color & "" & The color of the border if empty it's
|
||||
* border_color & color & "" & The color of the border; if empty it's
|
||||
* not drawn. $
|
||||
* fill_color & color & "" & The color of the interior if omitted
|
||||
* fill_color & color & "" & The color of the interior; if omitted
|
||||
* it's not drawn. $
|
||||
* debug & string & "" & Debug message to show upon creation
|
||||
* debug & string & "" & Debug message to show upon creation;
|
||||
* this message is not stored. $
|
||||
* @end{table}
|
||||
* @end{tag}{name="rectangle"}
|
||||
|
@ -758,6 +760,150 @@ void rectangle_shape::draw(surface& canvas,
|
|||
}
|
||||
}
|
||||
|
||||
/***** ***** ***** ***** ***** Rounded Rectangle ***** ***** ***** ***** *****/
|
||||
|
||||
/** Definition of a rounded rectangle shape. */
|
||||
class round_rectangle_shape : public canvas::shape {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param cfg The config object to define the round rectangle see
|
||||
* http://www.wesnoth.org/wiki/GUICanvasWML#Rounded_Rectangle
|
||||
* for more information.
|
||||
*/
|
||||
explicit round_rectangle_shape(const config& cfg);
|
||||
|
||||
/** Implement shape::draw(). */
|
||||
void draw(surface& canvas,
|
||||
SDL_Renderer* renderer,
|
||||
wfl::map_formula_callable& variables) override;
|
||||
|
||||
private:
|
||||
typed_formula<int> x_, /**< The x coordinate of the rectangle. */
|
||||
y_, /**< The y coordinate of the rectangle. */
|
||||
w_, /**< The width of the rectangle. */
|
||||
h_, /**< The height of the rectangle. */
|
||||
r_; /**< The radius of the corners. /
|
||||
|
||||
/**
|
||||
* Border thickness.
|
||||
*
|
||||
* If 0 the fill color is used for the entire widget.
|
||||
*/
|
||||
int border_thickness_;
|
||||
|
||||
/**
|
||||
* The border color of the rounded rectangle.
|
||||
*
|
||||
* If the color is fully transparent the border isn't drawn.
|
||||
*/
|
||||
color_t border_color_;
|
||||
|
||||
/**
|
||||
* The border color of the rounded rectangle.
|
||||
*
|
||||
* If the color is fully transparent the rounded rectangle won't be filled.
|
||||
*/
|
||||
color_t fill_color_;
|
||||
};
|
||||
|
||||
/*WIKI
|
||||
* @page = GUICanvasWML
|
||||
*
|
||||
* == Rounded Rectangle ==
|
||||
* @begin{tag}{name="round_rectangle"}{min="0"}{max="-1"}
|
||||
*
|
||||
* Definition of a rounded rectangle. When drawing a rounded rectangle it doesn't get blended on
|
||||
* the surface but replaces the pixels instead. A blitting flag might be added
|
||||
* later if needed.
|
||||
*
|
||||
* Keys:
|
||||
* @begin{table}{config}
|
||||
* x & f_unsigned & 0 & The x coordinate of the top left corner.
|
||||
* $
|
||||
* y & f_unsigned & 0 & The y coordinate of the top left corner.
|
||||
* $
|
||||
* w & f_unsigned & 0 & The width of the rounded rectangle. $
|
||||
* h & f_unsigned & 0 & The height of the rounded rectangle. $
|
||||
* corner_radius & f_unsigned & 0 &The radius of the rectangle's corners. $
|
||||
* border_thickness & unsigned & 0 &
|
||||
* The thickness of the border; if the
|
||||
* thickness is zero it's not drawn. $
|
||||
* border_color & color & "" & The color of the border; if empty it's
|
||||
* not drawn. $
|
||||
* fill_color & color & "" & The color of the interior; if omitted
|
||||
* it's not drawn. $
|
||||
* debug & string & "" & Debug message to show upon creation;
|
||||
* this message is not stored. $
|
||||
* @end{table}
|
||||
* @end{tag}{name="round_rectangle"}
|
||||
* Variables:
|
||||
* See [[#general_variables|Line]].
|
||||
*
|
||||
*/
|
||||
round_rectangle_shape::round_rectangle_shape(const config& cfg)
|
||||
: shape(cfg)
|
||||
, x_(cfg["x"])
|
||||
, y_(cfg["y"])
|
||||
, w_(cfg["w"])
|
||||
, h_(cfg["h"])
|
||||
, r_(cfg["corner_radius"])
|
||||
, border_thickness_(cfg["border_thickness"])
|
||||
, border_color_(decode_color(cfg["border_color"]))
|
||||
, fill_color_(decode_color(cfg["fill_color"])) {
|
||||
if(border_color_.null()) {
|
||||
border_thickness_ = 0;
|
||||
}
|
||||
|
||||
const std::string& debug = (cfg["debug"]);
|
||||
if(!debug.empty()) {
|
||||
DBG_GUI_P << "Rounded Rectangle: found debug message '" << debug << "'.\n";
|
||||
}
|
||||
}
|
||||
|
||||
void round_rectangle_shape::draw(surface& canvas,
|
||||
SDL_Renderer* renderer,
|
||||
wfl::map_formula_callable& variables) {
|
||||
/**
|
||||
* @todo formulas are now recalculated every draw cycle which is a bit
|
||||
* silly unless there has been a resize. So to optimize we should use an
|
||||
* extra flag or do the calculation in a separate routine.
|
||||
*/
|
||||
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 << "Rectangle: draw from " << x << ',' << y << " width " << w
|
||||
<< " height " << h << " canvas size " << canvas->w << ','
|
||||
<< canvas->h << ".\n";
|
||||
|
||||
VALIDATE(x < canvas->w
|
||||
&& x + w <= canvas->w
|
||||
&& y < canvas->h
|
||||
&& y + h <= canvas->h, _("Rectangle doesn't fit on canvas."));
|
||||
|
||||
surface_lock locker(canvas);
|
||||
|
||||
// Draw the border
|
||||
for(int i = 0; i < border_thickness_; ++i) {
|
||||
set_renderer_color(renderer, border_color_);
|
||||
|
||||
SDL_RenderDrawLine(renderer, x + r, y + i, x + w - r, y + i);
|
||||
SDL_RenderDrawLine(renderer, x + r, y + h - i, x + w - r, y + h - i);
|
||||
|
||||
SDL_RenderDrawLine(renderer, x + i, y + r, x + i, y + h - r);
|
||||
SDL_RenderDrawLine(renderer, x + w - i, y + r, x + w - i, y + h - r);
|
||||
|
||||
draw_circle<0xc0>(canvas, renderer, border_color_, x + r, y + r, r - i);
|
||||
draw_circle<0x03>(canvas, renderer, border_color_, x + w - r, y + r, r - i);
|
||||
draw_circle<0x30>(canvas, renderer, border_color_, x + r, y + h - r, r - i);
|
||||
draw_circle<0x0c>(canvas, renderer, border_color_, x + w - r, y + h - r, r - i);
|
||||
}
|
||||
}
|
||||
|
||||
/***** ***** ***** ***** ***** CIRCLE ***** ***** ***** ***** *****/
|
||||
|
||||
/** Definition of a circle shape. */
|
||||
|
@ -1483,6 +1629,8 @@ void canvas::parse_cfg(const config& cfg)
|
|||
shapes_.emplace_back(std::make_shared<line_shape>(data));
|
||||
} else if(type == "rectangle") {
|
||||
shapes_.emplace_back(std::make_shared<rectangle_shape>(data));
|
||||
} else if(type == "round_rectangle") {
|
||||
shapes_.emplace_back(std::make_shared<round_rectangle_shape>(data));
|
||||
} else if(type == "circle") {
|
||||
shapes_.emplace_back(std::make_shared<circle_shape>(data));
|
||||
} else if(type == "image") {
|
||||
|
|
Loading…
Add table
Reference in a new issue