This repository has been archived on 2025-03-02. You can view files and clone it, but cannot push or open issues or pull requests.
neofx-zoomedit/draw.cpp
2007-09-17 08:33:03 +00:00

299 lines
7.7 KiB
C++

#include "draw.h"
#include "edit.h"
#include "geometry.h"
#include <math.h>
#include <gtk/gtk.h>
#include <cairo/cairo.h>
#include <stdlib.h>
static double scale = 100.0;
static double xTranslate = 0.0, yTranslate = 0.0;
static gboolean repaint = FALSE;
static void drawGrid(cairo_t *cr, const Rectangle *rect) {
double depth = log10(scale)-0.75;
double depth2 = floor(depth);
double step = pow(0.1, depth2);
double d;
int i;
gchar *string;
double x1 = rect->getVertex1().getX(), y1 = rect->getVertex1().getY();
double x2 = rect->getVertex2().getX(), y2 = rect->getVertex2().getY();
cairo_set_font_size(cr, 10.0/scale);
for(i = 0; 0.4*(depth-depth2+i-1) < 0.5; i++) {
d = MIN(0.4*(depth-depth2+i), 0.5);
cairo_set_source_rgb(cr, d, d, d);
for(d = x1 - fmod(x1, step) - step; d <= x2; d+=step) {
cairo_move_to(cr, d, y1);
cairo_line_to(cr, d, y2);
if(step > 0.005) {
if(step > 0.5)
string = g_strdup_printf("%i", (int)rint(d));
else
string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10);
cairo_move_to(cr, d+1/scale, y1+11/scale);
cairo_show_text(cr, string);
g_free(string);
}
}
for(d = y1 - fmod(y1, step) - step; d <= y2; d+=step) {
cairo_move_to(cr, x1, d);
cairo_line_to(cr, x2, d);
if(step > 0.005) {
if(step > 0.5)
string = g_strdup_printf("%i", (int)rint(d));
else
string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10);
cairo_move_to(cr, x1+3/scale, d+11/scale);
cairo_show_text(cr, string);
g_free(string);
}
}
cairo_stroke(cr);
step *= 10;
}
}
static void polygon2path(cairo_t *cr, const Polygon *polygon, const Rectangle *rect, gboolean close) {
Polygon polygon2;
// no vertices
if(polygon->empty()) return;
if(rect)
simplifyPolygon(polygon, rect, &polygon2);
else
polygon2 = *polygon;
if(polygon2.empty()) return;
cairo_new_sub_path(cr);
for(Polygon::iterator it = polygon2.begin(); it != polygon2.end(); it++) {
cairo_line_to(cr, it->getX(), it->getY());
}
if(close)
cairo_close_path(cr);
}
gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
cairo_t *cr;
Vertex v1(-1, -1), v2(widget->allocation.width+1, widget->allocation.height+1);
Rectangle rect;
gboolean vertexOk;
static GdkPixmap *pixmap = NULL;
static double lastImageWidth = 0.0, lastImageHeight = 0.0;
static gint lastWidth = 0, lastHeight = 0;
static int lastEditMode = 0;
int i;
if(getLevel() == NULL) return FALSE;
viewToImage(&v1);
viewToImage(&v2);
rect.setVertex1(v1);
rect.setVertex2(v2);
if(pixmap == NULL || fabs(lastImageWidth - getImageWidth()) >= 0.000001 || fabs(lastImageHeight - getImageHeight()) >= 0.000001 ||
lastWidth != widget->allocation.width || lastHeight != widget->allocation.height || lastEditMode != getEditMode() || repaint)
{
if(pixmap != NULL)
g_object_unref(G_OBJECT(pixmap));
pixmap = gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, -1);
lastImageWidth = getImageWidth();
lastImageHeight = getImageHeight();
lastWidth = widget->allocation.width;
lastHeight = widget->allocation.height;
lastEditMode = getEditMode();
repaint = FALSE;
cr = gdk_cairo_create(GDK_DRAWABLE(pixmap));
cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate);
cairo_scale(cr, scale, scale);
cairo_set_line_width(cr, 1.0/scale);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
drawGrid(cr, &rect);
for(Level::iterator room = getLevel()->begin(); room != getLevel()->end(); room++) {
if(&*room != getActiveRoom()) {
polygon2path(cr, &*room, &rect, TRUE);
}
}
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.3);
cairo_fill_preserve(cr);
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
cairo_stroke(cr);
if(getEditMode() == EDIT_MODE_SELECTED) {
polygon2path(cr, getActiveRoom(), &rect, TRUE);
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.2);
cairo_fill_preserve(cr);
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.9);
cairo_set_line_width(cr, 2.0/scale);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
cairo_stroke(cr);
}
cairo_destroy (cr);
}
gdk_draw_drawable(GDK_DRAWABLE(widget->window), widget->style->fg_gc[GTK_WIDGET_STATE(widget)], GDK_DRAWABLE(pixmap), 0, 0, 0, 0, -1, -1);
cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate);
cairo_scale(cr, scale, scale);
cairo_set_line_width(cr, 2.0/scale);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
if(getHoveredRoom() != NULL && getHoveredRoom() != getActiveRoom() &&
(getEditMode() == EDIT_MODE_VIEW || getEditMode() == EDIT_MODE_SELECTED))
{
polygon2path(cr, getHoveredRoom(), &rect, TRUE);
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
cairo_stroke(cr);
}
else if(getEditMode() == EDIT_MODE_ADD) {
polygon2path(cr, getActiveRoom(), NULL, FALSE);
if(isPolygonOk(getActiveRoom()))
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.2);
else
cairo_set_source_rgba(cr, 1.0, 0.3, 0.3, 0.2);
cairo_fill_preserve(cr);
if(!getActiveRoom()->empty() && getHoveredVertex()) {
vertexOk = isVertexOk(getHoveredVertex());
if(vertexOk)
cairo_line_to(cr, getHoveredVertex()->getX(), getHoveredVertex()->getY());
}
cairo_set_line_width(cr, 2.0/scale);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
cairo_stroke(cr);
if(!getActiveRoom()->empty() && getHoveredVertex() && !vertexOk) {
cairo_set_source_rgba(cr, 1.0, 0.3, 0.3, 0.7);
cairo_move_to(cr, getActiveRoom()->back().getX(), getActiveRoom()->back().getY());
cairo_line_to(cr, getHoveredVertex()->getX(), getHoveredVertex()->getY());
cairo_stroke(cr);
}
}
cairo_destroy (cr);
return FALSE;
}
double getScale() {
return scale;
}
void setScale(double s) {
scale = MAX(0.005, MIN(s, 10000));
repaint = TRUE;
}
void imageToView(Vertex *v) {
v->setX(v->getX()*scale+getImageWidth()/2-xTranslate);
v->setY(v->getY()*scale+getImageHeight()/2-yTranslate);
}
void viewToImage(Vertex *v) {
v->setX((v->getX()-getImageWidth()/2+xTranslate)/scale);
v->setY((v->getY()-getImageHeight()/2+yTranslate)/scale);
}
double getImageWidth() {
double min = 0.0, max = 0.0;
if(getLevel()) {
for(Level::iterator room = getLevel()->begin(); room != getLevel()->end(); room++) {
for(Room::iterator v = room->begin(); v != room->end(); v++) {
min = MIN(min, v->getX());
max = MAX(max, v->getX());
}
}
}
return (max-min+10)*scale;
}
double getImageHeight() {
double min = 0.0, max = 0.0;
if(getLevel()) {
for(Level::iterator room = getLevel()->begin(); room != getLevel()->end(); room++) {
for(Room::iterator v = room->begin(); v != room->end(); v++) {
min = MIN(min, v->getY());
max = MAX(max, v->getY());
}
}
}
return (max-min+10)*scale;
}
double getXTranslate() {
return xTranslate;
}
void setXTranslate(double x) {
xTranslate = x;
repaint = TRUE;
}
double getYTranslate() {
return yTranslate;
}
void setYTranslate(double y) {
yTranslate = y;
repaint = TRUE;
}
void redraw() {
repaint = TRUE;
}