summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--draw.c109
-rw-r--r--edit.c149
-rw-r--r--edit.h8
-rw-r--r--geometry.c46
-rw-r--r--geometry.h5
-rw-r--r--level.c2
-rw-r--r--level.h2
-rw-r--r--window.c205
-rw-r--r--zoomedit.c11
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 <stdlib.h>
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 <gtk/gtk.h>
-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 <string.h>
-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), "<b>Room info:</b>");
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), "<b>Add room</b>");
+ 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;
}