Ejemplo n.º 1
0
void ImageLoader::buildAllIconsAndPutInCache(TXshSimpleLevel *level,
											 std::vector<TFrameId> fids,
											 std::vector<std::string> iconIds,
											 bool cacheImagesAsWell)
{
	if (m_path.getType() != "tlv")
		return;
	if (fids.empty() || iconIds.empty())
		return;
	/*- fidとアイコンidの数は同じはず -*/
	if ((int)fids.size() != (int)iconIds.size())
		return;

	try {
		TLevelReaderP lr(m_path);
		if (!lr)
			return;

		for (int i = 0; i < (int)fids.size(); i++) {
			lr->doReadPalette(false);
			TImageReaderP ir = lr->getFrameReader(fids[i]);
			lr->doReadPalette(true);

			TImageInfo info;
			TPalette *palette = level->getPalette();
			std::string fullImgId = level->getImageId(fids[i]);

			/*- 画像データも一緒にキャッシュする場合 -*/
			if (cacheImagesAsWell) {
				ir->enable16BitRead(m_64bitCompatible);
				ir->setShrink(1);
				TImageP fullImg = ir->load();
				if (fullImg) {
					if (palette)
						fullImg->setPalette(palette);
					TImageCache::instance()->add(fullImgId, fullImg, true);
					setImageInfo(info, fullImg.getPointer());
				}
			}

			/*- アイコンのロード -*/
			TImageP img = ir->loadIcon();
			ir->enable16BitRead(false);
			if (img) {
				if (palette)
					img->setPalette(palette);
				TImageCache::instance()->add(iconIds[i], img, true);
			}
		}
	} catch (...) {
		return;
	}
}
static void setFrame(QScriptEngine *engine, QScriptValue &level, const TFrameId &fid,
                     const TImageP &drawing) {
  QScriptValueList args;
  args << QString::fromStdString(fid.expand())
       << Wrapper::create(engine, new Image(drawing.getPointer()));
  level.property("setFrame").call(level, args);
}
Ejemplo n.º 3
0
void ImagePainter::paintImage(const TImageP &image, const TDimension &imageSize,
                              const TDimension &viewerSize, const TAffine &aff,
                              const VisualSettings &visualSettings,
                              const CompareSettings &compareSettings,
                              const TRect &loadbox) {
  glDisable(GL_DEPTH_TEST);

  if (visualSettings.m_drawExternalBG) {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
  }

  GLenum error = glGetError();
  // assert(error==GL_NO_ERROR);
  if (error != GL_NO_ERROR) {
    printf("ImagePainter::paintImage() gl_error:%d\n", error);
  }

  if (!image) return;

  TRasterImageP rimg = (TRasterImageP)image;
  TVectorImageP vimg = (TVectorImageP)image;
  TToonzImageP timg  = (TToonzImageP)image;

  TRect clipRect(viewerSize);
  clipRect -= TPoint(viewerSize.lx * 0.5, viewerSize.ly * 0.5);
  Painter painter(viewerSize, imageSize, aff, image->getPalette(),
                  visualSettings);

  if (rimg)
    painter.onRasterImage(rimg.getPointer());
  else if (vimg)
    painter.onVectorImage(vimg.getPointer());
  else if (timg)
    painter.onToonzImage(timg.getPointer());

  if (visualSettings.m_blankColor != TPixel::Transparent) {
    painter.drawBlank();
    return;
  }

  // if I have a color filter applied using a glmask, , drawing of images must
  // be done on black bg!
  if (!vimg)
    painter.flushRasterImages(
        loadbox, visualSettings.m_doCompare ? compareSettings.m_compareX
                                            : DefaultCompareValue,
        visualSettings.m_doCompare ? compareSettings.m_compareY
                                   : DefaultCompareValue,
        compareSettings.m_swapCompared);

  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

  if (visualSettings.m_doCompare)
    drawCompareLines(viewerSize, compareSettings.m_compareX,
                     compareSettings.m_compareY);
}
Ejemplo n.º 4
0
void RasterSelectionTool::draw()
{
	TImageP image = getImage(false);
	TToonzImageP ti = (TToonzImageP)image;
	TRasterImageP ri = (TRasterImageP)image;
	if (!ti && !ri)
		return;

	if (m_setSaveboxTool && m_modifySavebox.getValue()) {
		m_setSaveboxTool->draw();
		return;
	}

	glPushMatrix();

	/*-- フローティング画像の描画 --*/
	drawFloatingSelection();

	if (m_strokeSelectionType.getValue() == POLYLINE_SELECTION && !m_rasterSelection.isFloating())
		drawPolylineSelection();
	if (m_rasterSelection.isEmpty())
		m_bboxs.clear();

	/*-- 選択範囲の変形ハンドルの描画 --*/
	if (getBBoxsCount() > 0)
		drawCommandHandle(image.getPointer());

	/*-- 選択範囲の四角形の描画 --*/
	if (m_selecting && !m_selectingRect.isEmpty())
		drawRectSelection(image.getPointer());

	/*-- バウンディングボックスの描画 --*/
	/*
  if(ti)
  {
	 TRectD saveBox = ToonzImageUtils::convertRasterToWorld(ti->getSavebox(), ti);
    drawRect(saveBox.enlarge(0.5)*ti->getSubsampling(), TPixel32::Black, 0x5555, true);
  }
  */

	glPopMatrix();
}
Ejemplo n.º 5
0
/*-- Paste後のフローティング状態の画像の描画 --*/
void RasterSelectionTool::drawFloatingSelection()
{
	double pixelSize = TTool::getApplication()->getCurrentTool()->getTool()->getPixelSize();

	TAffine aff = m_rasterSelection.getTransformation();
	glPushMatrix();
	tglMultMatrix(aff);

	//draw m_floatingSelection
	if (isFloating()) {
		TRasterP floatingSelection = m_rasterSelection.getFloatingSelection();
		TImageP app;
		if (TRasterCM32P toonzRas = (TRasterCM32P)(floatingSelection))
			app = TToonzImageP(toonzRas, toonzRas->getBounds());
		if (TRaster32P fullColorRas = (TRaster32P)(floatingSelection))
			app = TRasterImageP(fullColorRas);
		if (TRasterGR8P grRas = (TRasterGR8P)(floatingSelection))
			app = TRasterImageP(grRas);
		app->setPalette(m_rasterSelection.getCurrentImage()->getPalette());
		FourPoints points = getBBox() * aff.inv();
		TRectD bbox = points.getBox();
		TPointD center((bbox.getP00() + bbox.getP11()) * 0.5);
		if (TToonzImageP ti = (TToonzImageP)app)
			GLRasterPainter::drawRaster(TTranslation(center), ti, false);
		if (TRasterImageP ri = (TRasterImageP)app)
			GLRasterPainter::drawRaster(TTranslation(center), ri, true);
	}

	std::vector<TStroke> strokes = m_rasterSelection.getStrokes();
	int i;
	for (i = 0; i < (int)strokes.size(); i++) {
		TStroke stroke = strokes[i];
		glEnable(GL_LINE_STIPPLE);
		glLineStipple(1, 0xF0F0);
		tglColor(TPixel32::Black);
		drawStrokeCenterline(stroke, pixelSize);
		glDisable(GL_LINE_STIPPLE);
	}

	glPopMatrix();
}
Ejemplo n.º 6
0
	void redo() const
	{
		TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
		TXshCell cell = xsheet->getCell(m_r, m_c);
		TImageP image = (TRasterImageP)cell.getImage(true);
		if (!image)
			return;
		TRasterP ras = image->raster();
		if (!ras)
			return;

		onChange(ras, m_threshold, m_softness);
		TXshSimpleLevel *simpleLevel = cell.getSimpleLevel();
		assert(simpleLevel);
		simpleLevel->touchFrame(cell.getFrameId());
		simpleLevel->setDirtyFlag(false);
		IconGenerator::instance()->invalidate(simpleLevel, cell.getFrameId());
		if (m_isLastInBlock) {
			TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
		}
	}
