Skip to content

Commit

Permalink
- Fixed device_to_user and user_to_device using matrices
Browse files Browse the repository at this point in the history
- Removed unused user_to_device_distance
  • Loading branch information
djowel committed Mar 10, 2024
1 parent 1da665a commit a80d383
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 34 deletions.
38 changes: 19 additions & 19 deletions lib/host/gtk3/base_view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,21 @@ namespace cycfi { namespace elements
return true;
}

gboolean on_draw(GtkWidget* /* widget */, cairo_t* cr, gpointer user_data)
gboolean on_draw(GtkWidget* widget, cairo_t* cr, gpointer user_data)
{
GtkAllocation alloc;
gtk_widget_get_allocation(widget, &alloc);

auto& view = get(user_data);
auto* host_view_h = platform_access::get_host_view(view);
cairo_set_source_surface(cr, host_view_h->surface, 0, 0);
cairo_paint(cr);

// Note that cr (cairo_t) is already clipped to only draw the
// exposed areas of the widget.
double left, top, right, bottom;
cairo_clip_extents(cr, &left, &top, &right, &bottom);
// Note that cr (cairo_t) is already clipped to only draw the exposed
// areas of the widget. double left, top, right, bottom;
view.draw(
cr,
rect{float(left), float(top), float(right), float(bottom)}
rect{0, 0, float(alloc.width), float(alloc.height)}
);

return false;
Expand Down Expand Up @@ -601,24 +602,23 @@ namespace cycfi { namespace elements

void base_view::refresh()
{
auto x = gtk_widget_get_allocated_width(_view->widget);
auto y = gtk_widget_get_allocated_height(_view->widget);
refresh({0, 0, float(x), float(y)});
GtkAllocation alloc;
gtk_widget_get_allocation(_view->widget, &alloc);
refresh({
float(alloc.x),
float(alloc.y),
float(alloc.x + alloc.width),
float(alloc.y + alloc.height)
});
}

void base_view::refresh(rect area)
{
// queue_draw_area's arguments are in "widget coordinates", which are
// relative to the widget's allocation when the widget in question has no
// GdkWindow (i.e. GtkGLArea).
GtkAllocation alloc;
gtk_widget_get_allocation(_view->widget, &alloc);

// Note: GTK uses int coordinates. Make sure area is not empty when converting
// from float to int.
// Note: GTK uses int coordinates. Make sure area is not empty
// when converting from float to int.
gtk_widget_queue_draw_area(_view->widget,
std::floor(area.left + alloc.x),
std::floor(area.top + alloc.y),
std::floor(area.left),
std::floor(area.top),
std::max<float>(area.width(), 1),
std::max<float>(area.height(), 1)
);
Expand Down
2 changes: 1 addition & 1 deletion lib/include/elements/support/canvas.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ namespace cycfi { namespace elements
void skew(float sx, float sy);
point device_to_user(point p);
point user_to_device(point p);
point user_to_device_distance(point p);

///////////////////////////////////////////////////////////////////////////////////
// Paths
Expand Down Expand Up @@ -227,6 +226,7 @@ namespace cycfi { namespace elements
using state_stack = std::stack<canvas_state>;

cairo_t& _context;
cairo_matrix_t _inv_affine;
canvas_state _state;
state_stack _state_stack;
float _pre_scale = 1.0f;
Expand Down
45 changes: 31 additions & 14 deletions lib/src/support/canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,14 @@ namespace cycfi { namespace elements

canvas::canvas(cairo_t& context_)
: _context(context_)
{}
{
cairo_get_matrix(&context_, &_inv_affine);
cairo_matrix_invert(&_inv_affine);
}

canvas::canvas(canvas&& rhs)
: _context(rhs._context)
: _context{rhs._context}
, _inv_affine{rhs._inv_affine}
{}

canvas::~canvas()
Expand Down Expand Up @@ -107,26 +111,39 @@ namespace cycfi { namespace elements

point canvas::device_to_user(point p)
{
double x = p.x * _pre_scale;
double y = p.y * _pre_scale;
cairo_device_to_user(&_context, &x, &y);
return { float(x), float(y) };
}
// Get the current matrix
cairo_matrix_t affine;
cairo_get_matrix(&_context, &affine);

point canvas::user_to_device(point p)
{
// Undo the initial transform
cairo_matrix_t xaf;
cairo_matrix_multiply(&xaf, &affine, &_inv_affine);

// Invert the`xaf` transform
cairo_matrix_invert(&xaf);

// Map the point to the `xaf` transform
double x = p.x;
double y = p.y;
cairo_user_to_device(&_context, &x, &y);
return { float(x / _pre_scale), float(y / _pre_scale) };
cairo_matrix_transform_point(&xaf, &x, &y);
return { float(x), float(y) };
}

point canvas::user_to_device_distance(point p)
point canvas::user_to_device(point p)
{
// Get the current matrix
cairo_matrix_t affine;
cairo_get_matrix(&_context, &affine);

// Undo the initial transform
cairo_matrix_t xaf;
cairo_matrix_multiply(&xaf, &affine, &_inv_affine);

// Map the point to the `xaf` transform
double x = p.x;
double y = p.y;
cairo_user_to_device_distance(&_context, &x, &y);
return {float(x / _pre_scale), float(y / _pre_scale)};
cairo_matrix_transform_point(&xaf, &x, &y);
return { float(x), float(y) };
}

void canvas::begin_path()
Expand Down

0 comments on commit a80d383

Please sign in to comment.