/*************************************************************************** sq_glwidget.cpp - description ------------------- begin : Mon Mar 15 2004 copyright : (C) 2004 by Baryshev Dmitry email : ksquirrel.iv@gmail.com ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef KSQUIRREL_PART #include "ksquirrel.h" #include "sq_widgetstack.h" #include "sq_glview.h" #include "sq_fileiconview.h" #include "sq_diroperator.h" #include "sq_hloptions.h" #include "sq_previewwidget.h" #include "sq_tabopendialog.h" #endif #include "sq_popupmenu.h" #include "sq_libraryhandler.h" #include "sq_config.h" #include "sq_glwidget_helpers.h" #include "sq_glwidget.h" #include "sq_glu.h" #include "sq_codecsettings.h" #include "sq_glselectionpainter.h" #include "sq_utils.h" #include "sq_errorstring.h" #include "fmt_filters.h" #include #include #include #include #ifdef SQ_HAVE_KEXIF #include #endif // is it enough ? #define SQ_FLOAT_SIGMA 1e-5 #define ISFLOAT(a,b) (fabs(a - b) < SQ_FLOAT_SIGMA) #define ISFLOAT1(a) ISFLOAT(a, 1.0) #define ISFLOAT0(a) ISFLOAT(a, 0.0) #define SQ_TAB_TEXT_LENGTH 30 /* ***************************************************************************************** */ SQ_GLWidget * SQ_GLWidget::m_instance = 0; static const int timer_delay_file = 5; static const double rad_const = 3.14159265358979323846 / 180.0; static const float SQ_WINDOW_BACKGROUND_POS = -1000.0; static const float SQ_IMAGE_CHECKER_POS = -999.0; static const float SQ_FIRST_FRAME_POS = -998.0; static const float SQ_MARKS_POS = -997.0; static const float SQ_FIRST_TILE_LAYER = -995.0; static const float SQ_ONSCREEN_LAYER = 10000.0; /* ***************************************************************************************** */ SQ_GLWidget::SQ_GLWidget(TQWidget *parent, const char *name) : TQGLWidget(parent, name) { kdDebug() << "+SQ_GLWidget" << endl; // init all variables... m_instance = this; #ifdef KSQUIRREL_PART connect(&t_glv, TQ_SIGNAL(message(const TQString &)), this, TQ_SIGNAL(message(const TQString &))); #endif zoomMenu = 0; selectionMenu = 0; images = 0; parts_broken = 0; ac = new TDEActionCollection(this, this, "GLWidget actionCollection"); changed = blocked = decoded = reset_mode = false; movetype = -1; buffer = new RGBA [512 * 512]; zoomFactor = 1.0; old_id = -1; menu = new TQPopupMenu(this); hackResizeGL = false; lastCopy = KURL::fromPathOrURL("/"); oldZoom = -1; percentsLabel = new TQLabel(this); percentsLabel->move(4, 4); percentsLabel->hide(); tabold = tab = &taborig; tmp = new KTempFile; tmp->setAutoDelete(true); tmp->close(); SQ_Config::instance()->setGroup("GL view"); zoom_type = SQ_Config::instance()->readNumEntry("zoom type", 2); linear = SQ_Config::instance()->readBoolEntry("zoom_nice", true); // load background for transparent image BGquads = TQImage(locate("data", "images/checker.png")); if(BGquads.isNull()) { BGquads = TQImage(32, 32, 32); BGquads.setAlphaBuffer(true); BGquads.fill(0); } bindChecker = true; zoomfactor = SQ_Config::instance()->readNumEntry("zoom", 25); movefactor = SQ_Config::instance()->readNumEntry("move", 5); rotatefactor = SQ_Config::instance()->readNumEntry("angle", 90); // load cursors setCursor(KCursor::arrowCursor()); setFocusPolicy(TQWidget::WheelFocus); setAcceptDrops(true); // popup menu with image pages images = new TDEPopupMenu; images->setCheckable(true); // create actions createActions(); // create toolbars createToolbar(); // create tickmarks createMarks(); initAccelsAndMenu(); enableActions(false); KCursor::setAutoHideCursor(this, true); KCursor::setHideCursorDelay(2500); #ifndef KSQUIRREL_PART timer_prev = new TQTimer(this); timer_next = new TQTimer(this); TQ_CHECK_PTR(timer_prev); TQ_CHECK_PTR(timer_next); connect(timer_prev, TQ_SIGNAL(timeout()), SQ_WidgetStack::instance(), TQ_SLOT(emitPreviousSelected())); connect(timer_next, TQ_SIGNAL(timeout()), SQ_WidgetStack::instance(), TQ_SLOT(emitNextSelected())); #endif timer_anim = new TQTimer(this); TQ_CHECK_PTR(timer_anim); connect(timer_anim, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotAnimateNext())); connect(images, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetCurrentImage(int))); connect(images, TQ_SIGNAL(aboutToHide()), this, TQ_SLOT(slotImagesHidden())); connect(images, TQ_SIGNAL(aboutToShow()), this, TQ_SLOT(slotImagesShown())); gls = new SQ_GLSelectionPainter(this); } SQ_GLWidget::~SQ_GLWidget() { kdDebug() << "-SQ_GLWidget" << endl; delete gls; delete parts_broken; removeCurrentTabs(); delete selectionMenu; delete zoomMenu; delete images; delete [] buffer; delete tmp; } // Initialize OpenGL context. Used internally by TQGLWidget. void SQ_GLWidget::initializeGL() { setClearColor(); glClearDepth(1.0); glEnable(GL_DEPTH_TEST); glEnable(GL_ALPHA_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glShadeModel(GL_FLAT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); // finally, clear glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // create "broken" image initBrokenImage(); initMarks(); } // Resize OpenGL context. Used internally by TQGLWidget. void SQ_GLWidget::resizeGL(int width, int height) { gls->setSourceSize(width, height); // set new viewport glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); // O(0,0) will be in the center of the window glOrtho(-width/2, width/2, -height/2, height/2, 0.1f, 10000.0); // camera setup SQ_GLU::gluLookAt(0,0,1, 0,0,0, 0,1,0); glMatrixMode(GL_MODELVIEW); if(decoded && !hackResizeGL) slotZoomIfLess(); hackResizeGL = false; } /* * Fill a w x h region with texture. Generate texture if needed. */ void SQ_GLWidget::draw_background(void *bits, unsigned int *tex, int dim, GLfloat w, GLfloat h, bool &bind, bool deleteOld) { float half_w, half_h; half_w = w / 2.0; half_h = h / 2.0; // bind texture ? if(bind) { // delete old texture before binding ? if(deleteOld) glDeleteTextures(1, tex); // generate and bind texture glGenTextures(1, tex); glBindTexture(GL_TEXTURE_2D, *tex); // setup parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // assign image to texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dim, dim, 0, GL_RGBA, GL_UNSIGNED_BYTE, bits); bind = false; } else glBindTexture(GL_TEXTURE_2D, *tex); // draw glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(-half_w, half_h); glTexCoord2f(w/(GLfloat)dim, 0.0); glVertex2f(half_w, half_h); glTexCoord2f(w/(GLfloat)dim, h/(GLfloat)dim); glVertex2f(half_w, -half_h); glTexCoord2f(0.0, h/(GLfloat)dim); glVertex2f(-half_w, -half_h); glEnd(); } // Redraw OpenGL context. Used internally by TQGLWidget. void SQ_GLWidget::paintGL() { int z; // clear glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if(gls->valid()) { matrix_push(); matrix_pure_reset(); TQPoint p = gls->center(); // move to selection center MATRIX_X = p.x(); MATRIX_Y = p.y(); write_gl_matrix(); gls->draw(); matrix_pop(); write_gl_matrix(); } glEnable(GL_TEXTURE_2D); // draw window background ? SQ_Config::instance()->setGroup("GL view"); if(SQ_Config::instance()->readNumEntry("GL view background type", 1) == 2) { static bool del = false; matrix_push(); matrix_pure_reset(); matrix_move_z(SQ_WINDOW_BACKGROUND_POS); draw_background(BGpixmap.bits(), &texPixmap, BGpixmap.width(), width(), height(), changed, del); del = true; matrix_pop(); write_gl_matrix(); } // draw image if(!reset_mode && decoded) { SQ_Config::instance()->setGroup("GL view"); fmt_image *im = &tab->finfo.image[tab->current]; // if the image is transparent, and we should draw background for image if(im->hasalpha && SQ_Config::instance()->readBoolEntry("alpha_bkgr", true)) { GLfloat w = (float)im->w / 2.0, h = (float)im->h / 2.0; static const GLdouble eq[4][4] = { {0.0, 1.0, 0.0, 0.0}, {1.0, 0.0, 0.0, 0.0}, {0.0, -1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0, 0.0} }; // we will draw background for transparent image (quads) within // entire window, and cut off useless regions with clip planes glPushMatrix(); glTranslatef(-w, -h, 0.0); glClipPlane(GL_CLIP_PLANE0, eq[0]); glClipPlane(GL_CLIP_PLANE1, eq[1]); glEnable(GL_CLIP_PLANE0); glEnable(GL_CLIP_PLANE1); glPopMatrix(); glPushMatrix(); glTranslatef(w, h, 0.0); glClipPlane(GL_CLIP_PLANE2, eq[2]); glClipPlane(GL_CLIP_PLANE3, eq[3]); glEnable(GL_CLIP_PLANE2); glEnable(GL_CLIP_PLANE3); glPopMatrix(); // draw background matrix_push(); matrix_pure_reset(); matrix_move_z(SQ_IMAGE_CHECKER_POS); draw_background(BGquads.bits(), &texQuads, 32, width(), height(), bindChecker, !bindChecker); matrix_pop(); write_gl_matrix(); // don't need planes any more... glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE0); } matrix_move_z(SQ_FIRST_FRAME_POS); Parts *pt = tab->broken ? parts_broken : &tab->parts[tab->current]; // draw current image int toy = pt->tilesy.size(); int tox = pt->tilesx.size(); for(z = 0;z < toy;z++) if(glIsList(pt->m_parts[z * tox].list)) glCallList(pt->m_parts[z * tox].list); // draw tickmarks ("broken" image won't have tickmarks) if(!tab->broken && marks && SQ_Config::instance()->readBoolEntry("marks", true)) { GLfloat zum = getZoom(); GLfloat x = fabsf(pt->m_parts[0].x1) * zum, y = pt->m_parts[0].y1 * zum; GLfloat X = MATRIX_X, Y = MATRIX_Y; if(x < 0.0) x = -x; const GLfloat ly = y+16, ry = -y-16; const GLfloat lx = x+16, rx = -x-16; matrix_push(); matrix_pure_reset(); MATRIX_X = X; MATRIX_Y = Y; matrix_rotate2(tab->curangle); matrix_move_z(SQ_MARKS_POS); GLfloat coords[4][8] = { {rx, ly, -x, ly, -x, y, rx, y}, {x, ly, lx, ly, lx, y, x, y}, {x, -y, lx, -y, lx, ry, x, ry}, {rx, -y, -x, -y, -x, ry, rx, ry} }; for(z = 0;z < 4;z++) { glBindTexture(GL_TEXTURE_2D, mark[z]); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(coords[z][0], coords[z][1]); glTexCoord2f(1.0, 0.0); glVertex2f(coords[z][2], coords[z][3]); glTexCoord2f(1.0, 1.0); glVertex2f(coords[z][4], coords[z][5]); glTexCoord2f(0.0, 1.0); glVertex2f(coords[z][6], coords[z][7]); glEnd(); } matrix_pop(); write_gl_matrix(); } } glDisable(GL_TEXTURE_2D); matrixChanged(); if(!tab->broken && tab->total > 1) frameChanged(); } /* * Change statusbar info according with * current matrix (it shows current zoom & angle values). */ void SQ_GLWidget::matrixChanged() { TQString str; float m = getZoom(); float fzoom = m * 100.0; float z = (m < 1.0) ? 1.0/m : m; // construct zoom str = TQString::fromLatin1("%1% [%2:%3]") .arg(fzoom, 0, 'f', 1) .arg((m < 1.0)?1.0:z, 0, 'f', 1) .arg((m > 1.0)?1.0:z, 0, 'f', 1); #ifndef KSQUIRREL_PART SQ_GLView::window()->sbarWidget("SBGLZoom")->setText(str); #else t_glv.sbarWidget("SBGLZoom")->setText(str); #endif // construct rotation angle str = TQString::fromLatin1("%1%2 %3 deg") .arg((tab->isflippedV)?"V":"") .arg((tab->isflippedH)?"H":"") .arg(tab->curangle, 0, 'f', 1); #ifndef KSQUIRREL_PART SQ_GLView::window()->sbarWidget("SBGLAngle")->setText(str); #else t_glv.sbarWidget("SBGLAngle")->setText(str); #endif } /* * Mouse wheel event. Let's load next/previous image, or * zoom in/zoom out (depends on settings). */ void SQ_GLWidget::wheelEvent(TQWheelEvent *e) { if(e->delta() < 0 && e->state() == TQt::NoButton) { #ifndef KSQUIRREL_PART SQ_Config::instance()->setGroup("GL view"); // load next file in current directory if(SQ_Config::instance()->readNumEntry("scroll", 0)) slotNext(); else #endif slotZoomPlus(); } else if(e->delta() > 0 && e->state() == TQt::NoButton) { #ifndef KSQUIRREL_PART SQ_Config::instance()->setGroup("GL view"); if(SQ_Config::instance()->readNumEntry("scroll", 0)) slotPrev(); else #endif slotZoomMinus(); } // some special bindings: // if CTRL key is pressed, zoom 2x or 0.5x else if(e->delta() < 0 && e->state() == TQt::ControlButton) matrix_zoom(2.0); else if(e->delta() > 0 && e->state() == TQt::ControlButton) matrix_zoom(0.5f); else if(e->delta() < 0 && e->state() == TQt::ShiftButton) slotZoomPlus(); else if(e->delta() > 0 && e->state() == TQt::ShiftButton) slotZoomMinus(); } // User pressed mouse button down. void SQ_GLWidget::mousePressEvent(TQMouseEvent *e) { setFocus(); // left button, update cursor if(e->button() == TQt::LeftButton && e->state() == TQt::NoButton && tab->glselection == -1) { #ifndef KSQUIRREL_PART TQTime t = TQTime::currentTime(); SQ_Config::instance()->setGroup("GL view"); int dc = SQ_Config::instance()->readNumEntry("double_click", 0); if(dc && clickTime.isValid() && clickTime.msecsTo(t) <= TDEApplication::doubleClickInterval()) { if(dc == 1) KSquirrel::app()->closeGLWidget(); else toggleFullScreen(); return; } else clickTime = t; #endif setCursor(KCursor::sizeAllCursor()); xmoveold = e->x(); ymoveold = e->y(); movetype = 1; } // left button + SHIFT, let's start drawing zoom frame else if(e->button() == TQt::LeftButton && (e->state() == TQt::ShiftButton || tab->glselection != -1)) { // stop animation! stopAnimation(); // update cursor to crosshair setCursor(KCursor::crossCursor()); if(tab->glselection == SQ_GLSelectionPainter::Rectangle || tab->glselection == SQ_GLSelectionPainter::Ellipse) gls->begin(static_cast(tab->glselection), e->x(), e->y()); else gls->begin(SQ_GLSelectionPainter::Rectangle, e->x(), e->y()); movetype = 2; } // right button - show context menu else if(e->button() == TQt::RightButton) menu->popup(TQCursor::pos()); // middle button - toggle fullscreen state else if(e->button() == TQt::MidButton) toggleFullScreen(); } // User moved mouse. void SQ_GLWidget::mouseMoveEvent(TQMouseEvent *e) { // user didn't press any mouse button before ? if(movetype == -1 && fullscreen()) { #if 0 // bool tvis = SQ_GLView::window()->toolbar()->isShown(); // bool svis = SQ_GLView::window()->statusbar()->isShown(); int h = SQ_GLView::window()->toolbar()->height() + SQ_GLView::window()->tabbar()->height(); #warning FIXME #ifndef KSQUIRREL_PART hackResizeGL = true; SQ_GLView::window()->boxBar()->setShown((/*tvis ? false:*/(e->y() < h))); SQ_GLView::window()->statusbar()->setShown((/*svis ? false:*/(e->y() > height()-SQ_GLView::window()->statusbar()->height()))); #endif #endif return; } // left mouse button, lets move image (or matrix :-) ) if(movetype == 1) { xmove = e->x(); ymove = e->y(); matrix_move(xmove-xmoveold, -ymove+ymoveold); xmoveold = e->x(); ymoveold = e->y(); } // left + SHIFT else if(movetype == 2) gls->move(e->x(), e->y()); } // User released some mouse button. void SQ_GLWidget::mouseReleaseEvent(TQMouseEvent *) { if(movetype == -1) return; // left button - restore cursor if(movetype == 1 || (movetype == 2 && tab->glselection != -1)) // permanent selection setCursor(KCursor::arrowCursor()); // left button + SHIFT - zoom to selected rectangle (if needed) else if(movetype == 2 && tab->glselection == -1) { setCursor(KCursor::arrowCursor()); TQSize sz = gls->size(); TQPoint pt = gls->pos(); TQRect lastRect(pt.x(), pt.y(), sz.width(), sz.height()); gls->end(); TQPoint lastC = lastRect.center(); TQPoint O(width() / 2, height() / 2); if(lastRect.width() > 2 && lastRect.height() > 2) { bool lastReset = reset_mode; reset_mode = true; float X = MATRIX_X, Y = MATRIX_Y; matrix_move(O.x() - lastC.x(), lastC.y() - O.y()); reset_mode = lastReset; // try to zoom bool zoomed = tab->broken ? false : zoomRect(lastRect); // not zoomed ? (zoom > maximum zoom) if(!zoomed) { MATRIX_X = X; MATRIX_Y = Y; write_gl_matrix(); } } updateGL(); // start animation, if needed if(!manualBlocked()) startAnimation(); } movetype = -1; } /* * Zoom to 'r'. Will be called after somebody used right mouse button * to select zoom region. */ bool SQ_GLWidget::zoomRect(const TQRect &r) { // calculate zoom factor float factor = 1.0; float w = (float)width(), h = (float)height(); float factorw = w / (float)r.width(); float factorh = h / (float)r.height(); float t = w / h; if(t > (float)r.width() / (float)r.height()) factor = factorh; else factor = factorw; // try to zoom return matrix_zoom(factor); } // Fit width. void SQ_GLWidget::slotZoomW() { zoom_type = 0; pAZoomW->setChecked(true); // no image decoded if(tab->broken || tab->finfo.image.empty()) return; // calculate zoom factor float factor = (float)width() / (tab->rotate ? (float)tab->finfo.image[tab->current].h : (float)tab->finfo.image[tab->current].w); // "Ignore, if the image is less than window" - restore zoom factor to 1.0 if(pAIfLess->isChecked() && (tab->finfo.image[tab->current].w < width() && tab->finfo.image[tab->current].h < height())) factor = 1.0; // zoom... internalZoom(factor); } // Fit height. void SQ_GLWidget::slotZoomH() { zoom_type = 1; pAZoomH->setChecked(true); if(tab->broken || tab->finfo.image.empty()) return; float factor = (float)height() / (tab->rotate ? (float)tab->finfo.image[tab->current].w : (float)tab->finfo.image[tab->current].h); if(pAIfLess->isChecked() && (tab->finfo.image[tab->current].w < width() && tab->finfo.image[tab->current].h < height())) factor = 1.0; internalZoom(factor); } // Fit image (e.g. width and height). void SQ_GLWidget::slotZoomWH() { zoom_type = 2; pAZoomWH->setChecked(true); if(tab->broken || tab->finfo.image.empty()) return; float factor = 1.0; float w = (float)width(), h = (float)height(); float factorw = w / (tab->rotate ? (float)tab->finfo.image[tab->current].h : (float)tab->finfo.image[tab->current].w); float factorh = h / (tab->rotate ? (float)tab->finfo.image[tab->current].w : (float)tab->finfo.image[tab->current].h); float t = w / h; float F = tab->rotate ? ((float)tab->finfo.image[tab->current].h / (float)tab->finfo.image[tab->current].w) : ((float)tab->finfo.image[tab->current].w / (float)tab->finfo.image[tab->current].h); if(t > F) factor = factorh; else factor = factorw; if(pAIfLess->isChecked() && (tab->finfo.image[tab->current].w < width() && tab->finfo.image[tab->current].h < height())) factor = 1.0; internalZoom(factor); } // Previous zoom. void SQ_GLWidget::slotZoomLast() { zoom_type = 4; pAZoomLast->setChecked(true); if(tab->broken || tab->finfo.image.empty()) return; internalZoom(zoomFactor); } // Zoom 100%. void SQ_GLWidget::slotZoom100() { zoom_type = 3; pAZoom100->setChecked(true); if(tab->broken || tab->finfo.image.empty()) return; internalZoom(1.0); } // "Ignore, if the image is less than window" void SQ_GLWidget::slotZoomIfLess() { if(tab->broken || tab->finfo.image.empty()) return; switch(zoom_type) { case 0: slotZoomW(); break; case 1: slotZoomH(); break; case 2: slotZoomWH(); break; case 3: break; default: slotZoomLast(); } } // Zoom+ void SQ_GLWidget::slotZoomPlus() { matrix_zoom(1.0+zoomfactor/100.0); } // Zoom- void SQ_GLWidget::slotZoomMinus() { matrix_zoom(1.0/(1.0+zoomfactor/100.0)); } // Rotate left. void SQ_GLWidget::slotRotateLeft() { matrix_rotate(-rotatefactor); } // Rotate right. void SQ_GLWidget::slotRotateRight() { matrix_rotate(rotatefactor); } /* operations with matrices are taken from GLiv =) thanks to Guillaume Chazarian. */ void SQ_GLWidget::flip(int id, bool U) { GLfloat x = MATRIX_X, y = MATRIX_Y; MATRIX_X = 0; MATRIX_Y = 0; tab->matrix[id] *= -1.0; tab->matrix[id + 1] *= -1.0; tab->matrix[id + 3] *= -1.0; MATRIX_X = x; MATRIX_Y = y; write_gl_matrix(); if(!reset_mode && U) updateGL(); } void SQ_GLWidget::slotFlipH() { if(!tab->broken) { tab->isflippedH = !tab->isflippedH; flip(0); } } void SQ_GLWidget::slotFlipV() { if(!tab->broken) { tab->isflippedV = !tab->isflippedV; flip(4); } } void SQ_GLWidget::slotMatrixReset() { if(!tab->broken) { oldZoom = getZoom(); matrix_reset(false); matrix_zoom(1.0); } } void SQ_GLWidget::write_gl_matrix() { GLfloat transposed[16] = { 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 }; transposed[0] = MATRIX_C1; transposed[5] = MATRIX_C2; transposed[4] = MATRIX_S1; transposed[1] = MATRIX_S2; transposed[12] = MATRIX_X; transposed[13] = MATRIX_Y; transposed[14] = MATRIX_Z; glLoadMatrixf(transposed); } void SQ_GLWidget::matrix_move(GLfloat x, GLfloat y) { if(tab->broken) return; MATRIX_X += x; MATRIX_Y += y; write_gl_matrix(); if(!reset_mode) updateGL(); } void SQ_GLWidget::matrix_move_z(GLfloat z) { MATRIX_Z = z; write_gl_matrix(); } void SQ_GLWidget::matrix_push() { memcpy(saved, tab->matrix, sizeof(tab->matrix)); } void SQ_GLWidget::matrix_pop() { memcpy(tab->matrix, saved, sizeof(tab->matrix)); } void SQ_GLWidget::matrix_reset(bool U) { tab->nullMatrix(); tab->curangle = 0.0; tab->isflippedH = tab->isflippedV = false; if(decoded) exifRotate(U); } void SQ_GLWidget::matrix_pure_reset() { tab->nullMatrix(); write_gl_matrix(); } bool SQ_GLWidget::matrix_zoom(GLfloat ratio) { if(tab->broken) return false; SQ_Config::instance()->setGroup("GL view"); int zoom_lim = SQ_Config::instance()->readNumEntry("zoom limit", 1); GLfloat zoom_min, zoom_max, zoom_tobe; zoom_tobe = hypot(MATRIX_C1 * ratio, MATRIX_S1 * ratio) * 100.0; switch(zoom_lim) { case 2: zoom_min = (float)SQ_Config::instance()->readNumEntry("zoom_min", 1); zoom_max = (float)SQ_Config::instance()->readNumEntry("zoom_max", 10000); break; default: // "case 1:" too zoom_min = 1.0; zoom_max = 10000.0; } if(zoom_lim) { float z = getZoomPercents(); // zoom limit exceeded - do nothing if((z >= zoom_max && ratio > 1.0) || (z <= zoom_min && ratio < 1.0)) return false; // if the new zoom will be greater (smaller) than maximum // (minimum) zoom - scale it. if(ratio < 1.0 && zoom_min >= zoom_tobe) ratio = ratio * zoom_min / zoom_tobe; else if(ratio > 1.0 && zoom_max <= zoom_tobe) ratio = ratio * zoom_max / zoom_tobe; } GLfloat oldz = (oldZoom == -1 ? getZoom() : oldZoom); MATRIX_C1 *= ratio; MATRIX_S1 *= ratio; MATRIX_X *= ratio; MATRIX_S2 *= ratio; MATRIX_C2 *= ratio; MATRIX_Y *= ratio; hackMatrix(); GLfloat z = getZoom(); int filter = -1; if(ISFLOAT1(oldz) && !ISFLOAT1(z)) filter = linear ? GL_LINEAR : GL_NEAREST; else if(ISFLOAT1(z)) filter = GL_NEAREST; // update all textures if(filter != -1) { for(int i = 0;i < tab->total;i++) { int toxy = tab->parts[i].m_parts.size(); for(int j = 0;j < toxy;j++) { glBindTexture(GL_TEXTURE_2D, tab->parts[i].m_parts[j].tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); } } } oldZoom = -1; write_gl_matrix(); changeSlider(z); if(!reset_mode) updateGL(); return true; } /* * Floating point operations are not 100% exact. * We should correct matrix values. */ void SQ_GLWidget::hackMatrix() { if(ISFLOAT1(MATRIX_C1)) MATRIX_C1 = MATRIX_C1 < 0 ? -1.0 : 1.0; else if(ISFLOAT0(MATRIX_C1)) MATRIX_C1 = 0.0; if(ISFLOAT1(MATRIX_C2)) MATRIX_C2 = MATRIX_C2 < 0 ? -1.0 : 1.0; else if(ISFLOAT0(MATRIX_C2)) MATRIX_C2 = 0.0; if(ISFLOAT1(MATRIX_S1)) MATRIX_S1 = MATRIX_S1 < 0 ? -1.0 : 1.0; else if(ISFLOAT0(MATRIX_S1)) MATRIX_S1 = 0.0; if(ISFLOAT1(MATRIX_S2)) MATRIX_S2 = MATRIX_S2 < 0 ? -1.0 : 1.0; else if(ISFLOAT0(MATRIX_S2)) MATRIX_S2 = 0.0; if(ISFLOAT0(MATRIX_X)) MATRIX_X = 0.0; if(ISFLOAT0(MATRIX_Y)) MATRIX_Y = 0.0; } GLfloat SQ_GLWidget::getZoom() const { return hypot(MATRIX_C1, MATRIX_S1); } GLfloat SQ_GLWidget::getZoomPercents() const { return getZoom() * 100.0; } void SQ_GLWidget::matrix_rotate(GLfloat angle, bool U) { if(tab->broken) return; GLfloat c1 = MATRIX_C1, c2 = MATRIX_C2, s1 = MATRIX_S1, s2 = MATRIX_S2; double rad = angle * rad_const; double cosine = cos(rad); double sine = sin(rad); MATRIX_C1 = c1 * cosine + s2 * sine; MATRIX_S1 = s1 * cosine + c2 * sine; MATRIX_S2 = -c1 * sine + s2 * cosine; MATRIX_C2 = -s1 * sine + c2 * cosine; hackMatrix(); tab->curangle += angle; if(tab->curangle == 360.0 || tab->curangle == -360.0) tab->curangle = 0.0; else if(tab->curangle > 360.0) tab->curangle -= 360.0; else if(tab->curangle < -360.0) tab->curangle += 360.0; write_gl_matrix(); if(U) updateGL(); } void SQ_GLWidget::matrix_rotate2(GLfloat angle) { GLfloat c1 = MATRIX_C1, c2 = MATRIX_C2, s1 = MATRIX_S1, s2 = MATRIX_S2; double rad = angle * rad_const; double cosine = cos(rad); double sine = sin(rad); MATRIX_C1 = c1 * cosine + s2 * sine; MATRIX_S1 = s1 * cosine + c2 * sine; MATRIX_S2 = -c1 * sine + s2 * cosine; MATRIX_C2 = -s1 * sine + c2 * cosine; write_gl_matrix(); } /* * Bind textures, draw them and create GL lists. * Also show textures by executing GL lists, if 'swap' = true. */ bool SQ_GLWidget::showFrames(int i, Parts *p, bool swap) { int z, k = 0; const int a = p->tilesx.size() * i, b = a + p->tilesx.size(); int filter = linear ? GL_LINEAR : GL_NEAREST; // for safety... makeCurrent(); glEnable(GL_TEXTURE_2D); float zm = getZoom(); for(z = a;z < b;z++) { glBindTexture(GL_TEXTURE_2D, p->m_parts[z].tex); // setup texture parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ISFLOAT1(zm) ? GL_NEAREST : filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ISFLOAT1(zm) ? GL_NEAREST : filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); setupBits(p, buffer, i, k); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p->tilesx[k], p->tilesy[i], 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); k++; } // create new display list glNewList(p->m_parts[a].list, swap ? GL_COMPILE_AND_EXECUTE : GL_COMPILE); // bind & draw textures (if needed) for(z = a;z < b;z++) { glBindTexture(GL_TEXTURE_2D, p->m_parts[z].tex); glBegin(GL_QUADS); glTexCoord2f(p->m_parts[z].tx1, p->m_parts[z].ty1); glVertex2f(p->m_parts[z].x1, p->m_parts[z].y1); glTexCoord2f(p->m_parts[z].tx2, p->m_parts[z].ty1); glVertex2f(p->m_parts[z].x2, p->m_parts[z].y1); glTexCoord2f(p->m_parts[z].tx2, p->m_parts[z].ty2); glVertex2f(p->m_parts[z].x2, p->m_parts[z].y2); glTexCoord2f(p->m_parts[z].tx1, p->m_parts[z].ty2); glVertex2f(p->m_parts[z].x1, p->m_parts[z].y2); glEnd(); } glEndList(); glDisable(GL_TEXTURE_2D); // swap buffers... if(swap) swapBuffers(); return GL_TRUE; } void SQ_GLWidget::setupBits(Parts *p, RGBA *_buffer, int y, int x) { TQPair pair = SQ_GLWidget::calcRealDimensions(*p, y, x); int offs = p->realw * pair.second + pair.first; RGBA *orig = p->buffer->data() + offs; int toy = p->tilesy[y]; int tox = p->tilesx[x]; for(int j = 0;j < toy;j++) memcpy(_buffer + tox*j, orig + p->realw*j, tox*sizeof(RGBA)); } /* * Start decoding given image. We can call it from anywhere. */ void SQ_GLWidget::startDecoding(const TQString &file) { #ifndef KSQUIRREL_PART if(SQ_PreviewWidget::instance()->cancel()) SQ_WidgetStack::instance()->diroperator()->stopPreview(); #endif if(reset_mode) return; started.start(); tabold = tab; tmptab.empty(); tab = &tmptab; reset_mode = true; timer_anim->stop(); images->clear(); tab->m_File = file; // original name tab->File = TQFile::encodeName(tab->m_File); // translated name tab->m_original = m_original; TQFileInfo fm(file); tab->fmt_ext = fm.extension(false); tab->fmt_size = fm.size(); #ifndef KSQUIRREL_PART // show window with image KSquirrel::app()->raiseGLWidget(); #endif if(m_expected.isEmpty()) TDEApplication::eventLoop()->processEvents(TQEventLoop::ExcludeUserInput | TQEventLoop::ExcludeSocketNotifiers); decode(); } /* * Prepare decoding. It will find proper library for decoding, * clear old memory buffers, etc. */ bool SQ_GLWidget::prepare() { TQString status; tab = &tmptab; // get library from cache SQ_LIBRARY *m_lib = SQ_LibraryHandler::instance()->libraryForFile(tab->m_File); if(!m_lib) { KMessageBox::error(this, i18n("Codec for %1 format not found").arg(tab->fmt_ext)); reset_mode = false; tab = tabold; return false; } else tmptab.lib = m_lib; enableActions(true); int already = -1, result = -1, i = 0; SQ_Config::instance()->setGroup("GL view"); #ifndef KSQUIRREL_PART bool use_tabs = SQ_GLView::window()->tabs(); #endif bool useCurrent = false; #ifndef KSQUIRREL_PART if(!use_tabs) { removeCurrentTabs(); SQ_GLView::window()->removeTabs(); } else { if(m_expected != m_original) { std::vector::iterator it = tabs.begin(); std::vector::iterator itEnd = tabs.end(); for(;it != itEnd;++it, ++i) { if((*it).m_original == m_original) { already = i; useCurrent = true; break; } } } // 0 - new page // 1 - replace current tab // 2 - close all and open in a new tab // -1 - ignore 'result' at all if(already == -1 && decoded && m_expected != m_original && !useCurrent && SQ_Config::instance()->readBoolEntry("tabs_ask", false)) { SQ_TabOpenDialog tbo(this); tbo.exec(); result = tbo.result(); } } #else removeCurrentTabs(); #endif #ifndef KSQUIRREL_PART int curtab = SQ_GLView::window()->tabbar()->indexOf(SQ_GLView::window()->tabbar()->currentTab()); #else int curtab = -1; #endif int curindex = (already == -1) ? curtab : already; if(curindex != -1 && (m_expected == m_original || result == 1 || useCurrent)) { if(curtab != curindex) tabs[curtab].removeParts(); tabs[curindex].clearParts(); tabs[curindex] = tmptab; tab = &tabs[curindex]; #ifndef KSQUIRREL_PART SQ_GLView::window()->tabbar()->blockSignals(true); SQ_GLView::window()->tabbar()->setCurrentTab(SQ_GLView::window()->tabbar()->tabAt(curindex)); SQ_GLView::window()->tabbar()->tabAt(curindex)->setText(KStringHandler::csqueeze(tab->m_original.fileName(), SQ_TAB_TEXT_LENGTH)); SQ_GLView::window()->tabbar()->blockSignals(false); #endif } else { if(curindex != -1) { if(result == 2) closeAllTabs(); else tabs[curindex].removeParts(); } tabs.push_back(tmptab); int lastId = tabs.size() - 1; tab = &tabs[lastId]; #ifndef KSQUIRREL_PART SQ_GLView::window()->tabbar()->blockSignals(true); SQ_GLView::window()->addPage(KStringHandler::csqueeze(tab->m_original.fileName(), SQ_TAB_TEXT_LENGTH)); SQ_GLView::window()->tabbar()->setCurrentTab(SQ_GLView::window()->tabbar()->tabAt(lastId)); // TQTabBar::show will emit selected(int), // we don't want it emit tabCountChanged(); SQ_GLView::window()->tabbar()->blockSignals(false); #endif } gls->setVisible(false); SQ_CodecSettings::applySettings(tab->lib, SQ_CodecSettings::ImageViewer); // determine codec tab->codeK = tab->lib->codec; // start decoding! i = tab->codeK->read_init(tab->File.ascii()); // oops, error... if(i != SQE_OK) { decodeFailedOn0(i); m_expected = KURL(); return false; } return true; } void SQ_GLWidget::decode() { // prepare decoding... if(!prepare()) return; #ifndef KSQUIRREL_PART KSquirrel::app()->setCaption(originalURL()); #endif zoomFactor = getZoom(); matrix_pure_reset(); matrixChanged(); #ifdef SQ_HAVE_KEXIF KExifData d; d.readFromFile(tab->m_File); tab->orient = d.getImageQt::Orientation(); tab->wm = SQ_Utils::exifGetMatrix(TQString(), tab->orient); tab->rotate = (tab->orient == KExifData::ROT_90_HFLIP || tab->orient == KExifData::ROT_90 || tab->orient == KExifData::ROT_90_VFLIP || tab->orient == KExifData::ROT_270); #else tab->orient = -1; tab->rotate = false; #endif errors = 0; /* *********************************************************** */ int i, j, id; int line, res, first_id = 0; fmt_image *im; memoryPart *pt; bool progr; SQ_Config::instance()->setGroup("GL view"); // in fullscreen mode progressive loading is disabled anyway if(fullscreen()) progr = false; else progr = SQ_Config::instance()->readBoolEntry("progressiv", true); int allpages = SQ_Config::instance()->readNumEntry("load_pages", 0); int pages_num = SQ_Config::instance()->readNumEntry("load_pages_number", 1); if(pages_num < 1) pages_num = 1; #ifndef KSQUIRREL_PART SQ_GLView::window()->sbarWidget("SBFile")->setText(tab->m_original.fileName()); #else t_glv.sbarWidget("SBFile")->setText(tab->m_original.fileName()); #endif tab->current = 0; bool notexpected = m_expected.isEmpty(); m_expected = KURL(); // start time counting while(true) { if((allpages == 1 && tab->current) || (allpages == 2 && tab->current == pages_num)) break; // absolute evil, but should do... if(notexpected) TDEApplication::eventLoop()->processEvents(TQEventLoop::ExcludeUserInput | TQEventLoop::ExcludeSocketNotifiers); i = tab->codeK->read_next(); // something went wrong. SQE_NOTOK is a special type of error. It means // that we decoded all pages. if(i != SQE_OK) { if(i == SQE_NOTOK || tab->current) break; else { decodeFailedOn0(i); return; } } im = tab->codeK->image(tab->current); Parts pp; // find tile size SQ_GLWidget::findCloserTiles(im->w, im->h, pp.tilesx, pp.tilesy); TQPair pair = SQ_GLWidget::calcRealDimensions(pp); pp.realw = pair.first; pp.realh = pair.second; // setup current Part pp.w = im->w; pp.h = im->h; // create textures and display lists if(!pp.makeParts()) { if(tab->current) break; else { KMessageBox::error(this, i18n("Memory allocation failed for %1 of memory") .arg(TDEIO::convertSize(pp.realw * pp.realh * sizeof(RGBA)))); decodeFailedOn0(SQE_R_NOMEMORY); return; } } pt = new memoryPart(pp.realw * pp.realh); pt->create(); if(!pt->valid()) { pp.removeParts(); if(tab->current) break; else { KMessageBox::error(this, i18n("Memory allocation failed")); decodeFailedOn0(SQE_R_NOMEMORY); return; } } line = 0; pp.computeCoords(); pp.buffer = pt; tab->finfo = tab->codeK->information(); if(!tab->current) { tab->isflippedH = tab->isflippedV = false; slotZoomIfLess(); matrixChanged(); updateCurrentFileInfo(); } matrix_move_z(SQ_FIRST_TILE_LAYER+tab->current); for(int pass = 0;pass < im->passes;pass++) { if(tab->codeK->read_next_pass() != SQE_OK) break; bool flip = tab->finfo.image[tab->current].needflip; line = 0; int tlsy = pp.tilesy.size(); int tlsyval, offs = 0, O, iA; for(i = 0;i < tlsy;i++) { iA = flip ? (tlsy-i-1) : i; tlsyval = pp.tilesy[iA]; for(j = 0;j < tlsyval;j++) { O = flip ? (pp.realw*(im->h - offs - j-1)) : (offs + j)*pp.realw; res = tab->codeK->read_scanline(pp.buffer->data() + O); errors += (int)(res != SQE_OK); if(++line == im->h) break; } offs += tlsyval; // last pass if(pass == im->passes-1) { // if(!tab->current) { bool b = showFrames(iA, &pp, progr); if(!b) kdWarning() << "Showframes failed for image " << tab->current << ", tiley " << i << endl; } } } } id = images->insertItem(TQString::fromLatin1("#%1 [%2x%3@%4]").arg(tab->current+1).arg(im->w).arg(im->h).arg(im->bpp)); images->setItemParameter(id, tab->current); if(!tab->current) { #ifndef KSQUIRREL_PART SQ_GLView::window()->sbarWidget("SBDecodedI")->setPixmap(tab->lib->mime); #endif old_id = first_id = id; } tab->parts.push_back(pp); calcFrameLabelWidth(); frameChanged(); tab->current++; } tab->finfo = tab->codeK->information(); tab->codeK->read_close(); tab->total = tab->finfo.image.size(); tab->current = 0; frameChanged(); enableSettingsButton(!tab->lib->config.isEmpty()); decoded = true; reset_mode = false; updateGL(); tab->quickImageInfo = tab->lib->quickinfo; tab->elapsed = started.elapsed(); #ifndef KSQUIRREL_PART SQ_GLView::window()->sbarWidget("SBLoaded")->setText(TDEGlobal::locale()->formatLong(tab->elapsed) + i18n(" ms.")); #else t_glv.sbarWidget("SBLoaded")->setText(TDEGlobal::locale()->formatLong(tab->elapsed) + i18n(" ms.")); #endif images->setItemChecked(first_id, true); if(tab->finfo.animated) TQTimer::singleShot(tab->finfo.image[tab->current].delay, this, TQ_SLOT(slotAnimateNext())); } /* * Palette changed. Let's update tickmarks and background color. */ void SQ_GLWidget::paletteChange(const TQPalette &oldPalette) { TQGLWidget::paletteChange(oldPalette); SQ_Config::instance()->setGroup("GL view"); if(SQ_Config::instance()->readNumEntry("GL view background type", 1) == 0) { TQColor color = colorGroup().color(TQColorGroup::Base); qglClearColor(color); updateGL(); } } void SQ_GLWidget::slotFirst() { #ifndef KSQUIRREL_PART if(!reset_mode) SQ_WidgetStack::instance()->firstFile(); #endif } void SQ_GLWidget::slotLast() { #ifndef KSQUIRREL_PART if(!reset_mode) SQ_WidgetStack::instance()->lastFile(); #endif } void SQ_GLWidget::slotNext() { #ifndef KSQUIRREL_PART timer_next->stop(); timer_prev->stop(); timer_next->start(timer_delay_file, true); #endif } void SQ_GLWidget::slotPrev() { #ifndef KSQUIRREL_PART timer_prev->stop(); timer_next->stop(); timer_prev->start(timer_delay_file, true); #endif } void SQ_GLWidget::slotZoomMenu() { zoomMenu->exec(TQCursor::pos()); } void SQ_GLWidget::slotAnimateNext() { // Some time ago we started to decode new image, but it is // not guaranteed that animation stopped! // // We should return now to avoid segfaults... if(reset_mode) return; // tab->parts[tab->current].removeParts(); tab->current++; if(tab->current >= (int)tab->finfo.image.size()) tab->current = 0; updateCurrentFileInfo(); updateGL(); int delay = tab->finfo.image[tab->current].delay; timer_anim->start(delay, true); } void SQ_GLWidget::startAnimation() { if(!tab->finfo.animated) return; timer_anim->start(tab->finfo.image[tab->current].delay, true); } void SQ_GLWidget::stopAnimation() { timer_anim->stop(); } void SQ_GLWidget::slotToggleAnimate() { if(!tab->finfo.animated || gls->valid()) return; if(!timer_anim->isActive()) { tab->manualBlocked = false; startAnimation(); } else { tab->manualBlocked = true; stopAnimation(); } } /* * Next image in animated sequence. Called by user (with F3). */ void SQ_GLWidget::nextImage() { // if the image has only one page - do nothing if(tab->total == 1) return; tab->current++; if(tab->current >= tab->total) tab->current = 0; updateGL(); updateCurrentFileInfo(); } /* * Previous image in animated sequence. Called by user (with F2). */ void SQ_GLWidget::prevImage() { if(tab->total == 1) return; tab->current--; if(tab->current < 0) tab->current = tab->total - 1; updateGL(); updateCurrentFileInfo(); } /* * Jump to first/last image page. */ void SQ_GLWidget::jumpToImage(bool last) { // if the image has only one page - do nothing if(tab->total == 1) return; tab->current = (last) ? tab->finfo.image.size() - 1 : 0; updateGL(); updateCurrentFileInfo(); } void SQ_GLWidget::initMarks() { for(int i = 0;i < 4;i++) { glGenTextures(1, &mark[i]); glBindTexture(GL_TEXTURE_2D, mark[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, mm[i].bits()); } } void SQ_GLWidget::internalZoom(const GLfloat &zF) { tab->curangle = 0.0; oldZoom = getZoom(); matrix_pure_reset(); exifRotate(false); matrix_zoom(zF); } void SQ_GLWidget::updateFilter(bool nice) { if(nice == linear) return; // store linear = nice; int filter = nice ? GL_LINEAR : GL_NEAREST; Parts *pt; // update all textures for(int i = 0;i < tab->total;i++) { pt = tab->broken ? parts_broken : &tab->parts[i]; int toxy = pt->m_parts.size(); for(int j = 0;j < toxy;j++) { glBindTexture(GL_TEXTURE_2D, pt->m_parts[j].tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); } } updateGL(); } /* * Cleanup method. */ void SQ_GLWidget::decodeFailedOn0(const int err_code) { tab->codeK->read_close(); tab->finfo.image.clear(); tab->finfo.meta.clear(); tab->total = 0; decoded = (bool)tabs.size(); reset_mode = false; tab->broken = true; tab->lib = 0; useBrokenImage(err_code); } /* * Force using broken image + update context. * Show appropriate error message in statusbar. */ void SQ_GLWidget::useBrokenImage(const int err_index) { enableSettingsButton(false); enableActions(false); // save "broken" image information in 'tab->finfo' tab->finfo.image.push_back(image_broken); // reset statusbar widgets SQ_GLView::window()->resetStatusBar(); #ifndef KSQUIRREL_PART // show error message instead of file name SQ_GLView::window()->sbarWidget("SBFile")->setText(SQ_ErrorString::instance()->string(err_index)); KSquirrel::app()->setCaption(TQString()); #else t_glv.sbarWidget("SBFile")->setText(SQ_ErrorString::instance()->string(err_index)); #endif matrix_pure_reset(); tab->curangle = 0; tab->isflippedH = tab->isflippedV = false; changeSlider(1.0); // update context and show "broken" image updateGL(); } /* * Are we in fullscreen state ? */ bool SQ_GLWidget::fullscreen() const { #ifndef KSQUIRREL_PART KWin::WindowInfo wi = KWin::windowInfo(SQ_GLView::window()->winId()); if(wi.valid()) pAFull->setChecked((wi.state() & NET::FullScreen)); return pAFull->isChecked(); #else return false; #endif } /* * Toggle fullscreen state. */ void SQ_GLWidget::toggleFullScreen() { #ifndef KSQUIRREL_PART bool fs = !fullscreen(); pAFull->setChecked(fs); pAToolFull->setOn(fs); KSquirrel::app()->slotFullScreen(fs); #endif } void SQ_GLWidget::slotSetZoomPercents(int perc) { if(tab->broken || tab->finfo.image.empty()) return; GLfloat z = (perc <= 20) ? (GLfloat)perc / 20 : ((GLfloat)perc - 20)/2 + 1.0; internalZoom(z); } void SQ_GLWidget::updateFactors() { zoomfactor = SQ_Config::instance()->readNumEntry("zoom", 25); movefactor = SQ_Config::instance()->readNumEntry("move", 5); rotatefactor = SQ_Config::instance()->readNumEntry("angle", 90); } void SQ_GLWidget::slotSelectionRect() { stopAnimation(); tab->glselection = SQ_GLSelectionPainter::Rectangle; gls->end(); } void SQ_GLWidget::slotSelectionEllipse() { stopAnimation(); tab->glselection = SQ_GLSelectionPainter::Ellipse; gls->end(); } void SQ_GLWidget::slotSelectionClear() { tab->glselection = -1; gls->end(); pASelectionEllipse->setChecked(false); pASelectionRect->setChecked(false); if(!manualBlocked()) startAnimation(); } bool SQ_GLWidget::manualBlocked() { // selection is also blocks animation return tab->manualBlocked || gls->valid(); } void SQ_GLWidget::setDownloadPercents(int p) { if(p < 0) percentsLabel->hide(); else { percentsLabel->setText(i18n("Downloading...") + ' ' + TDEIO::convertSize(p)); percentsLabel->adjustSize(); percentsLabel->show(); } } #include "sq_glwidget.moc"