Ejemplo n.º 7
0
	void undo() const
	{
		std::map<TFrameId, QString>::const_iterator it = m_images.begin();
		TPalette *palette = m_palette->clone();
		m_level->setPalette(palette);
		vector<TFrameId> fids;
		for (; it != m_images.end(); ++it) //, ++mit)
		{
			QString id = "MergeCmappedUndo" + QString::number(m_mergeCmappedSessionId) + "-" + QString::number(it->first.getNumber());
			TImageP img = TImageCache::instance()->get(id, false)->cloneImage();
			img->setPalette(palette);
			m_level->setFrame(it->first, img);
			fids.push_back(it->first);
		}

		removeLevel(m_xl);

		TApp::instance()->getPaletteController()->getCurrentLevelPalette()->setPalette(palette);
		m_level->setDirtyFlag(true);
		TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
	}
Ejemplo n.º 8
0
void AntialiasPopup::setCurrentSampleRaster()
{
	TRasterP sampleRas;

	m_startRas = TRasterP();
	TSelection *selection = TApp::instance()->getCurrentSelection()->getSelection();
	TCellSelection *cellSelection = dynamic_cast<TCellSelection *>(selection);
	TFilmstripSelection *filmstripSelection = dynamic_cast<TFilmstripSelection *>(selection);
	TImageP image;
	if (cellSelection) {
		TApp *app = TApp::instance();
		TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
		TXshCell cell = xsh->getCell(app->getCurrentFrame()->getFrameIndex(), app->getCurrentColumn()->getColumnIndex());
		TImageP aux = cell.getImage(true);
		if (aux)
			image = aux->cloneImage();
	} else if (filmstripSelection) {
		TApp *app = TApp::instance();
		TXshSimpleLevel *simpleLevel = app->getCurrentLevel()->getSimpleLevel();
		if (simpleLevel) {
			TImageP imageAux = simpleLevel->getFrame(app->getCurrentFrame()->getFid(), true);
			if (imageAux)
				image = imageAux->cloneImage();
		}
	}

	if (!image || !(sampleRas = image->raster())) {
		m_viewer->setImage(TImageP());
		m_viewer->update();
		m_okBtn->setEnabled(false);
		return;
	}

	m_okBtn->setEnabled(true);
	m_startRas = sampleRas->clone();
	onChange(m_startRas, sampleRas, m_thresholdField->getValue(), m_softnessField->getValue());

	m_viewer->setImage(image);
	m_viewer->update();
}
Ejemplo n.º 9
0
	TRasterP getRaster() const
	{
		return m_img->raster();
	}
