zoomedit: Man kann R?ume hinzuf?gen, yeah!

This commit is contained in:
neoraider 2007-09-15 17:54:02 +00:00
parent 4d035c6455
commit 8dc800c372
9 changed files with 399 additions and 146 deletions

109
draw.c
View file

@ -31,30 +31,34 @@ static void drawGrid(cairo_t *cr, const RECTANGLE *rect) {
cairo_move_to(cr, d, rect->y); cairo_move_to(cr, d, rect->y);
cairo_line_to(cr, d, rect->y+rect->height); cairo_line_to(cr, d, rect->y+rect->height);
if(step > 0.5) if(step > 0.005) {
string = g_strdup_printf("%i", (int)rint(d)); if(step > 0.5)
else string = g_strdup_printf("%i", (int)d);
string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10); 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_move_to(cr, d+1/scale, rect->y+11/scale);
cairo_show_text(cr, string); cairo_show_text(cr, string);
g_free(string); g_free(string);
}
} }
for(d = rect->y - fmod(rect->y, step) - step; d <= rect->y+rect->height; d+=step) { for(d = rect->y - fmod(rect->y, step) - step; d <= rect->y+rect->height; d+=step) {
cairo_move_to(cr, rect->x, d); cairo_move_to(cr, rect->x, d);
cairo_line_to(cr, rect->x+rect->width, d); cairo_line_to(cr, rect->x+rect->width, d);
if(step > 0.5) if(step > 0.005) {
string = g_strdup_printf("%i", (int)rint(d)); if(step > 0.5)
else string = g_strdup_printf("%i", (int)d);
string = g_strdup_printf("%.*f", -(int)floor(log10(step*1.1)), d+step/10); 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_move_to(cr, rect->x+3/scale, d+11/scale);
cairo_show_text(cr, string); cairo_show_text(cr, string);
g_free(string); g_free(string);
}
} }
cairo_stroke(cr); 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; int i;
POLYGON polygon2 = {0, NULL}; 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_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) if(rect && polygon2.vertices)
free(polygon2.vertices); free(polygon2.vertices);
@ -93,9 +98,11 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
cairo_t *cr; cairo_t *cr;
VERTEX v1 = {-1, -1}, v2 = {widget->allocation.width+1, widget->allocation.height+1}; VERTEX v1 = {-1, -1}, v2 = {widget->allocation.width+1, widget->allocation.height+1};
RECTANGLE rect; RECTANGLE rect;
gboolean vertexOk;
static GdkPixmap *pixmap = NULL; static GdkPixmap *pixmap = NULL;
static double lastImageWidth = 0.0, lastImageHeight = 0.0; static double lastImageWidth = 0.0, lastImageHeight = 0.0;
static gint lastWidth = 0.0, lastHeight = 0.0; static gint lastWidth = 0.0, lastHeight = 0.0;
static int lastEditMode = 0;
int i; int i;
@ -109,8 +116,8 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
rect.width = v2.x-v1.x; rect.width = v2.x-v1.x;
rect.height = v2.y-v1.y; rect.height = v2.y-v1.y;
if(pixmap == NULL || lastImageWidth != getImageWidth() || lastImageHeight != getImageHeight() || if(pixmap == NULL || fabs(lastImageWidth - getImageWidth()) >= 0.000001 || fabs(lastImageHeight - getImageHeight()) >= 0.000001 ||
lastWidth != widget->allocation.width || lastHeight != widget->allocation.height || repaint) lastWidth != widget->allocation.width || lastHeight != widget->allocation.height || lastEditMode != getEditMode() || repaint)
{ {
if(pixmap != NULL) if(pixmap != NULL)
g_object_unref(G_OBJECT(pixmap)); g_object_unref(G_OBJECT(pixmap));
@ -121,15 +128,17 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
lastImageHeight = getImageHeight(); lastImageHeight = getImageHeight();
lastWidth = widget->allocation.width; lastWidth = widget->allocation.width;
lastHeight = widget->allocation.height; lastHeight = widget->allocation.height;
lastEditMode = getEditMode();
repaint = FALSE; repaint = FALSE;
cr = gdk_cairo_create(GDK_DRAWABLE(pixmap)); cr = gdk_cairo_create(GDK_DRAWABLE(pixmap));
cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate); cairo_translate(cr, getImageWidth()/2-xTranslate, getImageHeight()/2-yTranslate);
cairo_scale(cr, scale, scale); cairo_scale(cr, scale, scale);
cairo_set_line_width(cr, 1.0/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_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr); cairo_paint(cr);
@ -138,7 +147,7 @@ gboolean drawTopView(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
for(i = 0; i < getLevel()->nRooms; i++) { for(i = 0; i < getLevel()->nRooms; i++) {
if(&getLevel()->rooms[i] != getActiveRoom()) 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); 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); cairo_stroke(cr);
if(getEditMode() == EDIT_MODE_SELECTED) { 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_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.2);
cairo_fill_preserve(cr); cairo_fill_preserve(cr);
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.9); cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.9);
cairo_set_line_width(cr, 2.0/scale); cairo_set_line_width(cr, 2.0/scale);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
cairo_stroke(cr); cairo_stroke(cr);
} }
@ -163,24 +173,57 @@ 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); 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() && if(getHoveredRoom() != NULL && getHoveredRoom() != getActiveRoom() &&
(getEditMode() == EDIT_MODE_VIEW || getEditMode() == EDIT_MODE_SELECTED)) (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_line_width(cr, 2.0/scale);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
polygon2path(cr, &getHoveredRoom()->polygon, &rect);
cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7); cairo_set_source_rgba(cr, 0.0, 0.7, 1.0, 0.7);
cairo_stroke(cr); cairo_stroke(cr);
cairo_destroy (cr);
} }
else if(getEditMode() == EDIT_MODE_ADD) {
polygon2path(cr, &getActiveRoom()->polygon, NULL, FALSE);
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);
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);
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; return FALSE;
} }
@ -191,7 +234,7 @@ double getScale() {
} }
void setScale(double s) { void setScale(double s) {
scale = s; scale = MAX(0.005, MIN(s, 10000));
repaint = TRUE; repaint = TRUE;
} }

