#include "window.h" #include "ui.h" #include "edit.h" #include "draw.h" #include "geometry.h" #include "level.h" #include #include #include static GtkWidget *drawingArea = NULL, *sidebarView = NULL, *sidebarAdd = NULL; static GtkAdjustment *hAdjustment = NULL, *vAdjustment = NULL; static GtkWidget *entryName, *labelArea = NULL, *labelPerimeter = NULL, *buttonAdd = NULL, *buttonAddDo = NULL; static gboolean deleteEvent(GtkWidget *widget, GdkEvent *event, gpointer data) { return FALSE; } static gboolean scrollEvent(GtkWidget *widget, GdkEventScroll *event, gpointer user_data) { const gdouble x = event->x/widget->allocation.width, y = event->y/widget->allocation.height; switch(event->direction) { case GDK_SCROLL_UP: zoomIn(1.1, x, y); break; case GDK_SCROLL_DOWN: zoomOut(1.1, x, y); } } static gboolean buttonEvent(GtkWidget *widget, GdkEventButton *event, gpointer user_data) { Vertex v(event->x, event->y); switch(event->type) { case GDK_BUTTON_PRESS: switch(event->button) { case 1: 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(); } } gtk_widget_queue_draw(drawingArea); } } return FALSE; } gboolean crossingNotifyEvent(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) { Vertex v(event->x, event->y); switch(event->type) { case GDK_ENTER_NOTIFY: viewToImage(&v); setHoveredVertex(&v); break; case GDK_LEAVE_NOTIFY: setHoveredVertex(NULL); } gtk_widget_queue_draw(drawingArea); } gboolean motionNotifyEvent(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) { Vertex v(event->x, event->y); ROOM *last = getHoveredRoom(); viewToImage(&v); setHoveredVertex(&v); if(getHoveredRoom() != last || getEditMode() == EDIT_MODE_ADD) gtk_widget_queue_draw(drawingArea); } static void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); } static void refreshScrolling() { if(getImageWidth() < drawingArea->allocation.width) setXTranslate((getImageWidth()-drawingArea->allocation.width)/2); else setXTranslate(gtk_adjustment_get_value(hAdjustment)); if(getImageHeight() < drawingArea->allocation.height) setYTranslate((getImageHeight()-drawingArea->allocation.height)/2); else setYTranslate(gtk_adjustment_get_value(vAdjustment)); gtk_widget_queue_draw(drawingArea); } static void updateScrollbars(double x, double y) { const gdouble imageWidth = getImageWidth(), imageHeight = getImageHeight(); const gdouble width = drawingArea->allocation.width, height = drawingArea->allocation.height; gdouble upper, pageSize, value; gdk_window_freeze_updates(drawingArea->window); g_object_get(G_OBJECT(hAdjustment), "upper", &upper, "page_size", &pageSize, NULL); g_object_set(G_OBJECT(hAdjustment), "upper", imageWidth, "page_size", width, NULL); gtk_adjustment_changed(hAdjustment); if((pageSize > upper && width < imageWidth) || upper == 0) value = (imageWidth-width)/2; else value = (gtk_adjustment_get_value(hAdjustment)+pageSize*x)/upper*imageWidth-width*x; gtk_adjustment_set_value(hAdjustment, MAX(MIN(value, imageWidth-width), 0)); g_object_get(G_OBJECT(vAdjustment), "upper", &upper, "page_size", &pageSize, NULL); g_object_set(G_OBJECT(vAdjustment), "upper", imageHeight, "page_size", height, NULL); gtk_adjustment_changed(vAdjustment); if((pageSize > upper && height < imageHeight) || upper == 0) value = (imageHeight-height)/2; else value = (gtk_adjustment_get_value(vAdjustment)+pageSize*y)/upper*imageHeight-height*y; gtk_adjustment_set_value(vAdjustment, MAX(MIN(value, imageHeight-height), 0)); gdk_window_thaw_updates(drawingArea->window); refreshScrolling(); } static void updateScrollbarsCentered() { updateScrollbars(0.5, 0.5); } static void sidebarNameChanged(GtkEditable *editable, gpointer user_data) { if(getActiveRoom() == NULL) return; free(getActiveRoom()->name); 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 *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); 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(sidebarView), labelRoomInfo, 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(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(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(sidebarView), tableRoomData, FALSE, FALSE, 5); labelAreaLabel = gtk_label_new("Room area:"); gtk_misc_set_alignment(GTK_MISC(labelAreaLabel), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelAreaLabel, 0, 1, 0, 1); labelArea = gtk_label_new(NULL); gtk_misc_set_alignment(GTK_MISC(labelArea), 1.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelArea, 1, 2, 0, 1); labelPerimeterLabel = gtk_label_new("Room perimeter:"); gtk_misc_set_alignment(GTK_MISC(labelPerimeterLabel), 0.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelPerimeterLabel, 0, 1, 1, 2); labelPerimeter = gtk_label_new(NULL); gtk_misc_set_alignment(GTK_MISC(labelPerimeter), 1.0, 0.5); gtk_table_attach_defaults(GTK_TABLE(tableRoomData), labelPerimeter, 1, 2, 1, 2); 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, *hPaned, *vbox, *table, *vScroll, *hScroll, *sidebar; GdkColor color = {0, 0, 0, 0}; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(window), 640, 480); g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK(deleteEvent), NULL); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(window), vbox); gtk_box_pack_start(GTK_BOX(vbox), getMenu(), FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), getToolbar(), FALSE, FALSE, 0); gtk_window_add_accel_group(GTK_WINDOW(window), getAccels()); hPaned = gtk_hpaned_new(); gtk_box_pack_end(GTK_BOX(vbox), hPaned, TRUE, TRUE, 0); table = gtk_table_new(2, 2, FALSE); gtk_paned_pack1(GTK_PANED(hPaned), table, TRUE, TRUE); drawingArea = gtk_drawing_area_new(); gtk_widget_modify_bg(drawingArea, (GtkStateType)GTK_WIDGET_STATE(drawingArea), &color); g_signal_connect(G_OBJECT(drawingArea), "configure-event", G_CALLBACK(updateScrollbarsCentered), NULL); g_signal_connect(G_OBJECT(drawingArea), "expose-event", G_CALLBACK(drawTopView), NULL); g_signal_connect(G_OBJECT(drawingArea), "button-press-event", G_CALLBACK(buttonEvent), NULL); g_signal_connect(G_OBJECT(drawingArea), "button-release-event", G_CALLBACK(buttonEvent), NULL); g_signal_connect(G_OBJECT(drawingArea), "enter-notify-event", G_CALLBACK(crossingNotifyEvent), NULL); g_signal_connect(G_OBJECT(drawingArea), "leave-notify-event", G_CALLBACK(crossingNotifyEvent), 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); gtk_widget_add_events(drawingArea, GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_table_attach(GTK_TABLE(table), drawingArea, 0, 1, 0, 1, (GtkAttachOptions)(GTK_FILL|GTK_EXPAND|GTK_SHRINK), (GtkAttachOptions)(GTK_FILL|GTK_EXPAND|GTK_SHRINK), 0, 0); hAdjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 0, 10, 100, 100)); hScroll = gtk_hscrollbar_new(hAdjustment); g_signal_connect(G_OBJECT(hScroll), "value-changed", G_CALLBACK(refreshScrolling), NULL); gtk_table_attach(GTK_TABLE(table), hScroll, 0, 1, 1, 2, (GtkAttachOptions)(GTK_FILL|GTK_EXPAND|GTK_SHRINK), (GtkAttachOptions)0, 0, 0); vAdjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 0, 10, 100, 100)); vScroll = gtk_vscrollbar_new(vAdjustment); g_signal_connect(G_OBJECT(vScroll), "value-changed", G_CALLBACK(refreshScrolling), NULL); gtk_table_attach(GTK_TABLE(table), vScroll, 1, 2, 0, 1, (GtkAttachOptions)0, (GtkAttachOptions)(GTK_FILL|GTK_EXPAND|GTK_SHRINK), 0, 0); sidebar = createSidebar(); gtk_paned_pack2(GTK_PANED(hPaned), sidebar, FALSE, TRUE); gtk_widget_show_all(vbox); gtk_widget_hide(sidebarAdd); return window; } void updateSidebar() { gchar *string; 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); } } } void zoomIn(double factor, double x, double y) { setScale(getScale()*factor); updateScrollbars(x, y); } void zoomOut(double factor, double x, double y) { setScale(getScale()/factor); updateScrollbars(x, y); } void zoomInCentered(double factor) { zoomIn(factor, 0.5, 0.5); } void zoomOutCentered(double factor) { zoomOut(factor, 0.5, 0.5); }