Ejemplo n.º 10
0
void AntialiasPopup::apply()
{
	TCellSelection *cellSelection = dynamic_cast<TCellSelection *>(TSelection::getCurrent());
	int threshold = m_thresholdField->getValue();
	int softness = m_softnessField->getValue();
	if (cellSelection) {
		std::set<TImage *> images;
		int r0, c0, r1, c1;
		cellSelection->getSelectedCells(r0, c0, r1, c1);
		TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
		bool oneImageChanged = false;
		int c, r;
		TUndoManager::manager()->beginBlock();
		for (c = c0; c <= c1; c++)
			for (r = r0; r <= r1; r++) {
				TXshCell cell = xsheet->getCell(r, c);
				TImageP image = cell.getImage(true);
				if (!image)
					continue;
				if (images.find(image.getPointer()) != images.end())
					continue;
				TRasterP ras = image->raster();
				if (!ras)
					continue;
				images.insert(image.getPointer());
				oneImageChanged = true;
				TUndoManager::manager()->add(new TRasterAntialiasUndo(threshold, softness, r, c, ras->clone()));
				onChange(ras, threshold, softness);
				TXshSimpleLevel *simpleLevel = cell.getSimpleLevel();
				assert(simpleLevel);
				simpleLevel->touchFrame(cell.getFrameId());
				simpleLevel->setDirtyFlag(true);
				IconGenerator::instance()->invalidate(simpleLevel, cell.getFrameId());
			}
		TUndoManager::manager()->endBlock();
		if (oneImageChanged) {
			close();
			return;
		}
	}
	TFilmstripSelection *filmstripSelection = dynamic_cast<TFilmstripSelection *>(TSelection::getCurrent());
	if (filmstripSelection) {
		TXshSimpleLevel *simpleLevel = TApp::instance()->getCurrentLevel()->getSimpleLevel();
		if (simpleLevel) {
			std::set<TFrameId> fids = filmstripSelection->getSelectedFids();
			std::set<TFrameId>::iterator it = fids.begin();
			bool oneImageChanged = false;
			for (it; it != fids.end(); it++) {
				TImageP image = simpleLevel->getFrame(*it, true);
				if (!image)
					continue;
				TRasterP ras = image->raster();
				if (!ras)
					continue;
				oneImageChanged = true;
				onChange(ras, threshold, softness);
				simpleLevel->touchFrame(*it);
				simpleLevel->setDirtyFlag(true);
				IconGenerator::instance()->invalidate(simpleLevel, *it);
			}
			if (oneImageChanged) {
				close();
				return;
			}
		}
	}

	DVGui::error(QObject::tr("The current selection is invalid."));
	return;
}
Ejemplo n.º 11
0
StylePicker::StylePicker(const TImageP &image)
	: m_image(image), m_palette(image->getPalette())
{
}
QString ImageBuilder::add(const TImageP &img, const TAffine &aff) {
  if (fabs(aff.det()) < 0.001) return "";
  if (m_img && (m_img->getType() != img->getType()))
    return "Image type mismatch";

  if (!m_img && img->getType() != TImage::VECTOR && m_width > 0 &&
      m_height > 0) {
    TRasterP ras = img->raster()->create(m_width, m_height);
    if (img->getType() == TImage::RASTER)
      m_img = TRasterImageP(ras);
    else if (img->getType() == TImage::TOONZ_RASTER) {
      m_img = TToonzImageP(ras, ras->getBounds());
      m_img->setPalette(img->getPalette());
    } else
      return "Bad image type";
  }

  if (!m_img && aff.isIdentity()) {
    m_img = img->cloneImage();
  } else if (img->getType() == TImage::VECTOR) {
    // vector image
    if (!m_img) {
      // transform
      TVectorImageP vi = img->cloneImage();
      vi->transform(aff);
      m_img = vi;
    } else {
      // merge
      TVectorImageP up = img;
      TVectorImageP dn = m_img;
      dn->mergeImage(up, aff);
    }
  } else {
    if (img->getType() != TImage::TOONZ_RASTER &&
        img->getType() != TImage::RASTER) {
      // this should not ever happen
      return "Bad image type";
    }
    TRasterP up = img->raster();
    if (!m_img) {
      // create an empty bg
      TRasterP ras = up->create();
      ras->clear();
      if (img->getType() == TImage::TOONZ_RASTER) {
        TRasterCM32P rasCm = ras;
        m_img              = TToonzImageP(rasCm,
                             TRect(0, 0, ras->getLx() - 1, ras->getLy() - 1));
        m_img->setPalette(img->getPalette());
      } else {
        m_img = TRasterImageP(ras);
      }
    }
    TRasterP dn = m_img->raster();
    if (aff.isTranslation() && aff.a13 == floor(aff.a13) &&
        aff.a23 == floor(aff.a23)) {
      // just a integer coord translation
      TPoint delta = -up->getCenter() + dn->getCenter() +
                     TPoint((int)aff.a13, (int)aff.a23);
      TRop::over(dn, up, delta);
    } else {
      TAffine aff1 = TTranslation(dn->getCenterD()) * aff *
                     TTranslation(-up->getCenterD());
      TRop::over(dn, up, aff1, TRop::Mitchell);
    }
  }
  return "";
}
Ejemplo n.º 13
0
TImageP ImageLoader::build(int imFlags, void *extData)
{
	assert(extData);

	// Extract external data
	BuildExtData *data = static_cast<BuildExtData *>(extData);

	int subsampling = buildSubsampling(imFlags, data);

	try {
		// Initialize level reader
		TLevelReaderP lr(m_path);
		if (!lr)
			return TImageP();

		// Load info in cases where it's required first
		lr->doReadPalette(false);

		if ((m_path.getType() == "pli") || (m_path.getType() == "svg") || (m_path.getType() == "psd"))
			lr->loadInfo();

		lr->doReadPalette(true); // Allow palette loading

		TImageReaderP ir = lr->getFrameReader(m_fid);

		bool enable64bit = (imFlags & ImageManager::is64bitEnabled);
		ir->enable16BitRead(enable64bit); // Set 64-bit loading if required

		// Load the image
		TImageP img;

		if (data->m_icon && m_path.getType() == "tlv")
			img = ir->loadIcon(); // TODO: Why just in the tlv case??
		else {
			ir->setShrink(subsampling);
			img = ir->load();
		}

		ir->enable16BitRead(false);

		if (!img)
			return img; // There was an error loading the image.

		TPalette *palette = data->m_sl->getPalette();
		if (palette)
			img->setPalette(palette);

		if (subsampling > 1) {
			// Store the subsampling info in the image
			if (TRasterImageP ri = img)
				ri->setSubsampling(subsampling);
			else if (TToonzImageP ti = img)
				ti->setSubsampling(subsampling);
		}

		// In case the image will be cached, store its subsampling and 64 bit compatibility
		if (!(imFlags & ImageManager::dontPutInCache)) {
			m_subsampling = subsampling;
			m_64bitCompatible = data->m_sl->is16BitChannelLevel() ? enable64bit : true;
		}

		return img;
	} catch (...) {
		return TImageP();
	}
}
Ejemplo n.º 14
0
TImage *TTool::touchImage() {
  if (!m_application) return 0;

  m_cellsData.clear();

  m_isLevelCreated  = false;
  m_isFrameCreated  = false;
  Preferences *pref = Preferences::instance();

  bool isAutoCreateEnabled   = pref->isAutoCreateEnabled();
  bool animationSheetEnabled = pref->isAnimationSheetEnabled();
  bool isAutoStretchEnabled  = pref->isAutoStretchEnabled();

  TFrameHandle *currentFrame    = m_application->getCurrentFrame();
  TXshLevelHandle *currentLevel = m_application->getCurrentLevel();

  if (currentFrame->isEditingLevel()) {
    // Editing level

    // no level => return 0
    TXshLevel *xl = currentLevel->getLevel();
    if (!xl) return 0;
    TXshSimpleLevel *sl = xl->getSimpleLevel();
    if (!sl || sl->isEmpty()) return 0;

    TFrameId fid = currentFrame->getFid();
    TImageP img  = sl->getFrame(fid, true);
    if (!img) {
      // no drawing found
      if (sl->isSubsequence() || sl->isReadOnly() || !isAutoCreateEnabled)
        return 0;

      // create a new drawing
      img = sl->createEmptyFrame();
      sl->setFrame(fid, img);
      currentLevel->notifyLevelChange();
      m_isFrameCreated = true;
    }
    return img.getPointer();
  } else {
    // editing xsheet
    if (m_application->getCurrentObject()->isSpline()) return 0;

    TSceneHandle *currentScene = m_application->getCurrentScene();
    ToonzScene *scene          = currentScene->getScene();
    int row                    = currentFrame->getFrame();
    int col = m_application->getCurrentColumn()->getColumnIndex();
    if (col < 0) return 0;

    TXsheetHandle *currentXsheet = m_application->getCurrentXsheet();
    TXsheet *xsh                 = currentXsheet->getXsheet();
    if (!xsh) return 0;

    TXshCell cell       = xsh->getCell(row, col);
    TXshSimpleLevel *sl = cell.getSimpleLevel();

    if (sl != 0) {
      // current cell is not empty
      if (isAutoCreateEnabled && animationSheetEnabled && row > 0 &&
          xsh->getCell(row - 1, col) == xsh->getCell(row, col)) {
        // animationSheet is enabled and the current cell is a "hold". We must
        // create a new drawing.
        // measure the hold length (starting from the current row) : r0-r1
        int r0 = row, r1 = row;
        if (isAutoStretchEnabled)
          while (xsh->getCell(r1 + 1, col) == cell) r1++;
        // find the proper frameid (possibly addisng suffix, in order to avoid a
        // fid already used)
        TFrameId fid = getNewFrameId(sl, row);
        // create the new drawing
        TImageP img      = sl->createEmptyFrame();
        m_isFrameCreated = true;
        // insert the drawing in the level
        sl->setFrame(fid, img);
        // update the cell
        cell = TXshCell(sl, fid);
        // update the xsheet (change the current cell and possibly all the
        // following "hold")
        for (int r = r0; r <= r1; r++) xsh->setCell(r, col, cell);
        // notify
        currentXsheet->notifyXsheetChanged();
        currentScene->notifyCastChange();
        currentLevel->notifyLevelChange();
        m_cellsData.push_back(r0);
        m_cellsData.push_back(r1);
        m_cellsData.push_back(0);
      }
      // we've found the image. return it.
      return cell.getImage(true).getPointer();
    }

    // current cell is empty.
    if (!isAutoCreateEnabled) return 0;

    // get the column range
    int r0, r1;
    xsh->getCellRange(col, r0, r1);

    if (animationSheetEnabled && r0 <= r1) {
      // animation sheet enabled and not empty column. We must create a new
      // drawing in the column level and possibly add "holds"

      // find the last not-empty cell before the current one (a) and the first
      // after (b)
      int a = row - 1, b = row + 1;
      while (a >= r0 && xsh->getCell(a, col).isEmpty()) a--;
      while (b <= r1 && xsh->getCell(b, col).isEmpty()) b++;

      // find the level we must attach to
      if (a >= r0) {
        // there is a not-emtpy cell before the current one
        sl = xsh->getCell(a, col).getSimpleLevel();
      } else if (b <= r1) {
        sl = xsh->getCell(b, col).getSimpleLevel();
      }
      if (sl) {
        // note: sl should be always !=0 (the column is not empty)
        // if - for some reason - it is ==0 then we skip to the standard (i.e.
        // !animationSheetEnabled) beahviour

        // create the drawing
        // find the proper frameid (possibly addisng suffix, in order to avoid a
        // fid already used)
        TFrameId fid = getNewFrameId(sl, row);
        // create the new drawing
        TImageP img      = sl->createEmptyFrame();
        m_isFrameCreated = true;
        // insert the drawing in the level
        sl->setFrame(fid, img);
        // update the cell
        cell = TXshCell(sl, fid);
        xsh->setCell(row, col, cell);

        // create holds
        if (!isAutoStretchEnabled) {
          m_cellsData.push_back(row);
          m_cellsData.push_back(row);
          m_cellsData.push_back(2);  // vuoto => nuovo
        } else {
          if (a >= r0) {
            // create a hold before : [a+1, row-1]
            TXshCell aCell = xsh->getCell(a, col);
            for (int i = a + 1; i < row; i++) xsh->setCell(i, col, aCell);
            m_cellsData.push_back(a + 1);
            m_cellsData.push_back(row - 1);
            m_cellsData.push_back(1);  // vuoto => vecchio

            if (b <= r1 && xsh->getCell(b, col).getSimpleLevel() == sl) {
              // create also a hold after
              for (int i = row + 1; i < b; i++) xsh->setCell(i, col, cell);
              m_cellsData.push_back(row);
              m_cellsData.push_back(b - 1);
              m_cellsData.push_back(2);  // vuoto => nuovo
            } else {
              m_cellsData.push_back(row);
              m_cellsData.push_back(row);
              m_cellsData.push_back(2);  // vuoto => nuovo
            }
          } else if (b <= r1) {
            // create a hold after
            for (int i = row + 1; i < b; i++) xsh->setCell(i, col, cell);
            m_cellsData.push_back(row);
            m_cellsData.push_back(b - 1);
            m_cellsData.push_back(2);  // vuoto => nuovo
          }
        }
      }
      // notify & return
      currentXsheet->notifyXsheetChanged();
      currentScene->notifyCastChange();
      currentLevel->notifyLevelChange();
      return cell.getImage(true).getPointer();
    }

    if (row > 0 && xsh->getCell(row - 1, col).getSimpleLevel() != 0 &&
        !animationSheetEnabled) {
      sl = xsh->getCell(row - 1, col).getSimpleLevel();
      if (sl->getType() != OVL_XSHLEVEL ||
          sl->getPath().getFrame() != TFrameId::NO_FRAME) {
        // la cella precedente contiene un drawing di un livello. animationSheet
        // e' disabilitato
        // creo un nuovo frame
        currentLevel->setLevel(sl);
        if (sl->isSubsequence() || sl->isReadOnly()) return 0;
        TFrameId fid     = sl->index2fid(sl->getFrameCount());
        TImageP img      = sl->createEmptyFrame();
        m_isFrameCreated = true;
        sl->setFrame(fid, img);
        cell = TXshCell(sl, fid);
        xsh->setCell(row, col, cell);
        currentXsheet->notifyXsheetChanged();
        currentScene->notifyCastChange();
        currentLevel->notifyLevelChange();
        return img.getPointer();
      }
    }

    // animation sheet disabled or empty column. autoCreate is enabled: we must
    // create a new level
    int levelType    = pref->getDefLevelType();
    TXshLevel *xl    = scene->createNewLevel(levelType);
    sl               = xl->getSimpleLevel();
    m_isLevelCreated = true;

    // create the drawing
    TFrameId fid = animationSheetEnabled ? getNewFrameId(sl, row) : TFrameId(1);
    TImageP img  = sl->createEmptyFrame();
    m_isFrameCreated = true;
    sl->setFrame(fid, img);
    cell = TXshCell(sl, fid);
    xsh->setCell(row, col, cell);
    if (animationSheetEnabled) {
      m_cellsData.push_back(row);
      m_cellsData.push_back(row);
      m_cellsData.push_back(2);  // vuoto => nuovo
    }

    currentXsheet->notifyXsheetChanged();
    currentScene->notifyCastChange();
    currentLevel->notifyLevelChange();
    return img.getPointer();
  }
}