149
edit.c
View file

@ -1,4 +1,7 @@
#include "edit.h" #include "edit.h"
#include "level.h"
#include "geometry.h"
#include <stdlib.h>
static int editMode = EDIT_MODE_VIEW; static int editMode = EDIT_MODE_VIEW;
@ -6,6 +9,8 @@ static int editMode = EDIT_MODE_VIEW;
static ROOM *activeRoom = NULL; static ROOM *activeRoom = NULL;
static ROOM *hoveredRoom = NULL; static ROOM *hoveredRoom = NULL;
static VERTEX hoveredVertex;
static int hasHoveredVertex = 0;
int getEditMode() { int getEditMode() {
return editMode; return editMode;
@ -18,14 +23,150 @@ ROOM *getActiveRoom() {
void setActiveRoom(ROOM *room) { void setActiveRoom(ROOM *room) {
activeRoom = room; activeRoom = room;
if(editMode == EDIT_MODE_VIEW || editMode == EDIT_MODE_SELECTED) if(room == NULL) {
editMode = (room == NULL) ? EDIT_MODE_VIEW : EDIT_MODE_SELECTED; 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() { ROOM *getHoveredRoom() {
return hoveredRoom; return hoveredRoom;
} }
void setHoveredRoom(ROOM *room) { static isLineOk(LINE *l) {
hoveredRoom = room; 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;
} }

8
edit.h
View file

@ -2,6 +2,7 @@
#define EDIT_H_ #define EDIT_H_
#include "level.h" #include "level.h"
#include "geometry.h"
#define EDIT_MODE_VIEW 0 #define EDIT_MODE_VIEW 0
#define EDIT_MODE_SELECTED 1 #define EDIT_MODE_SELECTED 1
@ -13,6 +14,11 @@ ROOM *getActiveRoom();
void setActiveRoom(ROOM *room); void setActiveRoom(ROOM *room);
ROOM *getHoveredRoom(); ROOM *getHoveredRoom();
void setHoveredRoom(ROOM *room);
VERTEX *getHoveredVertex();
void setHoveredVertex(VERTEX *v);
int isVertexOk(VERTEX *v);
int isPolygonOk(POLYGON *polygon);
#endif /*EDIT_H_*/ #endif /*EDIT_H_*/

View file

@ -4,13 +4,13 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
void addVertex(VERTEX_LIST *list, VERTEX *v) { void addVertex(VERTEX_LIST *list, const VERTEX *v) {
list->nVertices++; list->nVertices++;
list->vertices = realloc(list->vertices, list->nVertices*sizeof(VERTEX)); list->vertices = realloc(list->vertices, list->nVertices*sizeof(VERTEX));
list->vertices[list->nVertices-1] = *v; 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; int i;
if(n > list->nVertices) if(n > list->nVertices)
@ -44,6 +44,27 @@ double vertexDistance(const VERTEX *v1, const VERTEX *v2) {
return sqrt(vertexDistanceSquare(v1, 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 vertexInRect(const VERTEX *v, const RECTANGLE *rect) {
int ret = EDGE_NONE; int ret = EDGE_NONE;
@ -149,7 +170,7 @@ double polygonArea(const POLYGON *p) {
for(i = 0; i < p->nVertices; i++) 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); 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) { 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; switched = 1;
} }
double ma = (ya2-ya1)/(xa2-xa1); if(xa1 == xa2 && xb1 == xb2)
double mb = (yb2-yb1)/(xb2-xb1); return (xa1 == xb1) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE;
double ba = ya1 - ma*xa1;
double bb = yb1 - mb*xb1;
if(ma == mb) return (ba == bb) ? INTERSECTION_IDENTICAL : INTERSECTION_NONE; if(xa1 == xa2) {
if(isinf(ma)) {
v->x = xa1; v->x = xa1;
v->y = yb1; v->y = yb1;
} }
else if(isinf(mb)) { else if(xb1 == xb2) {
v->x = xb1; v->x = xb1;
v->y = ya1; v->y = ya1;
} }
else { 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->x = (bb-ba)/(ma-mb);
v->y = ma*v->x + ba; v->y = ma*v->x + ba;
} }

View file

@ -39,13 +39,14 @@ typedef struct _VERTEX_LIST {
} VERTEX_LIST, POLYGON; } VERTEX_LIST, POLYGON;
void addVertex(VERTEX_LIST *list, VERTEX *v); void addVertex(VERTEX_LIST *list, const VERTEX *v);
void insertVertex(VERTEX_LIST *list, VERTEX *v, unsigned int n); void insertVertex(VERTEX_LIST *list, const VERTEX *v, unsigned int n);
void deleteVertex(VERTEX_LIST *list, unsigned int n); void deleteVertex(VERTEX_LIST *list, unsigned int n);
double vertexDistanceSquare(const VERTEX *v1, const VERTEX *v2); double vertexDistanceSquare(const VERTEX *v1, const VERTEX *v2);
double vertexDistance(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); int vertexInRect(const VERTEX *v, const RECTANGLE *rect);
gboolean vertexInPolygon(const VERTEX *v, const POLYGON *p); gboolean vertexInPolygon(const VERTEX *v, const POLYGON *p);

View file

@ -13,7 +13,7 @@ void setLevel(LEVEL *l) {
level = l; level = l;
} }
void addRoom(LEVEL *lvl, ROOM *room) { void addRoom(LEVEL *lvl, const ROOM *room) {
lvl->nRooms++; lvl->nRooms++;
lvl->rooms = realloc(lvl->rooms, lvl->nRooms*sizeof(ROOM)); lvl->rooms = realloc(lvl->rooms, lvl->nRooms*sizeof(ROOM));
lvl->rooms[lvl->nRooms-1] = *room; lvl->rooms[lvl->nRooms-1] = *room;

View file

@ -17,7 +17,7 @@ typedef struct _LEVEL {
LEVEL *getLevel(); LEVEL *getLevel();
void setLevel(LEVEL *l); 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 deleteRoom(LEVEL *lvl, unsigned int n);
void freeLevel(LEVEL *lvl); void freeLevel(LEVEL *lvl);

191
window.c
View file

@ -8,10 +8,10 @@
#include <string.h> #include <string.h>
static GtkWidget *drawingArea = NULL, *sidebar = NULL; static GtkWidget *drawingArea = NULL, *sidebarView = NULL, *sidebarAdd = NULL;
static GtkAdjustment *hAdjustment = NULL, *vAdjustment = 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) { 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) { static gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
VERTEX v = {event->x, event->y}; VERTEX v = {event->x, event->y};
int i;
switch(event->type) { switch(event->type) {
case GDK_BUTTON_PRESS: case GDK_BUTTON_PRESS:
switch(event->button) { switch(event->button) {
case 1: case 1:
viewToImage(&v); switch(getEditMode()) {
case EDIT_MODE_VIEW:
case EDIT_MODE_SELECTED:
setActiveRoom(getHoveredRoom());
setActiveRoom(NULL); updateSidebar();
for(i = 0; i < getLevel()->nRooms; i++) { redraw();
if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) {
setActiveRoom(&getLevel()->rooms[i]);
break; break;
} case EDIT_MODE_ADD:
viewToImage(&v);
if(isVertexOk(&v)) {
addVertex(&getActiveRoom()->polygon, &v);
updateSidebar();
}
} }
updateSidebar();
redraw();
gtk_widget_queue_draw(drawingArea); 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) { gboolean crossingNotifyEvent(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) {
int i;
VERTEX v; VERTEX v;
setHoveredRoom(NULL); switch(event->type) {
case GDK_ENTER_NOTIFY:
v.x = event->x;
v.y = event->y;
if(event->type == GDK_ENTER_NOTIFY) { viewToImage(&v);
v.x = event->x;
v.y = event->y;
viewToImage(&v); setHoveredVertex(&v);
break;
for(i = 0; i < getLevel()->nRooms; i++) { case GDK_LEAVE_NOTIFY:
if(vertexInPolygon(&v, &getLevel()->rooms[i].polygon)) { setHoveredVertex(NULL);
setHoveredRoom(&getLevel()->rooms[i]);
break;
}
}
} }
gtk_widget_queue_draw(drawingArea); gtk_widget_queue_draw(drawingArea);
} }
gboolean motionNotifyEvent(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) { gboolean motionNotifyEvent(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) {
int i; VERTEX v;
static VERTEX v, v_last = {0, 0}; ROOM *last = getHoveredRoom();
LINE line;
gboolean changed = FALSE;
v.x = event->x; v.x = event->x;
v.y = event->y; v.y = event->y;
viewToImage(&v); viewToImage(&v);
line.v1 = v_last; setHoveredVertex(&v);
line.v2 = v;
for(i = 0; i < getLevel()->nRooms; i++) { if(getHoveredRoom() != last || getEditMode() == EDIT_MODE_ADD)
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)
gtk_widget_queue_draw(drawingArea); gtk_widget_queue_draw(drawingArea);
v_last = v;
} }
static void destroy(GtkWidget *widget, gpointer data) { 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))); getActiveRoom()->name = strdup(gtk_entry_get_text(GTK_ENTRY(entryName)));
} }
static GtkWidget* createSidebar() { static void sidebarButtonClicked(GtkButton *button, gpointer user_data) {
GtkWidget *widget, *labelRoomInfo, *labelName, *tableRoomData, *labelAreaLabel, *labelPerimeterLabel; if(button == GTK_BUTTON(buttonAdd)) {
startAddMode();
updateSidebar();
widget = gtk_vbox_new(FALSE, 0); 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 *sidebar, *labelRoomInfo, *labelName;
GtkWidget *tableRoomData, *labelAreaLabel, *labelPerimeterLabel;
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); labelRoomInfo = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(labelRoomInfo), "<b>Room info:</b>"); gtk_label_set_markup(GTK_LABEL(labelRoomInfo), "<b>Room info:</b>");
gtk_misc_set_alignment(GTK_MISC(labelRoomInfo), 0.0, 0.5); 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:"); labelName = gtk_label_new("Name:");
gtk_misc_set_alignment(GTK_MISC(labelName), 0.0, 0.5); 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(); entryName = gtk_entry_new();
gtk_widget_set_sensitive(entryName, FALSE); gtk_widget_set_sensitive(entryName, FALSE);
g_signal_connect(G_OBJECT(entryName), "changed", G_CALLBACK(sidebarNameChanged), NULL); 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); tableRoomData = gtk_table_new(2, 2, FALSE);
gtk_table_set_row_spacings(GTK_TABLE(tableRoomData), 5); gtk_table_set_row_spacings(GTK_TABLE(tableRoomData), 5);
gtk_table_set_col_spacings(GTK_TABLE(tableRoomData), 10); 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:"); labelAreaLabel = gtk_label_new("Room area:");
gtk_misc_set_alignment(GTK_MISC(labelAreaLabel), 0.0, 0.5); 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_misc_set_alignment(GTK_MISC(labelPerimeter), 1.0, 0.5);
gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelPerimeter, 1, 2, 1, 2); 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* createMainWindow() {
GtkWidget *window, *vbox, *hPaned, *table, *vScroll, *hScroll; GtkWidget *window, *hPaned, *vbox, *table, *vScroll, *hScroll, *sidebar;
GdkColor color = {0, 0, 0, 0}; 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), "motion-notify-event", G_CALLBACK(motionNotifyEvent), NULL);
g_signal_connect(G_OBJECT(drawingArea), "scroll-event", G_CALLBACK(scrollEvent), 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_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); 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)); 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_paned_pack2(GTK_PANED(hPaned), sidebar, FALSE, TRUE);
gtk_widget_show_all(vbox); gtk_widget_show_all(vbox);
gtk_widget_hide(sidebarAdd);
return window; return window;
} }
@ -286,25 +307,43 @@ GtkWidget* createMainWindow() {
void updateSidebar() { void updateSidebar() {
gchar *string; gchar *string;
switch(getEditMode()) {
case EDIT_MODE_VIEW:
case EDIT_MODE_SELECTED:
gtk_widget_hide(sidebarAdd);
gtk_widget_show(sidebarView);
if(getActiveRoom()) { if(getActiveRoom()) {
gtk_entry_set_text(GTK_ENTRY(entryName), getActiveRoom()->name); gtk_entry_set_text(GTK_ENTRY(entryName), getActiveRoom()->name);
gtk_widget_set_sensitive(entryName, TRUE); gtk_widget_set_sensitive(entryName, TRUE);
string = g_strdup_printf("%.2f", polygonArea(&getActiveRoom()->polygon)); string = g_strdup_printf("%.2f", polygonArea(&getActiveRoom()->polygon));
gtk_label_set_text(GTK_LABEL(labelArea), string); gtk_label_set_text(GTK_LABEL(labelArea), string);
g_free(string); g_free(string);
string = g_strdup_printf("%.2f", polygonPerimeter(&getActiveRoom()->polygon)); string = g_strdup_printf("%.2f", polygonPerimeter(&getActiveRoom()->polygon));
gtk_label_set_text(GTK_LABEL(labelPerimeter), string); gtk_label_set_text(GTK_LABEL(labelPerimeter), string);
g_free(string); g_free(string);
} }
else { else {
gtk_entry_set_text(GTK_ENTRY(entryName), ""); gtk_entry_set_text(GTK_ENTRY(entryName), "");
gtk_widget_set_sensitive(entryName, FALSE); gtk_widget_set_sensitive(entryName, FALSE);
gtk_label_set_text(GTK_LABEL(labelArea), NULL); gtk_label_set_text(GTK_LABEL(labelArea), NULL);
gtk_label_set_text(GTK_LABEL(labelPerimeter), 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);
}
} }
} }

View file

@ -5,22 +5,21 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
VERTEX vertices[4] = {{0,-1}, {1,0}, {0,1}, {-1,0}}; LEVEL *lvl = calloc(1, sizeof(LEVEL));
ROOM room = {{sizeof(vertices)/sizeof(vertices[0]), vertices}, calloc(1, sizeof(unsigned char))};
LEVEL lvl = {1, &room};
GtkWidget *window; GtkWidget *window;
setLevel(lvl);
gtk_init(&argc, &argv); gtk_init(&argc, &argv);
window = createMainWindow(); window = createMainWindow();
setLevel(&lvl);
gtk_widget_show(window); gtk_widget_show(window);
gtk_main(); gtk_main();
free(room.name); freeLevel(lvl);
return 0; return 0;
} }