#include "RenderArea.h" #include #include #include #include #include #include namespace ZoomEdit { namespace Gui { GdkGLConfig *RenderArea::glconfig = NULL; RenderArea::RenderArea(BaseObjectType *cobject, const Glib::RefPtr &xml) : Gtk::DrawingArea(cobject), zoomLevel(0), scale(100), xCenter(0), yCenter(0) { if(!glconfig) { glconfig = gdk_gl_config_new_by_mode((GdkGLConfigMode)(GDK_GL_MODE_RGB | GDK_GL_MODE_DOUBLE)); if(!glconfig) glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB); // Hmm, can't find double buffered config if(!glconfig) { std::cerr << "*** No appropriate OpenGL-capable visual found." << std::endl; std::exit(1); } } signal_realize().connect(sigc::mem_fun(this, &RenderArea::onRealize)); signal_configure_event().connect(sigc::mem_fun(this, &RenderArea::onConfigureEvent)); signal_expose_event().connect(sigc::mem_fun(this, &RenderArea::onExposeEvent)); signal_scroll_event().connect(sigc::mem_fun(this, &RenderArea::onScrollEvent)); Gtk::ToolButton *button; xml->get_widget("ToolButtonZoomIn", button); if(button) button->signal_clicked().connect(sigc::bind(sigc::mem_fun(this, &RenderArea::zoom), 2, 0.5f, 0.5f)); xml->get_widget("ToolButtonZoomOut", button); if(button) button->signal_clicked().connect(sigc::bind(sigc::mem_fun(this, &RenderArea::zoom), -2, 0.5f, 0.5f)); xml->get_widget("Hscrollbar", hScrollbar); xml->get_widget("Vscrollbar", vScrollbar); gtk_widget_set_gl_capability(GTK_WIDGET(cobject), glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); } void RenderArea::onRealize() { if(!gdkGLBegin()) return; glClearColor(0, 0, 0, 0); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); glEnable(GL_POINT_SMOOTH); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gdkGLEnd(); } bool RenderArea::onConfigureEvent(GdkEventConfigure *event) { updateViewport(); return true; } bool RenderArea::onExposeEvent(GdkEventExpose *event) { if(!gdkGLBegin()) return false; glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glScalef(scale, scale, 1); glTranslatef(-xCenter, -yCenter, 0); drawGrid(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); gdkSwapBuffers(); gdkGLEnd(); return true; } bool RenderArea::onScrollEvent(GdkEventScroll *event) { switch(event->direction) { case GDK_SCROLL_UP: zoom(1, event->x/get_width(), event->y/get_height()); return true; case GDK_SCROLL_DOWN: zoom(-1, event->x/get_width(), event->y/get_height()); return true; default: return false; } } void RenderArea::zoom(int zoom, float x, float y) { zoomLevel = std::max(std::min(zoomLevel + zoom, 50), -100); scale = 100*std::pow(1.1f, zoomLevel); updateScrollbars(x, y); } void RenderArea::updateViewport() { if(!gdkGLBegin()) return; glViewport(0, 0, get_width(), get_height()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(get_width() != 0 && get_height() != 0) glScalef(2.0f/get_width(), -2.0f/get_height(), 1); gdkGLEnd(); updateScrollbars(); } void RenderArea::updateScrollbars(float x, float y) { const gdouble imageWidth = getImageWidth(), imageHeight = getImageHeight(); const gdouble minX = -imageWidth/2, maxX = imageWidth/2; const gdouble minY = -imageHeight/2, maxY = imageHeight/2; const gdouble width = getViewWidth(), height = getViewHeight(); gdouble lower, upper, pageSize, value; get_window()->freeze_updates(); if(hScrollbar) { lower = hScrollbar->get_adjustment()->get_lower(); upper = hScrollbar->get_adjustment()->get_upper(); pageSize = hScrollbar->get_adjustment()->get_page_size(); hScrollbar->get_adjustment()->set_lower(minX + width/2); hScrollbar->get_adjustment()->set_upper(maxX + width/2); hScrollbar->get_adjustment()->set_page_size(width); if(pageSize > (upper-lower) && width < imageWidth) value = 0; else value = hScrollbar->get_value() + (x-0.5)*(pageSize-width); hScrollbar->set_value(std::max(std::min(value, maxX - width/2), minX + width/2)); } if(vScrollbar) { lower = vScrollbar->get_adjustment()->get_lower(); upper = vScrollbar->get_adjustment()->get_upper(); pageSize = vScrollbar->get_adjustment()->get_page_size(); vScrollbar->get_adjustment()->set_lower(minY + height/2); vScrollbar->get_adjustment()->set_upper(maxY + height/2); vScrollbar->get_adjustment()->set_page_size(height); if(pageSize > (upper-lower) && height < imageHeight) value = 0; else value = vScrollbar->get_value() + (y-0.5)*(pageSize-height); vScrollbar->set_value(std::max(std::min(value, maxY - height/2), minY + height/2)); } get_window()->thaw_updates(); updateScrolling(); } void RenderArea::updateScrolling() { if(hScrollbar) { if(getImageWidth() < getViewWidth()) xCenter = 0; else xCenter = hScrollbar->get_value(); } if(vScrollbar) { if(getImageHeight() < getViewHeight()) yCenter = 0; else yCenter = vScrollbar->get_value(); } queue_draw(); } void RenderArea::drawGrid() { float depth = 1.25f + 0.04f*zoomLevel; float depth2 = std::floor(depth); float step = std::pow(0.1f, depth2); float f; int i; float x1 = xCenter-getViewWidth()/2, y1 = yCenter-getViewHeight()/2; float x2 = xCenter+getViewWidth()/2, y2 = yCenter+getViewHeight()/2; glLineWidth(1.0f); glBegin(GL_LINES); for(i = 0; 0.4f*(depth-depth2+i-1) < 0.5f; i++) { f = std::min(0.4f*(depth-depth2+i), 0.5f); glColor3f(f, f, f); for(f = x1 - std::fmod(x1, step); f <= x2; f+=step) { glVertex2f(f, y1); glVertex2f(f, y2); } for(f = y1 - std::fmod(y1, step); f <= y2; f+=step) { glVertex2f(x1, f); glVertex2f(x2, f); } step *= 10; } glEnd(); } } }