/* * This file is part of rasdaman community. * * Rasdaman community 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 3 of the License, or * (at your option) any later version. * * Rasdaman community is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * PURPOSE: * * rView thumbnail viewer class. Unlike the regular MDD viewers (e.g. * rviewImage) this is not derived from rviewDisplay because it can * display any number of MDD objects in contrast to regular viewers * which manage exactly one object. * * COMMENTS: * None */ // Standard wxWindows preamble. #ifdef __GNUG__ #pragma implementation #endif // changed in wxWindows 2.4.2: //#include "wx_prec.h" #include #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include #endif #include #include #include "wx_pixmap.h" #include "labelManager.hh" #ifdef EARLY_TEMPLATE #define __EXECUTABLE__ #endif #include "rviewPrefs.hh" #include "rviewTypes.hh" #include "rviewUtils.hh" #include "rviewThumb.hh" #include "raslib/rmdebug.hh" #include "rasodmg/ref.hh" #include "rasodmg/marray.hh" const int rviewThumb::thumb_width = 450; const int rviewThumb::thumb_height = 300; const int rviewThumb::thumb_imgwidth = 100; const int rviewThumb::thumb_perline = 4; const int rviewThumb::thumb_space = 32; const int rviewThumb::thumb_border = 8; const int rviewThumb::thumb_scrstep = 8; const int rviewThumb::thumb_pgstep = 8; const int rviewThumb::thumb_chkwidth = 100; const int rviewThumb::thumb_chkheight = 30; const int rviewThumb::thumb_minwidth = 10; const int rviewThumb::thumb_maxwidth = 2000; const int rviewThumb::thumb_mincols = 1; const int rviewThumb::thumb_maxcols = 16; const int rviewThumb::thumb_cheight = 64; const int rviewThumb::thumb_twidth = 80; const int rviewThumb::thumb_theight = 50; const int rviewThumb::thumb_prjwidth = 60; /* * The thumbnail canvas class */ thumbCanvas::thumbCanvas(rviewThumb *par, int x, int y, int width, int height) : wxCanvas((wxWindow*)par, x, y, width, height, 0) { parent = par; brush.SetStyle(wxSOLID); brush.SetColour((char)0xc0, (char)0xc0, (char)0xc0); SetBackground(&brush); font = new wxFont(12, wxROMAN, wxNORMAL, wxNORMAL); } thumbCanvas::~thumbCanvas(void) { SetBackground(NULL); delete font; } void thumbCanvas::OnPaint(void) { int thumbs, thumbsperline; int gridX, gridY; wxPixmap *thumbnail; wxUpdateIterator upd(this); //wxRect rect; int startx, starty, endx, endy, w, h, posx, posy; int scrollx, scrolly; int maxy, runx, runy; //cout << "thumbCanvas::OnPaint" << endl; parent->getThumbInfo(thumbs, thumbsperline); parent->getGridInfo(gridX, gridY); if ((thumbs <= 0) || (thumbsperline <= 0) || (gridX <= 0) || (gridY <= 0)) return; GetClientSize(&w, &h); scrollx = rviewThumb::thumb_scrstep * GetScrollPos(wxHORIZONTAL); scrolly = rviewThumb::thumb_scrstep * GetScrollPos(wxVERTICAL); startx = (scrollx / gridX); endx = ((scrollx + w + gridX - 1) / gridX); starty = (scrolly / gridY); endy = ((scrolly + h + gridY - 1) / gridY); posx = rviewThumb::thumb_space / 2 + gridX * startx; posy = rviewThumb::thumb_space / 2 + gridY * starty; maxy = (thumbs + thumbsperline - 1) / thumbsperline; if ((startx >= thumbsperline) || (endx < 0)) return; if ((starty >= maxy) || (endy < 0)) return; if (startx < 0) startx = 0; if (endx >= thumbsperline) endx = thumbsperline-1; if (starty < 0) starty = 0; if (endy >= maxy) endy = maxy - 1; BeginDrawing(); SetFont(font); while (upd) { char caption[STRINGSIZE]; runx = posx; for (w = startx; w <= endx; w++, runx += gridX) { runy = posy; for (h = starty; h <= endy; h++, runy += gridY) { if ((thumbnail = parent->getPixmapNumber(h * thumbsperline + w, caption)) != NULL) { float tw, th; /*cout << "Pixmap " << w << ' ' << h << ": " << (void*)thumbnail << ", at " << runx << ' ' << runy << ", width " << thumbnail->getWidth() << ", height " << thumbnail->getHeight() << ", depth " << thumbnail->getDepth() << ", ddepth " << thumbnail->getModeDepth() << endl;*/ // Pixmaps have the canvas coordinate system, text has the _scrolled_ canvas cosys! thumbnail->plotPixmap(runx - scrollx, runy - scrolly); GetTextExtent(caption, &tw, &th); tw = ((float)(thumbnail->getWidth()) - tw) / 2; th = thumbnail->getHeight(); DrawText(caption, runx + tw, runy + th); } } } upd++; } SetFont(NULL); EndDrawing(); } void thumbCanvas::updateDisplay(void) { if (parent->IsShown()) { int cw, ch; GetClientSize(&cw, &ch); SetClippingRegion(0, 0, cw, ch); OnPaint(); DestroyClippingRegion(); } } /* * The rviewThumb class for displaying thumbnails of images */ rviewThumb::rviewThumb(void) : rviewFrame(NULL, "", 0, 0, thumb_width, thumb_height) { int x, y, tw, py; wxMenu *menu; wxMenu *setup; wxMenu *submenu; char buffer[STRINGSIZE]; thumbsperline = 4; if (prefs->thumbCols > 0) thumbsperline = prefs->thumbCols; projstep = 1; if (prefs->thumbProjstep > 0) projstep = prefs->thumbProjstep; doValToCspace = (prefs->rgbSpace != 0); doFullRangeCspace = (prefs->rgbSpace == 2); dimproj = prefs->thumbProjdim; imgWidth = 100; if (prefs->thumbWidth > 0) imgWidth = prefs->thumbWidth; if (imgWidth < thumb_minwidth) imgWidth = thumb_minwidth; if (imgWidth > thumb_maxwidth) imgWidth = thumb_maxwidth; thumbs = 0; numPixmaps = 0; maxHeight = -1; listHead = NULL; csmap = NULL; canDoCspace = FALSE; gridX = 0; gridY = 0; menu = new wxMenu; menu->Append(MENU_THUMB_DATA_CLOSE, ""); submenu = new wxMenu; submenu->Append(MENU_THUMB_CSPACE_ON, "", NULL, TRUE); submenu->Append(MENU_THUMB_CSPACE_FULL, "", NULL, TRUE); submenu->Append(MENU_THUMB_CSPACE_EDIT, ""); setup = new wxMenu; setup->Append(MENU_THUMB_SETUP_CSPACE, "", submenu, NULL); mbar = new wxMenuBar; sprintf(buffer, "&%s", lman->lookup("menThumbData")); mbar->Append(menu, buffer); sprintf(buffer, "&%s", lman->lookup("menThumbSetup")); mbar->Append(setup, buffer); mbar->Check(MENU_THUMB_CSPACE_ON, doValToCspace); mbar->Check(MENU_THUMB_CSPACE_FULL, doFullRangeCspace); configureCspace(FALSE); GetClientSize(&x, &y); panel = new wxPanel((wxWindow*)this, 0, thumb_border, x, thumb_cheight); panel->SetLabelPosition(wxVERTICAL); x -= 2*thumb_border; y -= 2*thumb_border + thumb_cheight; canvas = new thumbCanvas(this, thumb_border, thumb_border + thumb_cheight, x, y); tw = (x - 4*thumb_border - 2*thumb_prjwidth) / 3; py = thumb_border; projString[0] = '\0'; project = new rviewText(panel); thumbProj = new rviewText(panel, dimproj); thumbStep = new rviewText(panel, projstep); thumbWidth = new rviewText(panel, imgWidth); thumbCols = new rviewText(panel, thumbsperline); SetMenuBar(mbar); label(); frameWidth=-1; frameHeight=-1; OnSize(x, y); OnSize(x, y); Show(TRUE); } rviewThumb::~rviewThumb(void) { if (thumbs != 0) { int i; rviewThumbList *tlst = listHead; for (i=0; inext; delete listHead; } } if (csmap != NULL) delete csmap; } void rviewThumb::configureCspace(bool mode) { mbar->Enable(MENU_THUMB_SETUP_CSPACE, mode); mbar->Enable(MENU_THUMB_CSPACE_ON, mode); mbar->Enable(MENU_THUMB_CSPACE_FULL, mode); mbar->Enable(MENU_THUMB_CSPACE_EDIT, mode); } // Deletes all the pixmaps for one MDD object void rviewThumb::deletePixmapChain(rviewThumbList *tlst) { if (tlst->pixmaps != NULL) { rviewThumbPixList *tplst, *tplast; tplst = tlst->pixmaps; while (tplst != NULL) { //cout << " delete " << (void*)tplst << endl; tplast = tplst; tplst = tplst->next; if (tplast->pixmap != NULL) delete tplast->pixmap; delete tplast; numPixmaps--; } tlst->numPix = 0; tlst->pixmaps = NULL; } } // Creates a pixmap chain for a given MDD object int rviewThumb::pixmapsFromMDD(rviewThumbList *tlst) { rviewThumbPixList *newPixmap, *lastPixmap; int i, projval; bool pixLoop; //cout << "pixmapsFromMDD" << endl; // delete old pixmaps deletePixmapChain(tlst); lastPixmap = NULL; if (dimproj >= 0) { projval = pt1[dimproj]; } // Create all thumbnails for this object. This is 1 for 2D objects, any number for 3+D objects do { pixLoop = FALSE; newPixmap = new rviewThumbPixList; newPixmap->next = NULL; newPixmap->dimproj = dimproj; newPixmap->projval = projval; if (lastPixmap == NULL) { tlst->pixmaps = newPixmap; } else { lastPixmap->next = newPixmap; } lastPixmap = newPixmap; try { if ((newPixmap->pixmap = buildThumbnail(tlst->mdd, tlst->baseType, newPixmap->dimproj, newPixmap->projval)) == NULL) { cerr << lman->lookup("errorProjThumb") << endl; return 0; } } catch (r_Error &errObj) { cerr << errObj.what() << endl; return 0; } (tlst->numPix)++; numPixmaps++; i = newPixmap->pixmap->getHeight(); if (i > maxHeight) { maxHeight = i; } if (dimproj >= 0) { projval += projstep; if (projval <= pt2[dimproj]) pixLoop = TRUE; } } while (pixLoop); return 1; } int rviewThumb::addMDD(r_Ref &newMdd) { rviewThumbList *newItem; int i; r_Object *mo; bool oldCstate; RMDBGONCE(3, RMDebug::module_applications, "rviewThumb", "addMDD(...)"); if ((newItem = new rviewThumbList) == NULL) return 0; oldCstate = canDoCspace; // Init object-dependent internal data? if (projString[0] == '\0') { // No ==> init to a decent default: initForObject(newMdd); } mo = (r_Object*)(&(*newMdd)); newItem->mdd = newMdd; newItem->baseType = rviewGetBasetype(mo); newItem->numPix = 0; newItem->next = NULL; newItem->pixmaps = NULL; if (pixmapsFromMDD(newItem) == 0) { deletePixmapChain(newItem); delete newItem; return 0; } // If it was true before it's true now. if (oldCstate) canDoCspace = TRUE; else { // Otherwise try the transition FALSE -> TRUE if (canDoCspace) { // Enabling the parent automatically enables the children too, so reset them... mbar->Enable(MENU_THUMB_SETUP_CSPACE, TRUE); mbar->Enable(MENU_THUMB_CSPACE_FULL, doValToCspace); mbar->Enable(MENU_THUMB_CSPACE_EDIT, doValToCspace); } } if (thumbs == 0) { listHead = newItem; } else { rviewThumbList *tlst = listHead; for (i=1; inext; tlst->next = newItem; } thumbs++; updateCanvasSize(); return 1; } int rviewThumb::deleteMDD(r_Ref &obsMdd) { rviewThumbList *last, *tlst; int i; RMDBGONCE(3, RMDebug::module_applications, "rviewThumb", "deleteMDD(...)"); last = NULL; tlst = listHead; for (i=0; imdd == obsMdd) break; last = tlst; tlst = tlst->next; } if (i < thumbs) { deletePixmapChain(tlst); if (last == NULL) { listHead = tlst->next; } else { last->next = tlst->next; } delete tlst; thumbs--; // Removing a thumbnail means a new layout and new bounding boxes maxHeight = 0; tlst = listHead; for (i=0; ipixmaps; while (tplst != NULL) { ph = tplst->pixmap->getHeight(); if (ph > maxHeight) maxHeight = ph; tplst = tplst->next; } tlst = tlst->next; } // Close thumbnail viewer when the last thumbnail has been deleted if (thumbs <= 0) { this->Close(TRUE); } else { updateCanvasSize(); } return 1; } return 0; } void rviewThumb::setLayout(int width, int npl) { imgWidth = width; thumbsperline = npl; updateCanvasSize(); } void rviewThumb::label(void) { SetTitle(lman->lookup("titleThumb")); mbar->SetLabelTop(0, lman->lookup("menThumbData")); mbar->SetLabel(MENU_THUMB_DATA_CLOSE, lman->lookup("menThumbDataClose")); mbar->SetLabelTop(1, lman->lookup("menThumbSetup")); mbar->SetLabel(MENU_THUMB_SETUP_CSPACE, lman->lookup("menCspaceTitle")); mbar->SetLabel(MENU_THUMB_CSPACE_ON, lman->lookup("menCspaceOn")); mbar->SetLabel(MENU_THUMB_CSPACE_FULL, lman->lookup("menCspaceFull")); mbar->SetLabel(MENU_THUMB_CSPACE_EDIT, lman->lookup("menCspaceEdit")); project->SetLabel(lman->lookup("textProjString")); thumbProj->SetLabel(lman->lookup("textThumbProjDim")); thumbStep->SetLabel(lman->lookup("textThumbProjStep")); thumbWidth->SetLabel(lman->lookup("textThumbWidth")); thumbCols->SetLabel(lman->lookup("textThumbColumns")); } int rviewThumb::process(wxObject &obj, wxEvent &evt) { int type = evt.GetEventType(); if (type == wxEVENT_TYPE_TEXT_ENTER_COMMAND) { char buffer[STRINGSIZE]; int newVal; if (&obj == (wxObject*)thumbWidth) { newVal = atoi(thumbWidth->GetValue()); if ((newVal < thumb_minwidth) || (newVal > thumb_maxwidth)) { sprintf(buffer, "%d", imgWidth); thumbWidth->SetValue(buffer); } else { newThumbWidth(newVal); } return 1; } if (&obj == (wxObject*)thumbCols) { newVal = atoi(thumbCols->GetValue()); if ((newVal < thumb_mincols) || (newVal > thumb_maxcols)) { sprintf(buffer, "%d", thumbsperline); thumbCols->SetValue(buffer); } else { thumbsperline = newVal; updateCanvasSize(); } return 1; } if (&obj == (wxObject*)project) { if (thumbs > 0) { unsigned int oldProj; int oldFrom, oldTo; oldProj = dimproj; if (dimproj >= 0) { oldFrom = pt1[dimproj]; oldTo = pt2[dimproj]; } strcpy(projString, project->GetValue()); if (parseProjection(listHead->mdd) != 0) { bool fromScratch = TRUE; // Determine whether we have to rebuild everything from scratch or not if ((int)oldProj == dimproj) { if (dimproj >= 0) { if ((pt1[dimproj] == oldFrom) && (pt2[dimproj] == oldTo)) fromScratch = TRUE; } } rebuildThumbnails(fromScratch); } } return 1; } if (&obj == (wxObject*)thumbStep) { int oldStep = projstep; projstep = atoi(thumbStep->GetValue()); if (projstep <= 0) { projstep = 1; thumbProj->SetValue("1"); } if ((dimMDD > 2) && (oldStep != projstep)) rebuildThumbnails(TRUE); return 1; } if (&obj == (wxObject*)thumbProj) { if ((thumbs > 0) && (dimMDD > 2)) { if (parseProjection(listHead->mdd) != 0) { rebuildThumbnails(TRUE); } } return 1; } } return 0; } const char *rviewThumb::getFrameName(void) const { return "rviewThumb"; } rviewFrameType rviewThumb::getFrameType(void) const { return rviewFrameTypeThumb; } void rviewThumb::OnSize(int w, int h) { int x, y, tw, py, px; GetClientSize(&x, &y); if((x < thumb_width) || (y < thumb_height)) { frameWidth = x; frameHeight = y; SetClientSize(thumb_width, thumb_height); return; } panel->SetSize(0, thumb_border, x, thumb_cheight); x -= 2*thumb_border; y -= 2*thumb_border + thumb_cheight; canvas->SetSize(thumb_border, thumb_border + thumb_cheight, x, y); tw = (x - 2*thumb_prjwidth - 2*thumb_twidth - 6*thumb_border); py = thumb_border; px = thumb_border; project->SetSize(px, py, tw , thumb_theight); px +=thumb_border + tw; thumbProj->SetSize(px, py, thumb_prjwidth, thumb_theight); px +=thumb_prjwidth + thumb_border; thumbStep->SetSize(px, py, thumb_prjwidth, thumb_theight); px +=thumb_prjwidth + thumb_border; thumbWidth->SetSize(px, py, thumb_twidth, thumb_theight); px +=thumb_twidth + thumb_border; thumbCols->SetSize(px, py, thumb_twidth, thumb_theight); } void rviewThumb::OnMenuCommand(int id) { switch (id) { case MENU_THUMB_DATA_CLOSE: this->Close(TRUE); break; case MENU_THUMB_CSPACE_EDIT: csmap->openEditor(); break; case MENU_THUMB_CSPACE_ON: { rviewThumbList *tlst = listHead; int i; // Don't allow switching off cspace mapping if at least one object is float/double. for (i=0; ibaseType == rbt_float) || (tlst->baseType == rbt_double)) break; tlst = tlst->next; } if (i < thumbs) { mbar->Check(MENU_THUMB_CSPACE_ON, TRUE); } else { doValToCspace = mbar->Checked(MENU_THUMB_CSPACE_ON); mbar->Enable(MENU_THUMB_CSPACE_FULL, doValToCspace); mbar->Enable(MENU_THUMB_CSPACE_EDIT, doValToCspace); rebuildThumbnails(FALSE); } } break; case MENU_THUMB_CSPACE_FULL: doFullRangeCspace = mbar->Checked(MENU_THUMB_CSPACE_FULL); if (csmap != NULL) { csmap->processRange((doFullRangeCspace) ? CSPACE_RANGE_FULL : CSPACE_RANGE_ACTUAL); } rebuildThumbnails(FALSE); break; default: break; } } int rviewThumb::userEvent(const user_event &ue) { if (ue.type == usr_mdd_dying) { return deleteMDD(*((r_Ref*)(ue.data))); } if (ue.type == usr_cspace_changed) { if (ue.data == (void*)csmap) { rebuildThumbnails(FALSE); return 1; } } return 0; } // Return the pixmap with number no and write a textual description into // caption which has to be at least STRINGSIZE bytes large. wxPixmap *rviewThumb::getPixmapNumber(int no, char *caption) { rviewThumbList *tlst = listHead; int major, minor; wxPixmap *retPix = NULL; if (no >= numPixmaps) return NULL; // major = number of MDD object, minor = number of pixmap for this object major = 0; minor = 0; while ((tlst != NULL) && (no > 0)) { minor = 0; if (no < tlst->numPix) { rviewThumbPixList *tplst = tlst->pixmaps; while ((tplst != NULL) && (no > 0)) { tplst = tplst->next; minor++; no--; } if (tplst == NULL) { retPix = NULL; break; } else { //cout << "found " << (void*)(tplst->pixmap) << endl; retPix = tplst->pixmap; break; } } else { no -= tlst->numPix; tlst = tlst->next; major++; } } if ((retPix == NULL) && (tlst != NULL)) { if ((no == 0) && (tlst->numPix > 0)) { retPix = tlst->pixmaps->pixmap; } } if (retPix != NULL) { sprintf(caption, "MDD %d [%d]", major, minor*projstep); } return retPix; } void rviewThumb::getThumbInfo(int &num, int &npl) { num = numPixmaps; npl = thumbsperline; } void rviewThumb::getGridInfo(int &gx, int &gy) { gx = gridX; gy = gridY; } void rviewThumb::updateCanvasSize(void) { int stepx, stepy; int scrollx, scrolly; RMDBGONCE(3, RMDebug::module_applications, "rviewThumb", "updateCanvasSize()"); gridX = imgWidth + thumb_space; gridY = maxHeight + thumb_space; scrollx = canvas->GetScrollPos(wxHORIZONTAL); scrolly = canvas->GetScrollPos(wxVERTICAL); stepx = (gridX * thumbsperline + thumb_scrstep - 1) / thumb_scrstep; if ((numPixmaps == 0) || (thumbsperline == 0)) { stepy = 1; canvas->EnableScrolling(TRUE, FALSE); canvas->SetScrollRange(wxVERTICAL, 0); } else { stepy = (((numPixmaps + thumbsperline - 1) / thumbsperline) * gridY + thumb_scrstep - 1) / thumb_scrstep; canvas->EnableScrolling(TRUE, TRUE); } canvas->SetScrollbars(thumb_scrstep, thumb_scrstep, stepx, stepy, thumb_pgstep, thumb_pgstep, scrollx, scrolly); } // Init internal variables (e.g. projection-related) according to a sample object void rviewThumb::initForObject(r_Ref &mddObj) { char *data; int i; r_Minterval interv; interv = mddObj->spatial_domain(); dimMDD = interv.dimension(); // freeDims is a bitfield specifying which dimensions are free if (dimMDD <= 2) { freeDims = 3; } else { if ((dimproj == -1) || (dimproj >= dimMDD)) freeDims = 3; else { if (dimproj == 0) freeDims = 6; else if (dimproj == 1) freeDims = 5; else freeDims = 3; } } pt1 = r_Point(dimMDD); pt2 = r_Point(dimMDD); data = projString; for (i=0; iSetValue(projString); parseProjection(mddObj); } // Parse the projection string and set up all internal variables that depend on it. int rviewThumb::parseProjection(r_Ref &mddObj) { int x, h; mapIndex = r_Point(dimMDD); if (rviewParseProjection(mddObj->spatial_domain(), pt1, pt2, projString, &freeDims, &mapIndex) != dimMDD) { cerr << lman->lookup("errorProjection") << endl; rviewErrorbox eb(lman->lookup("errorProjection")); eb.activate(); return 0; } dimproj = -1; dim1 = -1; dim2 = -1; for (x=0; xlookup("errorProjThumb") << endl; return 0; } //cout << "parseProj: dim1 " << dim1 << ", dim2 " << dim2 << ", dimproj " << dimproj << endl; // are there 3 free dimensions to begin with? if (dimproj >= 0) { // user-specified projection value overrides default (last free one) h = atoi(thumbProj->GetValue()); // Now swap around the dimensions as required if (h == dim1) { dim1 = dim2; dim2 = dimproj; dimproj = h; } else if (h == dim2) { dim2 = dimproj; dimproj = h; } // otherwise just keep the default dimproj value } dim1 = mapIndex[dim1]; dim2 = mapIndex[dim2]; // Also read the other variables that can change the appearance of the thumbnails h = atoi(thumbWidth->GetValue()); if ((h >= thumb_minwidth) && (h <= thumb_maxwidth)) { imgWidth = h; } h = atoi(thumbStep->GetValue()); if (h > 0) { projstep = h; } return 1; } wxPixmap *rviewThumb::buildThumbnail(r_Ref &mddObj, rviewBaseType baseType, int dimproject, int projval) { char *data; wxPixmap *pixmap; wxColour palette[2]; int baseSize; int x; r_Minterval thisInterv; int objdim; int srcWidth; r_Point ptlow, pthigh; RMDBGENTER(3, RMDebug::module_applications, "rviewThumb", "buildThumbnail(...)"); //cout << "thumbnail " << dimproject << ", " << projval << endl; thisInterv = mddObj->spatial_domain(); objdim = thisInterv.dimension(); // Only data with at least 2 dimensions is allowed if (objdim < 2) return NULL; // Check if all the thumbnails have the same number of dimensions if (dimMDD != objdim) { cerr << "Warning: inconsistent number of dimensions in collection!" << endl; } // Make sure the points we use are within the spatial domain of this object, in case // the objects in this collection don't have a uniform spatial domain. ptlow = r_Point(dimMDD); pthigh = r_Point(dimMDD); for (x=0; x= thisInterv[x].low()) ptlow[x] = pt1[x]; else ptlow[x] = thisInterv[x].low(); if (pt2[x] <= thisInterv[x].high()) pthigh[x] = pt2[x]; else pthigh[x] = thisInterv[x].high(); } //cout << "Corners " << pt1 << ", " << pt2 << endl; //cout << "low " << ptlow << ", high " << pthigh << endl; baseSize = (int)(mddObj->get_type_length()); if ((baseType == rbt_float) || (baseType == rbt_double)) { doValToCspace = TRUE; mbar->Check(MENU_THUMB_CSPACE_ON, TRUE); configureCspace(TRUE); } rviewFlatProjEnv penv; penv.mddPtr = mddObj.ptr(); penv.pt1 = ptlow; penv.pt2 = pthigh; penv.dim1 = dim1; penv.dim2 = dim2; penv.bt = baseType; penv.doCspace = doValToCspace; if (dimproject >= 0) { penv.pt1[dimproject] = projval; penv.pt2[dimproject] = projval; } srcWidth = (int)(pthigh[dim1] - ptlow[dim1] + 1); //cout << "srcWidth " << srcWidth << endl; if (srcWidth < 1) srcWidth = 1; penv.scale = ((double)imgWidth) / srcWidth; //cout << "dimproject " << dimproject << ", projval " << projval // << ", scale " << penv.scale << endl; //cout << "penv " << penv.pt1 << ", " << penv.pt2 << endl; if (rviewPrepareFlatProjection(penv) != 0) return NULL; if (rviewImageTypes[baseType] == RVIEW_IMGTYPE_MONO) { palette[0] = wxColour(0,0,0); palette[1] = wxColour(255,255,255); } // Colourspace mapping possible for this object? if (rviewCheckInitCspace(baseType, NULL, mddObj) != 0) canDoCspace = TRUE; if (doValToCspace) { penv.cspaceState = rviewCheckInitCspace(baseType, &csmap, mddObj, doFullRangeCspace, NULL, penv.width, &penv.pitch, &penv.depth, &penv.pad); if (csmap != NULL) mbar->Enable(MENU_THUMB_CSPACE_EDIT, TRUE); } else penv.cspaceState = 0; penv.csmap = csmap; /*if (penv.pitch * penv.height >= 16*1024*1024) return NULL;*/ if ((data = (char*)malloc(penv.pitch * penv.height)) == NULL) return NULL; if (rviewPerformFlatProjection(penv, data) != 0) { free(data); return NULL; } pixmap = new wxPixmap((wxWindow*)canvas, penv.width, penv.height, penv.depth, penv.pad, data, rviewImage::getPixmapFlags(), (rviewImageTypes[baseType] == RVIEW_IMGTYPE_MONO) ? palette : NULL); RMDBGEXIT(3, RMDebug::module_applications, "rviewThumb", "buildThumbnail(...) Pixmap " << (void*)pixmap ); return pixmap; } void rviewThumb::newThumbWidth(int newWidth) { if (newWidth == imgWidth) return; imgWidth = newWidth; rebuildThumbnails(FALSE); } void rviewThumb::rebuildThumbnails(bool fromScratch) { int i, j; rviewThumbList *tlst; rviewThumbPixList *tplst; //cout << "rebuildThumbnails " << fromScratch << endl; tlst = listHead; if (fromScratch) { // Delete all thumbnail pixmaps, including the chain structure for (i=0; inext) { deletePixmapChain(tlst); } maxHeight = 0; for (i=0, tlst=listHead; inext) { if (pixmapsFromMDD(tlst) == 0) { cerr << lman->lookup("errorProjThumb") << endl; } } } else { // 1) Delete all the thumbnail pixmaps, but leave the chain intact! for (i=0; inext) { tplst = tlst->pixmaps; while (tplst != NULL) { if (tplst->pixmap != NULL) delete tplst->pixmap; tplst->pixmap = NULL; tplst = tplst->next; } } // 2) Create new ones. Doing this in two passes is better for the memory allocation for (i=0, tlst=listHead; inext) { tplst = tlst->pixmaps; while (tplst != NULL) { if ((tplst->pixmap = buildThumbnail(tlst->mdd, tlst->baseType, tplst->dimproj, tplst->projval)) == NULL) { cerr << lman->lookup("errorProjThumb") << endl; } tplst = tplst->next; } } } // Now adapt the maximum height maxHeight = 0; tlst = listHead; for (i=0; inext) { tplst = tlst->pixmaps; while (tplst != NULL) { if (tplst->pixmap != NULL) { j = tplst->pixmap->getHeight(); if (j > maxHeight) maxHeight = j; } tplst = tplst->next; } } updateCanvasSize(); }