#include "view.h"
#include <gtkmm/container.h>
void
View::Point::draw(
const Cairo::RefPtr<Cairo::Context>& context,
View &view )
{
const Real ps = view.get_pixel_size();
context->save();
context->arc(position.x, position.y, radius*ps, 0.0, 2.0*M_PI);
context->set_source_rgba(color.r, color.g, color.b, color.a);
context->fill_preserve();
context->set_source_rgba(0.0, 0.0, 0.0, color.a);
context->set_line_width(selected ? 2.0*ps : ps);
context->stroke();
context->restore();
}
View::View():
dragging()
{
set_events(
Gdk::POINTER_MOTION_MASK
| Gdk::BUTTON_PRESS_MASK
| Gdk::BUTTON_RELEASE_MASK );
}
View::~View() { }
Real
View::get_pixel_size()
{ return 1.0/sqrt(fabs(transform.m00 * transform.m11)); }
void
View::transform_context(const Cairo::RefPtr<Cairo::Context>& context) {
Cairo::Matrix matrix(
transform.m00, transform.m10, transform.m01,
transform.m11, transform.m30, transform.m31 );
context->translate(0.5*get_width(), 0.5*get_height());
context->transform(matrix);
}
void
View::back_transform_context(const Cairo::RefPtr<Cairo::Context>& context) {
Cairo::Matrix matrix(
transform.m00, transform.m10, transform.m01,
transform.m11, transform.m30, transform.m31 );
matrix.invert();
context->transform(matrix);
context->translate(-0.5*get_width(), -0.5*get_height());
}
bool
View::on_draw(const Cairo::RefPtr<Cairo::Context>& context) {
context->save();
const Real border_size = 1.0;
const Real border_margin = 2.0;
context->save();
context->rectangle(0, 0, get_width(), get_height());
context->set_source_rgba(0, 0, 0, 1);
context->fill();
context->rectangle(
border_margin, border_margin,
get_width() - 2*border_margin,
get_height() - 2*border_margin );
context->set_line_width(border_size);
context->set_source_rgba(1, 1, 0, 1);
context->stroke();
context->restore();
context->translate(0.5*get_width(), 0.5*get_height());
context->transform(Cairo::Matrix(transform.m00, transform.m10, transform.m01, transform.m11, transform.m30, transform.m31));
signal_draw_view(context);
for(PointList::const_iterator i = points.begin(); i != points.end(); ++i)
(*i)->draw(context, *this);
context->restore();
return true;
}
bool
View::on_motion_notify_event(GdkEventMotion *event) {
Vector2 prev_mouse_position = mouse_position;
mouse_position = Vector2(event->x - 0.5*get_width(), event->y - 0.5*get_height());
if (dragging) {
if (selected_point) {
selected_point->position = Vector2(transform.inverted()*Vector4(mouse_position + selected_point_offset, 0, 1));
point_motion(selected_point);
queue_draw();
}
return true;
}
PointPtr point;
for(PointList::iterator i = points.begin(); i != points.end(); ++i) {
(*i)->selected = false;
Vector2 point_position = Vector2(transform * Vector4((*i)->position, 0, 1));
Vector2 offset = point_position - mouse_position;
if (offset.square() <= (*i)->radius * (*i)->radius) {
point = *i;
selected_point_offset = offset;
}
}
if (point)
point->selected = true;
if (selected_point != point) {
selected_point = point;
queue_draw();
}
if (event->state & Gdk::BUTTON2_MASK) {
// translate
transform.row_w() += Vector4(mouse_position - prev_mouse_position);
queue_draw();
}
if (event->state & Gdk::BUTTON3_MASK) {
// zoom
Real scale = pow(2.0, (prev_mouse_position.y - mouse_position.y)/50.0); // zoom x2 by motion to 50 pixels
Vector2 center = Vector2(transform.inverted() * Vector4(0, 0, 0, 1));
transform.scale(scale, scale);
transform.row_w() = Vector4(0, 0, 0, 1);
transform.row_w() = transform * Vector4(-center, 0, 1);
queue_draw();
}
return true;
}
bool
View::on_button_press_event(GdkEventButton *event) {
if (event->button == 1)
dragging = true;
return true;
}
bool
View::on_button_release_event(GdkEventButton *event) {
if (event->button == 1) {
dragging = false;
if (selected_point)
point_changed(selected_point);
}
if (event->button == 2 || event->button == 3)
signal_transform_changed();
return true;
}