#include "draw.h" #include "edit.h" #include "geometry.h" #include #include #include #include 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.0, lastHeight = 0.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; }