#include "window.h" #include "ui.h" #include "edit.h" #include "draw.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 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(float x, float 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 gboolean deleteEvent(GtkWidget *widget, GdkEvent *event, gpointer data) { return FALSE; } static void realize(GtkWidget *widget, gpointer data) { GdkGLContext *context = gtk_widget_get_gl_context(widget); GdkGLDrawable *drawable = gtk_widget_get_gl_drawable(widget); if(!gdk_gl_drawable_gl_begin(drawable, context)) return; glClearColor(0.0, 0.0, 0.0, 1.0); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); glViewport(0, 0, widget->allocation.width, widget->allocation.height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(widget->allocation.width != 0 && widget->allocation.height != 0) { glTranslatef(-1, 1, 0); glScalef(2.0f/widget->allocation.width, -2.0f/widget->allocation.height, 1); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gdk_gl_drawable_gl_end(drawable); } static gboolean configureEvent(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { GdkGLContext *context = gtk_widget_get_gl_context(widget); GdkGLDrawable *drawable = gtk_widget_get_gl_drawable(widget); if(!gdk_gl_drawable_gl_begin(drawable, context)) return FALSE; glViewport(0, 0, widget->allocation.width, widget->allocation.height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(widget->allocation.width != 0 && widget->allocation.height != 0) { glTranslatef(-1, 1, 0); glScalef(2.0f/widget->allocation.width, -2.0f/widget->allocation.height, 1); } gdk_gl_drawable_gl_end(drawable); updateScrollbars(0.5, 0.5); return TRUE; } static gboolean scrollEvent(GtkWidget *widget, GdkEventScroll *event, gpointer user_data) { const float x = event->x/widget->allocation.width, y = event->y/widget->allocation.height; switch(event->direction) { case GDK_SCROLL_UP: zoomIn(1.1f, x, y); break; case GDK_SCROLL_DOWN: zoomOut(1.1f, 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(); break; case EDIT_MODE_ADD: viewToImage(&v); if(isVertexOk(&v)) { getActiveRoom()->push_back(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 sidebarNameChanged(GtkEditable *editable, gpointer user_data) { if(getActiveRoom() == NULL) return; getActiveRoom()->setName(std::string(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()->size() > 2 && isPolygonOk(getActiveRoom())) { getLevel()->push_back(*getActiveRoom()); setActiveRoom(&getLevel()->back()); } 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(GdkGLConfig *glconfig) { 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_set_gl_capability(drawingArea, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); gtk_widget_set_double_buffered(drawingArea, FALSE); g_signal_connect(G_OBJECT(drawingArea), "realize", G_CALLBACK(realize), NULL); g_signal_connect(G_OBJECT(drawingArea), "configure-event", G_CALLBACK(configureEvent), 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()->getName().c_str()); gtk_widget_set_sensitive(entryName, TRUE); string = g_strdup_printf("%.2f", getActiveRoom()->area()); gtk_label_set_text(GTK_LABEL(labelArea), string); g_free(string); string = g_strdup_printf("%.2f", getActiveRoom()->perimeter()); 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()->size() > 2 && isPolygonOk(getActiveRoom())) gtk_widget_set_sensitive(buttonAddDo, TRUE); else gtk_widget_set_sensitive(buttonAddDo, FALSE); } } } void zoomIn(float factor, float x, float y) { setScale(getScale()*factor); updateScrollbars(x, y); } void zoomOut(float factor, float x, float y) { setScale(getScale()/factor); updateScrollbars(x, y); } void zoomInCentered(float factor) { zoomIn(factor, 0.5, 0.5); } void zoomOutCentered(float factor) { zoomOut(factor, 0.5, 0.5); }