From 8dc800c37233bf64cbfe3b6a1eced0c9b7c46558 Mon Sep 17 00:00:00 2001 From: neoraider Date: Sat, 15 Sep 2007 17:54:02 +0000 Subject: zoomedit: Man kann R?ume hinzuf?gen, yeah! --- draw.c | 109 ++++++++++++++++++++++---------- edit.c | 149 ++++++++++++++++++++++++++++++++++++++++++-- edit.h | 8 ++- geometry.c | 46 ++++++++++---- geometry.h | 5 +- level.c | 2 +- level.h | 2 +- window.c | 205 ++++++++++++++++++++++++++++++++++++------------------------- zoomedit.c | 11 ++-- 9 files changed, 395 insertions(+), 142 deletions(-) diff --git a/draw.c b/draw.c index 7ce0d7f..cb25a1e 100644 --- a/draw.c +++ b/draw.c @@ -31,30 +31,34 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) { cairo_move_to(cr, d, rect->y); cairo_line_to(cr, d, rect->y+rect->height); - 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, rect->y+11/scale); - cairo_show_text(cr, string); - - g_free(string); + if(step > 0.005) { + if(step > 0.5) + string = g_strdup_printf("%i", (int)d); + else + string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10); + + cairo_move_to(cr, d+1/scale, rect->y+11/scale); + cairo_show_text(cr, string); + + g_free(string); + } } for(d = rect->y - fmod(rect->y, step) - step; d <= rect->y+rect->height; d+=step) { cairo_move_to(cr, rect->x, d); cairo_line_to(cr, rect->x+rect->width, d); - 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, rect->x+3/scale, d+11/scale); - cairo_show_text(cr, string); - - g_free(string); + if(step > 0.005) { + if(step > 0.5) + string = g_strdup_printf("%i", (int)d); + else + string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10); + + cairo_move_to(cr, rect->x+3/scale, d+11/scale); + cairo_show_text(cr, string); + + g_free(string); + } } cairo_stroke(cr); @@ -63,7 +67,7 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) { } } -static void polygon2path(cairo_t *cr, const POLYGON *polygon, const RECTANGLE *rect) { +static void polygon2path(cairo_t *cr, const POLYGON *polygon, const RECTANGLE *rect, gboolean close) { int i; POLYGON polygon2 = {0, NULL}; @@ -83,7 +87,8 @@ static void polygon2path(cairo_t *cr, const POLYGON *polygon, const RECTANGLE *r cairo_line_to(cr, polygon2.vertices[i].x, polygon2.vertices[i].y); } - cairo_close_path(cr); + if(close) + cairo_close_path(cr); if(rect && polygon2.vertices) free(polygon2.vertices); @@ -93,9 +98,11 @@ 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; @@ -109,8 +116,8 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) { rect.width = v2.x-v1.x; rect.height = v2.y-v1.y; - if(pixmap == NULL || lastImageWidth != getImageWidth() || lastImageHeight != getImageHeight() || - lastWidth != widget->allocation.width || lastHeight != widget->allocation.height || repaint) + 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)); @@ -121,15 +128,17 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) { 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_MITER); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); cairo_set_source_rgb(cr, 0, 0, 0); cairo_paint(cr); @@ -138,7 +147,7 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) { for(i = 0; i < getLevel()->nRooms; i++) { if(&getLevel()->rooms[i] != getActiveRoom()) - polygon2path(cr, &getLevel()->rooms[i].polygon, &rect); + polygon2path(cr, &getLevel()->rooms[i].polygon, &rect, TRUE); } cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.3); @@ -148,13 +157,14 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_stroke(cr); if(getEditMode() == EDIT_MODE_SELECTED) { - polygon2path(cr, &getActiveRoom()->polygon, &rect); + polygon2path(cr, &getActiveRoom()->polygon, &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); } @@ -163,25 +173,58 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) { 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)) { - cr = gdk_cairo_create(GDK_DRAWABLE(widget->window)); + polygon2path(cr, &getHoveredRoom()->polygon, &rect, TRUE); - cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate); - cairo_scale(cr, scale, scale); + 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()->polygon, NULL, FALSE); - cairo_set_line_width(cr, 2.0/scale); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); + if(isPolygonOk(&getActiveRoom()->polygon)) + 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); - polygon2path(cr, &getHoveredRoom()->polygon, &rect); + if(getActiveRoom()->polygon.nVertices && getHoveredVertex()) { + vertexOk = isVertexOk(getHoveredVertex()); + + if(vertexOk) + cairo_line_to(cr, getHoveredVertex()->x, getHoveredVertex()->y); + } + + 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); - cairo_destroy (cr); + if(getActiveRoom()->polygon.nVertices && getHoveredVertex() && !vertexOk) { + cairo_set_source_rgba(cr, 1.0, 0.3, 0.3, 0.7); + + i = getActiveRoom()->polygon.nVertices - 1; + cairo_move_to(cr, getActiveRoom()->polygon.vertices[i].x, getActiveRoom()->polygon.vertices[i].y); + cairo_line_to(cr, getHoveredVertex()->x, getHoveredVertex()->y); + + cairo_stroke(cr); + } } + cairo_destroy (cr); + return FALSE; } @@ -191,7 +234,7 @@ double getScale() { } void setScale(double s) { - scale = s; + scale = MAX(0.005, MIN(s, 10000)); repaint = TRUE; } diff --git a/edit.c b/edit.c index bb20d89..0fc01aa 100644 --- a/edit.c +++ b/edit.c @@ -1,4 +1,7 @@ #include "edit.h" +#include "level.h" +#include "geometry.h" +#include static int editMode = EDIT_MODE_VIEW; @@ -6,6 +9,8 @@ static int editMode = EDIT_MODE_VIEW; static ROOM *activeRoom = NULL; static ROOM *hoveredRoom = NULL; +static VERTEX hoveredVertex; +static int hasHoveredVertex = 0; int getEditMode() { return editMode; @@ -18,14 +23,150 @@ ROOM *getActiveRoom() { void setActiveRoom(ROOM *room) { activeRoom = room; - if(editMode == EDIT_MODE_VIEW || editMode == EDIT_MODE_SELECTED) - editMode = (room == NULL) ? EDIT_MODE_VIEW : EDIT_MODE_SELECTED; + if(room == NULL) { + editMode = EDIT_MODE_VIEW; + } + else if(editMode == EDIT_MODE_VIEW) { + editMode = EDIT_MODE_SELECTED; + } +} + +VERTEX *getHoveredVertex() { + if(hasHoveredVertex) return &hoveredVertex; + else return NULL; +} + +void setHoveredVertex(VERTEX *v) { + int i; + LEVEL *l; + + if(v) { + hasHoveredVertex = 1; + hoveredVertex = *v; + + l = getLevel(); + hoveredRoom = NULL; + + for(i = 0; i < l->nRooms; i++) { + if(vertexInPolygon(v, &l->rooms[i].polygon)) { + hoveredRoom = &l->rooms[i]; + break; + } + } + } + else { + hasHoveredVertex = 0; + hoveredRoom = NULL; + } +} + +void startAddMode() { + ROOM room = {{0, NULL}, calloc(1, sizeof(unsigned char))}; + + activeRoom = calloc(1, sizeof(ROOM)); + activeRoom->polygon.nVertices = 0; + activeRoom->polygon.vertices = NULL; + activeRoom->name = calloc(1, sizeof(unsigned char)); + + editMode = EDIT_MODE_ADD; +} + +void endAddMode() { + editMode = activeRoom ? EDIT_MODE_SELECTED : EDIT_MODE_VIEW; } ROOM *getHoveredRoom() { return hoveredRoom; } -void setHoveredRoom(ROOM *room) { - hoveredRoom = room; +static isLineOk(LINE *l) { + LEVEL *lvl = getLevel(); + LINE l2; + int i; + + + if(activeRoom) { + for(i = 0; i+2 < activeRoom->polygon.nVertices; i++) { + l2.v1 = activeRoom->polygon.vertices[i]; + l2.v2 = activeRoom->polygon.vertices[i+1]; + + if(lineIntersection(l, &l2, NULL) == INTERSECTION_SEGMENT_SEGMENT) return 0; + } + + if(activeRoom->polygon.nVertices > 1) { + l2.v1 = activeRoom->polygon.vertices[activeRoom->polygon.nVertices-2]; + l2.v2 = activeRoom->polygon.vertices[activeRoom->polygon.nVertices-1]; + if(vertexOnLine(&l->v2, &l2)) return 0; + } + } + + for(i = 0; i < lvl->nRooms; i++) { + if(linePolygonIntersection(l, &lvl->rooms[i].polygon)) + return 0; + } + + return 1; +} + +int isVertexOk(VERTEX *v) { + LEVEL *lvl = getLevel(); + LINE l; + int i; + + for(i = 0; i < lvl->nRooms; i++) { + if(vertexInPolygon(v, &lvl->rooms[i].polygon)) return 0; + } + + if(!(getActiveRoom() && getActiveRoom()->polygon.nVertices)) + return 1; + + l.v1 = getActiveRoom()->polygon.vertices[getActiveRoom()->polygon.nVertices-1]; + l.v2 = *v; + + return isLineOk(&l); +} + + + +int isPolygonOk(POLYGON *polygon) { + LEVEL *lvl = getLevel(); + LINE l, l2; + int i, j; + + if(!polygon->nVertices) return 0; + + for(i = 0; i < lvl->nRooms; i++) { + if(!lvl->rooms[i].polygon.nVertices) continue; + + if(vertexInPolygon(&polygon->vertices[0], &lvl->rooms[i].polygon)) + return 0; + + if(vertexInPolygon(&lvl->rooms[i].polygon.vertices[0], polygon)) + return 0; + } + + if(polygon->nVertices == 1) + return 1; + + for(i = 0; i < polygon->nVertices; i++) { + l.v1 = polygon->vertices[i]; + l.v2 = polygon->vertices[(i+1)%polygon->nVertices]; + + for(j = 0; j < lvl->nRooms; j++) { + if(linePolygonIntersection(&l, &lvl->rooms[j].polygon)) + return 0; + } + + for(j = i+2; j < polygon->nVertices; j++) { + if(i == 0 && j == polygon->nVertices-1) continue; + + l2.v1 = polygon->vertices[j]; + l2.v2 = polygon->vertices[(j+1)%polygon->nVertices]; + + if(lineIntersection(&l, &l2, NULL) == INTERSECTION_SEGMENT_SEGMENT) + return 0; + } + } + + return 1; } diff --git a/edit.h b/edit.h index d3ce2f6..663ba45 100644 --- a/edit.h +++ b/edit.h @@ -2,6 +2,7 @@ #define EDIT_H_ #include "level.h" +#include "geometry.h" #define EDIT_MODE_VIEW 0 #define EDIT_MODE_SELECTED 1 @@ -13,6 +14,11 @@ ROOM *getActiveRoom(); void setActiveRoom(ROOM *room); ROOM *getHoveredRoom(); -void setHoveredRoom(ROOM *room); + +VERTEX *getHoveredVertex(); +void setHoveredVertex(VERTEX *v); + +int isVertexOk(VERTEX *v); +int isPolygonOk(POLYGON *polygon); #endif /*EDIT_H_*/ diff --git a/geometry.c b/geometry.c index 248f354..2bbd6aa 100644 --- a/geometry.c +++ b/geometry.c @@ -4,13 +4,13 @@ #include -void addVertex(VERTEX_LIST *list, VERTEX *v) { +void addVertex(VERTEX_LIST *list, const VERTEX *v) { list->nVertices++; list->vertices = realloc(list->vertices, list->nVertices*sizeof(VERTEX)); list->vertices[list->nVertices-1] = *v; } -void insertVertex(VERTEX_LIST *list, VERTEX *v, unsigned int n) { +void insertVertex(VERTEX_LIST *list, const VERTEX *v, unsigned int n) { int i; if(n > list->nVertices) @@ -44,6 +44,27 @@ double vertexDistance(const VERTEX *v1, const VERTEX *v2) { return sqrt(vertexDistanceSquare(v1, v2)); } +int vertexOnLine(const VERTEX *v, const LINE *l) { + if(l->v1.x == l->v2.x && l->v1.y == l->v2.y) { + if(l->v1.x == v->x && l->v1.y == v->y) return 1; + else return 0; + } + + if(l->v1.x == l->v2.x) { + if(l->v1.x != v->x) return 0; + else if(v->y >= MIN(l->v1.y, l->v2.y) && v->y <= MAX(l->v1.y, l->v2.y)) return 1; + else return 1; + } + + if(l->v1.y == l->v2.y) { + if(l->v1.y != v->y) return 0; + else if(v->x >= MIN(l->v1.x, l->v2.x) && v->x <= MAX(l->v1.x, l->v2.x)) return 1; + else return 1; + } + if((v->x-l->v1.x)/(l->v2.x-l->v1.x) - (v->y-l->v1.y)/(l->v2.y-l->v1.y) == 0) return 1; + else return 0; +} + int vertexInRect(const VERTEX *v, const RECTANGLE *rect) { int ret = EDGE_NONE; @@ -149,7 +170,7 @@ double polygonArea(const POLYGON *p) { for(i = 0; i < p->nVertices; i++) d += (p->vertices[(i+1)%p->nVertices].x+p->vertices[i].x)*(p->vertices[(i+1)%p->nVertices].y-p->vertices[i].y); - return d/2; + return fabs(d/2); } int lineIntersection(const LINE *la, const LINE *lb, VERTEX *v) { @@ -176,22 +197,25 @@ int lineIntersection(const LINE *la, const LINE *lb, VERTEX *v) { switched = 1; } - double ma = (ya2-ya1)/(xa2-xa1); - double mb = (yb2-yb1)/(xb2-xb1); - double ba = ya1 - ma*xa1; - double bb = yb1 - mb*xb1; - - if(ma == mb) return (ba == bb) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE; + if(xa1 == xa2 && xb1 == xb2) + return (xa1 == xb1) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE; - if(isinf(ma)) { + if(xa1 == xa2) { v->x = xa1; v->y = yb1; } - else if(isinf(mb)) { + else if(xb1 == xb2) { v->x = xb1; v->y = ya1; } else { + double ma = (ya2-ya1)/(xa2-xa1); + double mb = (yb2-yb1)/(xb2-xb1); + double ba = ya1 - ma*xa1; + double bb = yb1 - mb*xb1; + + if(ma == mb) return (ba == bb) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE; + v->x = (bb-ba)/(ma-mb); v->y = ma*v->x + ba; } diff --git a/geometry.h b/geometry.h index c32b3ea..a272b2c 100644 --- a/geometry.h +++ b/geometry.h @@ -39,13 +39,14 @@ typedef struct _VERTEX_LIST { } VERTEX_LIST, POLYGON; -void addVertex(VERTEX_LIST *list, VERTEX *v); -void insertVertex(VERTEX_LIST *list, VERTEX *v, unsigned int n); +void addVertex(VERTEX_LIST *list, const VERTEX *v); +void insertVertex(VERTEX_LIST *list, const VERTEX *v, unsigned int n); void deleteVertex(VERTEX_LIST *list, unsigned int n); double vertexDistanceSquare(const VERTEX *v1, const VERTEX *v2); double vertexDistance(const VERTEX *v1, const VERTEX *v2); +int vertexOnLine(const VERTEX *v, const LINE *l); int vertexInRect(const VERTEX *v, const RECTANGLE *rect); gboolean vertexInPolygon(const VERTEX *v, const POLYGON *p); diff --git a/level.c b/level.c index 7c6aaa9..e78dfb7 100644 --- a/level.c +++ b/level.c @@ -13,7 +13,7 @@ void setLevel(LEVEL *l) { level = l; } -void addRoom(LEVEL *lvl, ROOM *room) { +void addRoom(LEVEL *lvl, const ROOM *room) { lvl->nRooms++; lvl->rooms = realloc(lvl->rooms, lvl->nRooms*sizeof(ROOM)); lvl->rooms[lvl->nRooms-1] = *room; diff --git a/level.h b/level.h index aa51ea1..e647509 100644 --- a/level.h +++ b/level.h @@ -17,7 +17,7 @@ typedef struct _LEVEL { LEVEL *getLevel(); void setLevel(LEVEL *l); -void addRoom(LEVEL *lvl, ROOM *room); +void addRoom(LEVEL *lvl, const ROOM *room); void deleteRoom(LEVEL *lvl, unsigned int n); void freeLevel(LEVEL *lvl); diff --git a/window.c b/window.c index d0cb531..38cf0cc 100644 --- a/window.c +++ b/window.c @@ -8,10 +8,10 @@ #include -static GtkWidget *drawingArea = NULL, *sidebar = NULL; +static GtkWidget *drawingArea = NULL, *sidebarView = NULL, *sidebarAdd = NULL; static GtkAdjustment *hAdjustment = NULL, *vAdjustment = NULL; -static GtkWidget *entryName, *labelArea = NULL, *labelPerimeter = NULL; +static GtkWidget *entryName, *labelArea = NULL, *labelPerimeter = NULL, *buttonAdd = NULL, *buttonAddDo = NULL; static gboolean deleteEvent(GtkWidget *widget, GdkEvent *event, gpointer data) { @@ -32,27 +32,30 @@ static gboolean scrollEvent(GtkWidget *widget, GdkEventScroll *event, gpointer u static gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer user_data) { VERTEX v = {event->x, event->y}; - int i; switch(event->type) { case GDK_BUTTON_PRESS: switch(event->button) { case 1: - viewToImage(&v); - - setActiveRoom(NULL); - - for(i = 0; i < getLevel()->nRooms; i++) { - if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) { - setActiveRoom(&getLevel()->rooms[i]); + switch(getEditMode()) { + case EDIT_MODE_VIEW: + case EDIT_MODE_SELECTED: + setActiveRoom(getHoveredRoom()); + + updateSidebar(); + + redraw(); break; - } + case EDIT_MODE_ADD: + viewToImage(&v); + + if(isVertexOk(&v)) { + addVertex(&getActiveRoom()->polygon, &v); + updateSidebar(); + } } - updateSidebar(); - - redraw(); gtk_widget_queue_draw(drawingArea); } } @@ -61,64 +64,40 @@ static gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer u } gboolean crossingNotifyEvent(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) { - int i; VERTEX v; - setHoveredRoom(NULL); - - if(event->type == GDK_ENTER_NOTIFY) { - v.x = event->x; - v.y = event->y; - - viewToImage(&v); - + switch(event->type) { + case GDK_ENTER_NOTIFY: + v.x = event->x; + v.y = event->y; + + viewToImage(&v); - for(i = 0; i < getLevel()->nRooms; i++) { - if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) { - setHoveredRoom(&getLevel()->rooms[i]); - - break; - } - } + setHoveredVertex(&v); + + break; + case GDK_LEAVE_NOTIFY: + setHoveredVertex(NULL); } + gtk_widget_queue_draw(drawingArea); } gboolean motionNotifyEvent(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) { - int i; - static VERTEX v, v_last = {0, 0}; - LINE line; - gboolean changed = FALSE; + VERTEX v; + ROOM *last = getHoveredRoom(); v.x = event->x; v.y = event->y; viewToImage(&v); - line.v1 = v_last; - line.v2 = v; + setHoveredVertex(&v); - for(i = 0; i < getLevel()->nRooms; i++) { - if(linePolygonIntersection(&line, &getLevel()->rooms[i].polygon)) { - if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) { - setHoveredRoom(&getLevel()->rooms[i]); - changed = TRUE; - - break; - } - else { - setHoveredRoom(NULL); - changed = TRUE; - } - } - } - - if(changed) + if(getHoveredRoom() != last || getEditMode() == EDIT_MODE_ADD) gtk_widget_queue_draw(drawingArea); - - v_last = v; } static void destroy(GtkWidget *widget, gpointer data) { @@ -182,31 +161,56 @@ static void sidebarNameChanged(GtkEditable *editable, gpointer user_data) { getActiveRoom()->name = strdup(gtk_entry_get_text(GTK_ENTRY(entryName))); } +static void sidebarButtonClicked(GtkButton *button, gpointer user_data) { + if(button == GTK_BUTTON(buttonAdd)) { + startAddMode(); + updateSidebar(); + + gtk_widget_queue_draw(drawingArea); + } + else if(button == GTK_BUTTON(buttonAddDo)) { + if(getActiveRoom() &&getActiveRoom()->polygon.nVertices > 2 && isPolygonOk(&getActiveRoom()->polygon)) { + addRoom(getLevel(), getActiveRoom()); + setActiveRoom(&getLevel()->rooms[getLevel()->nRooms-1]); + } + + endAddMode(); + updateSidebar(); + + gtk_widget_queue_draw(drawingArea); + } +} + static GtkWidget* createSidebar() { - GtkWidget *widget, *labelRoomInfo, *labelName, *tableRoomData, *labelAreaLabel, *labelPerimeterLabel; + GtkWidget *sidebar, *labelRoomInfo, *labelName; + GtkWidget *tableRoomData, *labelAreaLabel, *labelPerimeterLabel; - widget = gtk_vbox_new(FALSE, 0); + sidebar = gtk_hbox_new(FALSE, 0); + + // View sidebar + sidebarView = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(sidebar), sidebarView, FALSE, FALSE, 5); labelRoomInfo = gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(labelRoomInfo), "Room info:"); gtk_misc_set_alignment(GTK_MISC(labelRoomInfo), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(widget), labelRoomInfo, FALSE, FALSE, 5); + gtk_box_pack_start(GTK_BOX(sidebarView), labelRoomInfo, FALSE, FALSE, 5); - gtk_box_pack_start(GTK_BOX(widget), gtk_hseparator_new(), FALSE, FALSE, 5); + gtk_box_pack_start(GTK_BOX(sidebarView), gtk_hseparator_new(), FALSE, FALSE, 5); labelName = gtk_label_new("Name:"); gtk_misc_set_alignment(GTK_MISC(labelName), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(widget), labelName, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(sidebarView), labelName, FALSE, FALSE, 0); entryName = gtk_entry_new(); gtk_widget_set_sensitive(entryName, FALSE); g_signal_connect(G_OBJECT(entryName), "changed", G_CALLBACK(sidebarNameChanged), NULL); - gtk_box_pack_start(GTK_BOX(widget), entryName, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(sidebarView), entryName, FALSE, FALSE, 0); tableRoomData = gtk_table_new(2, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(tableRoomData), 5); gtk_table_set_col_spacings(GTK_TABLE(tableRoomData), 10); - gtk_box_pack_start(GTK_BOX(widget), tableRoomData, FALSE, FALSE, 5); + gtk_box_pack_start(GTK_BOX(sidebarView), tableRoomData, FALSE, FALSE, 5); labelAreaLabel = gtk_label_new("Room area:"); gtk_misc_set_alignment(GTK_MISC(labelAreaLabel), 0.0, 0.5); @@ -224,11 +228,28 @@ static GtkWidget* createSidebar() { gtk_misc_set_alignment(GTK_MISC(labelPerimeter), 1.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelPerimeter, 1, 2, 1, 2); - return widget; + buttonAdd = gtk_button_new_with_label("Add room"); + g_signal_connect(G_OBJECT(buttonAdd), "clicked", G_CALLBACK(sidebarButtonClicked), NULL); + gtk_box_pack_end(GTK_BOX(sidebarView), buttonAdd, FALSE, FALSE, 0); + + // Add sidebar + sidebarAdd = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(sidebar), sidebarAdd, FALSE, FALSE, 5); + + labelRoomInfo = gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(labelRoomInfo), "Add room"); + gtk_misc_set_alignment(GTK_MISC(labelRoomInfo), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(sidebarAdd), labelRoomInfo, FALSE, FALSE, 5); + + buttonAddDo = gtk_button_new_with_label("Add room"); + g_signal_connect(G_OBJECT(buttonAddDo), "clicked", G_CALLBACK(sidebarButtonClicked), NULL); + gtk_box_pack_end(GTK_BOX(sidebarAdd), buttonAddDo, FALSE, FALSE, 0); + + return sidebar; } GtkWidget* createMainWindow() { - GtkWidget *window, *vbox, *hPaned, *table, *vScroll, *hScroll; + GtkWidget *window, *hPaned, *vbox, *table, *vScroll, *hScroll, *sidebar; GdkColor color = {0, 0, 0, 0}; @@ -262,7 +283,6 @@ GtkWidget* createMainWindow() { g_signal_connect(G_OBJECT(drawingArea), "motion-notify-event", G_CALLBACK(motionNotifyEvent), NULL); g_signal_connect(G_OBJECT(drawingArea), "scroll-event", G_CALLBACK(scrollEvent), NULL); gtk_widget_add_events(drawingArea, GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - gtk_widget_set_double_buffered(drawingArea, FALSE); gtk_table_attach(GTK_TABLE(table), drawingArea, 0, 1, 0, 1, GTK_FILL|GTK_EXPAND|GTK_SHRINK, GTK_FILL|GTK_EXPAND|GTK_SHRINK, 0, 0); hAdjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 0, 10, 100, 100)); @@ -279,6 +299,7 @@ GtkWidget* createMainWindow() { gtk_paned_pack2(GTK_PANED(hPaned), sidebar, FALSE, TRUE); gtk_widget_show_all(vbox); + gtk_widget_hide(sidebarAdd); return window; } @@ -286,25 +307,43 @@ GtkWidget* createMainWindow() { void updateSidebar() { gchar *string; - - if(getActiveRoom()) { - gtk_entry_set_text(GTK_ENTRY(entryName), getActiveRoom()->name); - gtk_widget_set_sensitive(entryName, TRUE); - - string = g_strdup_printf("%.2f", polygonArea(&getActiveRoom()->polygon)); - gtk_label_set_text(GTK_LABEL(labelArea), string); - g_free(string); - - string = g_strdup_printf("%.2f", polygonPerimeter(&getActiveRoom()->polygon)); - gtk_label_set_text(GTK_LABEL(labelPerimeter), string); - g_free(string); - } - else { - gtk_entry_set_text(GTK_ENTRY(entryName), ""); - gtk_widget_set_sensitive(entryName, FALSE); - - gtk_label_set_text(GTK_LABEL(labelArea), NULL); - gtk_label_set_text(GTK_LABEL(labelPerimeter), NULL); + switch(getEditMode()) { + case EDIT_MODE_VIEW: + case EDIT_MODE_SELECTED: + gtk_widget_hide(sidebarAdd); + gtk_widget_show(sidebarView); + + if(getActiveRoom()) { + gtk_entry_set_text(GTK_ENTRY(entryName), getActiveRoom()->name); + gtk_widget_set_sensitive(entryName, TRUE); + + string = g_strdup_printf("%.2f", polygonArea(&getActiveRoom()->polygon)); + gtk_label_set_text(GTK_LABEL(labelArea), string); + g_free(string); + + string = g_strdup_printf("%.2f", polygonPerimeter(&getActiveRoom()->polygon)); + gtk_label_set_text(GTK_LABEL(labelPerimeter), string); + g_free(string); + } + else { + gtk_entry_set_text(GTK_ENTRY(entryName), ""); + gtk_widget_set_sensitive(entryName, FALSE); + + gtk_label_set_text(GTK_LABEL(labelArea), NULL); + gtk_label_set_text(GTK_LABEL(labelPerimeter), NULL); + } + + break; + case EDIT_MODE_ADD: + gtk_widget_hide(sidebarView); + gtk_widget_show(sidebarAdd); + + if(getActiveRoom()) { + if(getActiveRoom()->polygon.nVertices > 2 && isPolygonOk(&getActiveRoom()->polygon)) + gtk_widget_set_sensitive(buttonAddDo, TRUE); + else + gtk_widget_set_sensitive(buttonAddDo, FALSE); + } } } diff --git a/zoomedit.c b/zoomedit.c index 0d90aa3..5cce048 100644 --- a/zoomedit.c +++ b/zoomedit.c @@ -5,22 +5,21 @@ int main(int argc, char *argv[]) { - VERTEX vertices[4] = {{0,-1}, {1,0}, {0,1}, {-1,0}}; - ROOM room = {{sizeof(vertices)/sizeof(vertices[0]), vertices}, calloc(1, sizeof(unsigned char))}; - LEVEL lvl = {1, &room}; + LEVEL *lvl = calloc(1, sizeof(LEVEL)); GtkWidget *window; + + setLevel(lvl); + gtk_init(&argc, &argv); window = createMainWindow(); - setLevel(&lvl); - gtk_widget_show(window); gtk_main(); - free(room.name); + freeLevel(lvl); return 0; } -- cgit v1.2.3