Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/rasterselection.h"
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "tpaletteutil.h"
Toshihiro Shimizu 890ddd
#include "trop.h"
Toshihiro Shimizu 890ddd
#include "drawutil.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
#include "timagecache.h"
Toshihiro Shimizu 890ddd
#include "tpixelutils.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/rasterimagedata.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/strokesdata.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/selectioncommandids.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/tselectionhandle.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/dvdialog.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzimageutils.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/tpalettehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/palettecontroller.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcamera.h"
Toshihiro Shimizu 890ddd
#include "toonz/trasterimageutils.h"
Toshihiro Shimizu 890ddd
#include "toonz/toonzimageutils.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qapplication></qapplication>
Toshihiro Shimizu 890ddd
#include <qclipboard></qclipboard>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "timage_io.h"
Toshihiro Shimizu 890ddd
#include "tropcm.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRasterP getRaster(const TImageP image) {
Shinya Kitaoka 120a6e
  if (TToonzImageP ti = (TToonzImageP)(image)) return ti->getRaster();
Shinya Kitaoka 120a6e
  if (TRasterImageP ri = (TRasterImageP)(image)) return ri->getRaster();
Shinya Kitaoka 120a6e
  return (TRasterP)(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRect convertWorldToRaster(const TRectD area, const TRasterP ras) {
Shinya Kitaoka 120a6e
  if (area.isEmpty()) return TRect();
Shinya Kitaoka 120a6e
  if (!ras)
Shinya Kitaoka 120a6e
    return TRect(tfloor(area.x0), tfloor(area.y0), tfloor(area.x1) - 1,
Shinya Kitaoka 120a6e
                 tfloor(area.y1) - 1);
Shinya Kitaoka 120a6e
  TRectD rect(area + ras->getCenterD());
Shinya Kitaoka 120a6e
  return TRect(tfloor(rect.x0), tfloor(rect.y0), tceil(rect.x1) - 1,
Shinya Kitaoka 120a6e
               tceil(rect.y1) - 1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRect convertWorldToRaster(const TRectD area, const TImageP image) {
Shinya Kitaoka 120a6e
  TRasterImageP ri(image);
Shinya Kitaoka 120a6e
  TToonzImageP ti(image);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Watch out! TToonzImage::getRaster() returns a TRasterCM32P, while
Shinya Kitaoka 120a6e
  // TRasterImage::getRaster() returns a TRasterP!
Shinya Kitaoka 120a6e
  TRasterP ras = (ri) ? ri->getRaster() : (TRasterP)ti->getRaster();
Shinya Kitaoka 120a6e
  return convertWorldToRaster(area, ras);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD convertRasterToWorld(const TRect area, const TImageP image) {
Shinya Kitaoka 120a6e
  TToonzImageP ti(image);
Shinya Kitaoka 120a6e
  if (ti) return ToonzImageUtils::convertRasterToWorld(area, image);
Shinya Kitaoka 120a6e
  return TRasterImageUtils::convertRasterToWorld(area, image);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD intersection(const TRectD &area, const TImageP image) {
Shinya Kitaoka 120a6e
  TToonzImageP ti(image);
Shinya Kitaoka 120a6e
  if (ti)
Shinya Kitaoka 120a6e
    return area * ToonzImageUtils::convertRasterToWorld(
Shinya Kitaoka 120a6e
                      ti->getRaster()->getBounds(), image);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRasterImageP ri(image);
Shinya Kitaoka 120a6e
  if (ri)
Shinya Kitaoka 120a6e
    return area * TRasterImageUtils::convertRasterToWorld(
Shinya Kitaoka 120a6e
                      ri->getRaster()->getBounds(), ri);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return area;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// The stroke is in raster coordinates
Toshihiro Shimizu 890ddd
template <class class="" pixel1,="" pixel2=""></class>
Shinya Kitaoka 120a6e
TRasterPT<pixel1> getImageFromStroke(TRasterPT<pixel2> ras,</pixel2></pixel1>
Shinya Kitaoka 120a6e
                                     const TStroke &stroke) {
Shinya Kitaoka 120a6e
  TRectD regionsBoxD = stroke.getBBox();
Shinya Kitaoka 120a6e
  // E' volutamente allargato di un pixel!
Shinya Kitaoka 120a6e
  TRect regionsBox(tfloor(regionsBoxD.x0), tfloor(regionsBoxD.y0),
Shinya Kitaoka 120a6e
                   tceil(regionsBoxD.x1), tceil(regionsBoxD.y1));
Shinya Kitaoka 120a6e
  regionsBox *= ras->getBounds();
Shinya Kitaoka 120a6e
  if (regionsBox.isEmpty()) return (TRasterPT<pixel1>)0;</pixel1>
Shinya Kitaoka 120a6e
  TRasterPT<pixel1> buffer(regionsBox.getSize());</pixel1>
Shinya Kitaoka 120a6e
  buffer->clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Compute regions created by the std::vector
Shinya Kitaoka 120a6e
  TVectorImage app;
Shinya Kitaoka 120a6e
  app.addStroke(new TStroke(stroke));
Shinya Kitaoka 120a6e
  app.findRegions();
Shinya Kitaoka 120a6e
  int reg, j, k, y;
Shinya Kitaoka 120a6e
  ras->lock();
Shinya Kitaoka 120a6e
  for (reg = 0; reg < (int)app.getRegionCount(); reg++) {
Shinya Kitaoka 120a6e
    // For each region, pixels inside the region are copied in buffer!
Shinya Kitaoka 120a6e
    TRectD bBoxD = stroke.getBBox();
Shinya Kitaoka 120a6e
    TRect bBox(tfloor(bBoxD.x0), tfloor(bBoxD.y0), tceil(bBoxD.x1) - 1,
Shinya Kitaoka 120a6e
               tceil(bBoxD.y1) - 1);
Shinya Kitaoka 120a6e
    bBox *= ras->getBounds();
Shinya Kitaoka 120a6e
    for (y = bBox.y0; y <= bBox.y1; y++) {
Shinya Kitaoka 120a6e
      PIXEL2 *selectedLine = ras->pixels(y);
Shinya Kitaoka 120a6e
      int startY           = y - regionsBox.y0;
Shinya Kitaoka 120a6e
      PIXEL1 *bufferLine   = buffer->pixels(startY >= 0 ? startY : 0);
Shinya Kitaoka 120a6e
      std::vector<double> intersections;</double>
Shinya Kitaoka 120a6e
      app.getRegion(reg)->computeScanlineIntersections(y, intersections);
Shinya Kitaoka 120a6e
      if (intersections.empty())
Shinya Kitaoka 120a6e
        app.getRegion(reg)->computeScanlineIntersections(y + 0.9,
Shinya Kitaoka 120a6e
                                                         intersections);
Shinya Kitaoka 120a6e
      for (j = 0; j < (int)intersections.size(); j += 2) {
Shinya Kitaoka 120a6e
        if (intersections[j] == intersections[j + 1]) continue;
Shinya Kitaoka 120a6e
        int from = std::max(tfloor(intersections[j]), bBox.x0);
Shinya Kitaoka 120a6e
        int to   = std::min(tceil(intersections[j + 1]), bBox.x1);
Shinya Kitaoka 120a6e
        for (k = from; k <= to; k++) {
Shinya Kitaoka 120a6e
          TRasterCM32P bufferCM(buffer);
Shinya Kitaoka 120a6e
          TRaster32P buffer32(buffer);
Shinya Kitaoka 120a6e
          TRasterCM32P rasCM(ras);
Shinya Kitaoka 120a6e
          TRaster32P ras32(ras);
Shinya Kitaoka 120a6e
          TRasterGR8P rasGR8(ras);
Shinya Kitaoka 120a6e
          if (bufferCM && rasCM) {
Shinya Kitaoka 120a6e
            TPixelCM32 *bottomPix =
Shinya Kitaoka 120a6e
                (TPixelCM32 *)bufferLine + k - regionsBox.x0;
Shinya Kitaoka 120a6e
            TPixelCM32 *topPix = (TPixelCM32 *)selectedLine + k;
Shinya Kitaoka 120a6e
            *bottomPix         = *topPix;
Shinya Kitaoka 120a6e
          } else if (buffer32 && ras32) {
Shinya Kitaoka 120a6e
            TPixel32 *bottomPix = (TPixel32 *)bufferLine + k - regionsBox.x0;
Shinya Kitaoka 120a6e
            TPixel32 *topPix    = (TPixel32 *)selectedLine + k;
Shinya Kitaoka 120a6e
            *bottomPix          = *topPix;
Shinya Kitaoka 120a6e
          } else if (buffer32 && rasGR8) {
Shinya Kitaoka 120a6e
            TPixel32 *bottomPix = (TPixel32 *)bufferLine + k - regionsBox.x0;
Shinya Kitaoka 120a6e
            TPixelGR8 *topPix   = (TPixelGR8 *)selectedLine + k;
Shinya Kitaoka 120a6e
            *bottomPix =
Shinya Kitaoka 120a6e
                TPixel32(topPix->value, topPix->value, topPix->value, 255);
Shinya Kitaoka 120a6e
          } else
Shinya Kitaoka 120a6e
            assert(0);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ras->unlock();
Shinya Kitaoka 120a6e
  return buffer;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <class class="" pixel1,="" pixel2=""></class>
Shinya Kitaoka 120a6e
TRasterPT<pixel1> getImageFromSelection(TRasterPT<pixel2> &ras,</pixel2></pixel1>
Shinya Kitaoka 120a6e
                                        RasterSelection &selection) {
Shinya Kitaoka 120a6e
  if (selection.isEmpty()) return (TRasterPT<pixel1>)0;</pixel1>
Shinya Kitaoka 120a6e
  TRectD wSelectionBound = selection.getSelectionBbox();
Shinya Kitaoka 120a6e
  TRect rSelectionBound  = convertWorldToRaster(wSelectionBound, ras);
Shinya Kitaoka 120a6e
  rSelectionBound *= ras->getBounds();
Shinya Kitaoka 120a6e
  TRasterPT<pixel1> selectedRaster(rSelectionBound.getSize());</pixel1>
Shinya Kitaoka 120a6e
  selectedRaster->clear();
Shinya Kitaoka 120a6e
  std::vector<tstroke> strokes = selection.getStrokes();</tstroke>
Shinya Kitaoka 120a6e
  TPoint startPosition         = rSelectionBound.getP00();
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < strokes.size(); i++) {
Shinya Kitaoka 120a6e
    TStroke stroke = strokes[i];
Shinya Kitaoka 120a6e
    stroke.transform(TTranslation(ras->getCenterD()));
Shinya Kitaoka 120a6e
    TRasterPT<pixel1> app = getImageFromStroke<pixel1, pixel2="">(ras, stroke);</pixel1,></pixel1>
Shinya Kitaoka 120a6e
    if (!app) continue;
Shinya Kitaoka 120a6e
    TRectD strokeRectD = stroke.getBBox();
Shinya Kitaoka 120a6e
    TRect strokeRect(tfloor(strokeRectD.x0), tfloor(strokeRectD.y0),
Shinya Kitaoka 120a6e
                     tceil(strokeRectD.x1) - 1, tceil(strokeRectD.y1) - 1);
Shinya Kitaoka 120a6e
    TPoint offset((strokeRect * rSelectionBound).getP00() -
Shinya Kitaoka 120a6e
                  rSelectionBound.getP00());
Shinya Kitaoka 120a6e
    TPoint startP = rSelectionBound.getP00() + offset;
Shinya Kitaoka 120a6e
    startPosition = TPoint(std::min(startPosition.x, startP.x),
Shinya Kitaoka 120a6e
                           std::min(startPosition.y, startP.y));
Shinya Kitaoka 120a6e
    TRop::over(selectedRaster, app, offset);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  selection.setStartPosition(startPosition);
Shinya Kitaoka 120a6e
  return selectedRaster;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRasterP getImageFromSelection(const TImageP &image,
Shinya Kitaoka 120a6e
                               RasterSelection &selection) {
Shinya Kitaoka 120a6e
  if (TToonzImageP toonzImage = (TToonzImageP)image) {
Shinya Kitaoka 120a6e
    TRasterPT<tpixelcm32> ras = toonzImage->getRaster();</tpixelcm32>
Shinya Kitaoka 120a6e
    return getImageFromSelection<tpixelcm32, tpixelcm32="">(ras, selection);</tpixelcm32,>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (TRasterImageP rasterImage = (TRasterImageP)image) {
Shinya Kitaoka 120a6e
    TRasterP ras = rasterImage->getRaster();
Shinya Kitaoka 120a6e
    if (TRaster32P ras32 = (TRaster32P)ras)
Shinya Kitaoka 120a6e
      return getImageFromSelection<tpixel32, tpixel32="">(ras32, selection);</tpixel32,>
Shinya Kitaoka 120a6e
    if (TRasterGR8P rasGR8 = (TRasterGR8P)ras)
Shinya Kitaoka 120a6e
      return getImageFromSelection<tpixel32, tpixelgr8="">(rasGR8, selection);</tpixel32,>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return (TRasterP)0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pixel=""></typename>
Shinya Kitaoka 120a6e
void deleteSelectionWithoutUndo(TRasterPT<pixel> &ras,</pixel>
Shinya Kitaoka 120a6e
                                const std::vector<tstroke> &strokes,</tstroke>
Shinya Kitaoka 120a6e
                                PIXEL emptyValue) {
Shinya Kitaoka 120a6e
  if (!ras) return;
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < strokes.size(); i++) {
Shinya Kitaoka 120a6e
    TStroke s = strokes[i];
Shinya Kitaoka 120a6e
    s.transform(TTranslation(ras->getCenterD()));
Shinya Kitaoka 120a6e
    TRectD strokeRectD = s.getBBox();
Shinya Kitaoka 120a6e
    // E' volutamente allargato di un pixel!
Shinya Kitaoka 120a6e
    TRect strokeRect(tfloor(strokeRectD.x0), tfloor(strokeRectD.y0),
Shinya Kitaoka 120a6e
                     tceil(strokeRectD.x1), tceil(strokeRectD.y1));
Shinya Kitaoka 120a6e
    if (!strokeRect.overlaps(ras->getBounds())) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Compute regions created by the std::vector
Shinya Kitaoka 120a6e
    TVectorImage app;
Shinya Kitaoka 120a6e
    app.addStroke(new TStroke(s));
Shinya Kitaoka 120a6e
    app.findRegions();
Shinya Kitaoka 120a6e
    int reg, j, k, y;
Shinya Kitaoka 120a6e
    ras->lock();
Shinya Kitaoka 120a6e
    TRect rasRect(ras->getBounds());
Shinya Kitaoka 120a6e
    for (reg = 0; reg < (int)app.getRegionCount(); reg++) {
Shinya Kitaoka 120a6e
      // For each region, pixels inside the region are erased!
Shinya Kitaoka 120a6e
      TRectD bBoxD = app.getRegion(reg)->getBBox();
Shinya Kitaoka 120a6e
      TRect bBox(tfloor(bBoxD.x0), tfloor(bBoxD.y0), tceil(bBoxD.x1) - 1,
Shinya Kitaoka 120a6e
                 tceil(bBoxD.y1) - 1);
Shinya Kitaoka 120a6e
      bBox *= rasRect;
Shinya Kitaoka 120a6e
      for (y = bBox.y0; y <= bBox.y1; y++) {
Shinya Kitaoka 120a6e
        PIXEL *selectedLine = ras->pixels(y);
Shinya Kitaoka 120a6e
        int startY          = y - strokeRect.y0;
Shinya Kitaoka 120a6e
        std::vector<double> intersections;</double>
Shinya Kitaoka 120a6e
        app.getRegion(reg)->computeScanlineIntersections(y, intersections);
Shinya Kitaoka 120a6e
        if (intersections.empty())
Shinya Kitaoka 120a6e
          app.getRegion(reg)->computeScanlineIntersections(y + 0.9,
Shinya Kitaoka 120a6e
                                                           intersections);
Shinya Kitaoka 120a6e
        for (j = 0; j < (int)intersections.size(); j += 2) {
Shinya Kitaoka 120a6e
          if (intersections[j] == intersections[j + 1]) continue;
Shinya Kitaoka 120a6e
          int from = std::max(tfloor(intersections[j]), bBox.x0);
Shinya Kitaoka 120a6e
          int to   = std::min(tceil(intersections[j + 1]), bBox.x1);
Shinya Kitaoka 120a6e
          for (k = from; k <= to; k++) *(selectedLine + k) = emptyValue;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    ras->unlock();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void deleteSelectionWithoutUndo(const TImageP &image,
Shinya Kitaoka 120a6e
                                const std::vector<tstroke> &strokes) {</tstroke>
Shinya Kitaoka 120a6e
  if (TToonzImageP toonzImage = (TToonzImageP)image) {
Shinya Kitaoka 120a6e
    TRasterPT<tpixelcm32> ras = toonzImage->getRaster();</tpixelcm32>
Shinya Kitaoka 120a6e
    deleteSelectionWithoutUndo<tpixelcm32>(ras, strokes, TPixelCM32());</tpixelcm32>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (TRasterImageP rasterImage = (TRasterImageP)image) {
Shinya Kitaoka 120a6e
    TRasterP ras = rasterImage->getRaster();
Shinya Kitaoka 120a6e
    if (TRaster32P ras32 = (TRaster32P)ras)
Shinya Kitaoka 120a6e
      deleteSelectionWithoutUndo<tpixel32>(ras32, strokes,</tpixel32>
Shinya Kitaoka 120a6e
                                           TPixel32::Transparent);
Shinya Kitaoka 120a6e
    if (TRasterGR8P rasGR8 = (TRasterGR8P)ras)
Shinya Kitaoka 120a6e
      deleteSelectionWithoutUndo<tpixelgr8>(rasGR8, strokes, TPixelGR8::White);</tpixelgr8>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void pasteFloatingSelectionWithoutUndo(const TImageP &image,
Shinya Kitaoka 120a6e
                                       const TRasterP &floatingSelection,
Shinya Kitaoka 120a6e
                                       const TAffine &transformation,
Shinya Kitaoka 120a6e
                                       const TRectD &wSelectionBound,
Shinya Kitaoka 120a6e
                                       bool noAntialiasing) {
Shinya Kitaoka 120a6e
  TRasterImageP ri = (TRasterImageP)image;
Shinya Kitaoka 120a6e
  TToonzImageP ti  = (TToonzImageP)image;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRasterP targetRaster = (ri) ? ri->getRaster() : (TRasterP)ti->getRaster();
Shinya Kitaoka 120a6e
  if (!targetRaster || !floatingSelection) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRect rSelectionBound = convertWorldToRaster(wSelectionBound, targetRaster);
Shinya Kitaoka 120a6e
  TRop::over(targetRaster, floatingSelection, rSelectionBound.getP00(),
Shinya Kitaoka 120a6e
             transformation,
Shinya Kitaoka 120a6e
             noAntialiasing ? TRop::ClosestPixel : TRop::Triangle);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// UndoDeleteSelection
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoDeleteSelection final : public TUndo {
Shinya Kitaoka 120a6e
  static int m_id;
Shinya Kitaoka 120a6e
  TXshSimpleLevelP m_level;
Shinya Kitaoka 120a6e
  TFrameId m_frameId;
Shinya Kitaoka 120a6e
  std::string m_erasedImageId;
Shinya Kitaoka 120a6e
  TPoint m_erasePoint;
Shinya Kitaoka 120a6e
  std::vector<tstroke> m_strokes;</tstroke>
Shinya Kitaoka 120a6e
  TTool *m_tool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoDeleteSelection(RasterSelection *selection, TXshSimpleLevel *level)
Shinya Kitaoka 120a6e
      : TUndo()
Shinya Kitaoka 120a6e
      , m_level(level)
Shinya Kitaoka 120a6e
      , m_frameId(selection->getFrameId())
Shinya Kitaoka 120a6e
      , m_strokes(selection->getOriginalStrokes()) {
Shinya Kitaoka 120a6e
    TImageP image   = m_level->getFrame(m_frameId, true);
Shinya Kitaoka 120a6e
    m_erasedImageId = "UndoDeleteSelection" + std::to_string(m_id++);
Shinya Kitaoka 120a6e
    TRasterP ras    = getRaster(image);
Shinya Kitaoka 120a6e
    TRasterP erasedRas;
Shinya Kitaoka 120a6e
    if (!selection->isFloating())
Shinya Kitaoka 120a6e
      erasedRas = TRasterP(getImageFromSelection(image, *selection));
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      erasedRas = TRasterP(selection->getOriginalFloatingSelection());
Shinya Kitaoka 120a6e
    TImageP erasedImage;
Shinya Kitaoka 120a6e
    if (TRasterCM32P toonzRas = (TRasterCM32P)(erasedRas))
Shinya Kitaoka 120a6e
      erasedImage = TToonzImageP(toonzRas, toonzRas->getBounds());
Shinya Kitaoka 120a6e
    else if (TRaster32P fullColorRas = (TRaster32P)(erasedRas))
Shinya Kitaoka 120a6e
      erasedImage = TRasterImageP(fullColorRas);
Shinya Kitaoka 120a6e
    TImageCache::instance()->add(m_erasedImageId, erasedImage, false);
Shinya Kitaoka 120a6e
    m_erasePoint = selection->getStartPosition();
Shinya Kitaoka 120a6e
    m_tool       = TTool::getApplication()->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~UndoDeleteSelection() {
Shinya Kitaoka 120a6e
    if (TImageCache::instance()->isCached(m_erasedImageId))
Shinya Kitaoka 120a6e
      TImageCache::instance()->remove(m_erasedImageId);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    TImageP image = m_level->getFrame(m_frameId, true);
Shinya Kitaoka 120a6e
    if (!image) return;
Shinya Kitaoka 120a6e
    TRasterP ras = getRaster(image);
Shinya Kitaoka 120a6e
    if (!ras) return;
Shinya Kitaoka 120a6e
    TImageP erasedImage = TImageCache::instance()->get(m_erasedImageId, false);
Shinya Kitaoka 120a6e
    if (!erasedImage) return;
Shinya Kitaoka 120a6e
    TRasterP erasedRaster = getRaster(erasedImage);
Shinya Kitaoka 120a6e
    TRop::over(ras, erasedRaster, m_erasePoint);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ToolUtils::updateSaveBox(m_level, m_frameId);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_tool) return;
Shinya Kitaoka 120a6e
    m_tool->notifyImageChanged(m_frameId);
Shinya Kitaoka 120a6e
    m_tool->invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    TImageP image       = m_level->getFrame(m_frameId, true);
Shinya Kitaoka 120a6e
    TImageP erasedImage = TImageCache::instance()->get(m_erasedImageId, false);
Shinya Kitaoka 120a6e
    if (!erasedImage) return;
Shinya Kitaoka 120a6e
    deleteSelectionWithoutUndo(image, m_strokes);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ToolUtils::updateSaveBox(m_level, m_frameId);
Shinya Kitaoka 120a6e
    if (!m_tool) return;
Shinya Kitaoka 120a6e
    m_tool->notifyImageChanged(m_frameId);
Shinya Kitaoka 120a6e
    m_tool->invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int UndoDeleteSelection::m_id = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// UndoPasteSelection
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoPasteSelection final : public TUndo {
Shinya Kitaoka 120a6e
  RasterSelection *m_currentSelection, m_newSelection;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoPasteSelection(RasterSelection *currentSelection)
Shinya Kitaoka 120a6e
      : TUndo()
Shinya Kitaoka 120a6e
      , m_currentSelection(currentSelection)
Shinya Kitaoka 120a6e
      , m_newSelection(*currentSelection) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~UndoPasteSelection() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    m_currentSelection->setFloatingSeletion(TRasterP());
Shinya Kitaoka 120a6e
    m_currentSelection->selectNone();
Shinya Kitaoka 120a6e
    m_currentSelection->notify();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    *m_currentSelection = m_newSelection;
Shinya Kitaoka 120a6e
    m_currentSelection->notify();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getHistoryString() override { return QObject::tr("Paste"); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// UndoPasteFloatingSelection
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class UndoPasteFloatingSelection final : public TUndo {
Shinya Kitaoka 120a6e
  static int m_id;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TXshCell m_imageCell;  //!< Level/frame pair to the pasted-to image
Shinya Kitaoka 120a6e
                         //!< (seemingly cached as m_imageId)
Shinya Kitaoka 120a6e
  TPaletteP m_oldPalette, m_newPalette;
Shinya Kitaoka 120a6e
  std::string m_imageId, m_floatingImageId, m_undoImageId, m_oldFloatingImageId;
Shinya Kitaoka 120a6e
  std::vector<tstroke> m_strokes;</tstroke>
Shinya Kitaoka 120a6e
  TRectD m_selectionRect;
Shinya Kitaoka 120a6e
  TAffine m_transformation;
Shinya Kitaoka 120a6e
  TPoint m_startPos;
Shinya Kitaoka 120a6e
  bool m_isPastedSelection;
Shinya Kitaoka 120a6e
  bool m_noAntialiasing;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TTool *m_tool;
Shinya Kitaoka 120a6e
  TFrameId m_frameId;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  UndoPasteFloatingSelection(RasterSelection *currentSelection,
Shinya Kitaoka 120a6e
                             TPalette *oldPalette, bool noAntialiasing)
Shinya Kitaoka 120a6e
      : TUndo()
Shinya Kitaoka 120a6e
      , m_imageCell(currentSelection->getCurrentImageCell())
Shinya Kitaoka 120a6e
      , m_oldPalette(oldPalette ? oldPalette->clone() : 0)
Shinya Kitaoka 120a6e
      , m_strokes(currentSelection->getOriginalStrokes())
Shinya Kitaoka 120a6e
      , m_selectionRect(currentSelection->getSelectionBbox())
Shinya Kitaoka 120a6e
      , m_transformation(currentSelection->getTransformation())
Shinya Kitaoka 120a6e
      , m_isPastedSelection(currentSelection->isPastedSelection())
Shinya Kitaoka 120a6e
      , m_noAntialiasing(noAntialiasing)
Shinya Kitaoka 120a6e
      , m_undoImageId("")
Shinya Kitaoka 120a6e
      , m_frameId(currentSelection->getFrameId()) {
Shinya Kitaoka 120a6e
    TImageP image(currentSelection->getCurrentImage());
Shinya Kitaoka 120a6e
    if (!image) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_imageId = "UndoPasteImage_" + std::to_string(m_id);
Shinya Kitaoka 120a6e
    TImageCache::instance()->add(m_imageId, image, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_floatingImageId =
Shinya Kitaoka 120a6e
        "UndoPasteFloatingSelection_floating_" + std::to_string(m_id);
Shinya Kitaoka 120a6e
    TRasterP floatingRas = currentSelection->getFloatingSelection();
Shinya Kitaoka 120a6e
    TImageP floatingImage;
Shinya Kitaoka 120a6e
    if (TRasterCM32P toonzRas = (TRasterCM32P)(floatingRas))
Shinya Kitaoka 120a6e
      floatingImage = TToonzImageP(toonzRas, toonzRas->getBounds());
Shinya Kitaoka 120a6e
    else if (TRaster32P fullColorRas = (TRaster32P)(floatingRas))
Shinya Kitaoka 120a6e
      floatingImage = TRasterImageP(fullColorRas);
Shinya Kitaoka 120a6e
    else if (TRasterGR8P grRas = (TRasterGR8P)(floatingRas))
Shinya Kitaoka 120a6e
      floatingImage = TRasterImageP(grRas);
Shinya Kitaoka 120a6e
    TImageCache::instance()->add(m_floatingImageId, floatingImage, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_oldFloatingImageId =
Shinya Kitaoka 120a6e
        "UndoPasteFloatingSelection_oldFloating_" + std::to_string(m_id);
Shinya Kitaoka 120a6e
    TRasterP oldFloatingRas = currentSelection->getOriginalFloatingSelection();
Shinya Kitaoka 120a6e
    TImageP olfFloatingImage;
Shinya Kitaoka 120a6e
    if (TRasterCM32P toonzRas = (TRasterCM32P)(oldFloatingRas))
Shinya Kitaoka 120a6e
      olfFloatingImage = TToonzImageP(toonzRas, toonzRas->getBounds());
Shinya Kitaoka 120a6e
    else if (TRaster32P fullColorRas = (TRaster32P)(oldFloatingRas))
Shinya Kitaoka 120a6e
      olfFloatingImage = TRasterImageP(fullColorRas);
Shinya Kitaoka 120a6e
    else if (TRasterGR8P grRas = (TRasterGR8P)(oldFloatingRas))
Shinya Kitaoka 120a6e
      olfFloatingImage = TRasterImageP(grRas);
Shinya Kitaoka 120a6e
    TImageCache::instance()->add(m_oldFloatingImageId, olfFloatingImage, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPaletteP imgPalette = image->getPalette();
Shinya Kitaoka 120a6e
    m_newPalette         = imgPalette ? imgPalette->clone() : 0;
Shinya Kitaoka 120a6e
    TRasterP rasImage    = getRaster(image);
Shinya Kitaoka 120a6e
    TRectD wRect         = m_selectionRect.enlarge(2);
Shinya Kitaoka 120a6e
    TRect rRect          = convertWorldToRaster(wRect, image);
Shinya Kitaoka 120a6e
    rRect *= rasImage->getBounds();
Shinya Kitaoka 120a6e
    if (!rRect.isEmpty()) {
Shinya Kitaoka 120a6e
      m_undoImageId = "UndoPasteFloatingSelection_undo" + std::to_string(m_id);
Shinya Kitaoka 120a6e
      TRasterP undoRas = rasImage->extract(rRect)->clone();
Shinya Kitaoka 120a6e
      TImageP undoImage;
Shinya Kitaoka 120a6e
      if (TRasterCM32P toonzRas = (TRasterCM32P)(undoRas))
Shinya Kitaoka 120a6e
        undoImage = TToonzImageP(toonzRas, toonzRas->getBounds());
Shinya Kitaoka 120a6e
      else if (TRaster32P fullColorRas = (TRaster32P)(undoRas))
Shinya Kitaoka 120a6e
        undoImage = TRasterImageP(fullColorRas);
Shinya Kitaoka 120a6e
      else if (TRasterGR8P grRas = (TRasterGR8P)(undoRas))
Shinya Kitaoka 120a6e
        undoImage = TRasterImageP(grRas);
Shinya Kitaoka 120a6e
      TImageCache::instance()->add(m_undoImageId, undoImage, false);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_startPos = currentSelection->getStartPosition();
Shinya Kitaoka 120a6e
    m_id++;
Shinya Kitaoka 120a6e
    m_tool = TTool::getApplication()->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ~UndoPasteFloatingSelection() {
Shinya Kitaoka 120a6e
    if (TImageCache::instance()->isCached(m_imageId))
Shinya Kitaoka 120a6e
      TImageCache::instance()->remove(m_imageId);
Shinya Kitaoka 120a6e
    if (TImageCache::instance()->isCached(m_floatingImageId))
Shinya Kitaoka 120a6e
      TImageCache::instance()->remove(m_floatingImageId);
Shinya Kitaoka 120a6e
    if (TImageCache::instance()->isCached(m_undoImageId))
Shinya Kitaoka 120a6e
      TImageCache::instance()->remove(m_undoImageId);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    TImageP image = TImageCache::instance()->get(m_imageId, false);
Shinya Kitaoka 120a6e
    if (!image) return;
Shinya Kitaoka 120a6e
    TRasterP rasImage = getRaster(image);
Shinya Kitaoka 120a6e
    TRectD wRect      = m_selectionRect.enlarge(2);
Shinya Kitaoka 120a6e
    TRect rRect       = convertWorldToRaster(wRect, image);
Shinya Kitaoka 120a6e
    rRect *= rasImage->getBounds();
Shinya Kitaoka 120a6e
    if (!m_undoImageId.empty()) {
Shinya Kitaoka 120a6e
      TImageP undoImage = TImageCache::instance()->get(m_undoImageId, false);
Shinya Kitaoka 120a6e
      if (!undoImage) return;
Shinya Kitaoka 120a6e
      rasImage->copy(getRaster(undoImage), rRect.getP00());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TXshSimpleLevelP sl(m_imageCell.getSimpleLevel());
Shinya Kitaoka 120a6e
    const TFrameId &fid = m_imageCell.m_frameId;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_isPastedSelection) {
Shinya Kitaoka 120a6e
      TImageP floatingImage =
Shinya Kitaoka 120a6e
          TImageCache::instance()->get(m_oldFloatingImageId, false);
Shinya Kitaoka 120a6e
      if (!floatingImage) return;
Shinya Kitaoka 120a6e
      TRasterP floatingRaster = getRaster(floatingImage);
Shinya Kitaoka 120a6e
      TRop::over(rasImage, floatingRaster, m_startPos);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ToolUtils::updateSaveBox(sl, fid);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_oldPalette) image->getPalette()->assign(m_oldPalette->clone());
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    app->getPaletteController()
Shinya Kitaoka 120a6e
        ->getCurrentLevelPalette()
Shinya Kitaoka 120a6e
        ->notifyPaletteChanged();
Shinya Kitaoka 120a6e
    if (!m_tool) return;
Shinya Kitaoka 120a6e
    m_tool->notifyImageChanged(m_frameId);
Shinya Kitaoka 120a6e
    m_tool->invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    TImageP image = TImageCache::instance()->get(m_imageId, false);
Shinya Kitaoka 120a6e
    TImageP floatingImage =
Shinya Kitaoka 120a6e
        TImageCache::instance()->get(m_floatingImageId, false);
Shinya Kitaoka 120a6e
    if (!floatingImage || !image) return;
Shinya Kitaoka 120a6e
    TRasterP floatingRas = getRaster(floatingImage);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TXshSimpleLevelP sl(m_imageCell.getSimpleLevel());
Shinya Kitaoka 120a6e
    const TFrameId &fid = m_imageCell.m_frameId;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!m_isPastedSelection) deleteSelectionWithoutUndo(image, m_strokes);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TRasterP ras = getRaster(image);
Shinya Kitaoka 120a6e
    pasteFloatingSelectionWithoutUndo(image, floatingRas, m_transformation,
Shinya Kitaoka 120a6e
                                      m_selectionRect, m_noAntialiasing);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    ToolUtils::updateSaveBox(sl, fid);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_newPalette) image->getPalette()->assign(m_newPalette->clone());
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    app->getPaletteController()
Shinya Kitaoka 120a6e
        ->getCurrentLevelPalette()
Shinya Kitaoka 120a6e
        ->notifyPaletteChanged();
Shinya Kitaoka 120a6e
    if (!m_tool) return;
Shinya Kitaoka 120a6e
    m_tool->notifyImageChanged(m_frameId);
Shinya Kitaoka 120a6e
    m_tool->invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  QString getHistoryString() override { return QObject::tr("Paste"); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int UndoPasteFloatingSelection::m_id = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Shinya Kitaoka 120a6e
// Next methods are used to compute intersection between selected stroke and
Shinya Kitaoka 120a6e
// image box
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Help function.*/
Shinya Kitaoka 120a6e
TSegment getSegmentByIndex(TRectD rect, int index) {
Shinya Kitaoka 120a6e
  if (index == 0) return TSegment(rect.getP00(), rect.getP01());
Shinya Kitaoka 120a6e
  if (index == 1) return TSegment(rect.getP01(), rect.getP11());
Shinya Kitaoka 120a6e
  if (index == 2) return TSegment(rect.getP11(), rect.getP10());
Shinya Kitaoka 120a6e
  if (index == 3) return TSegment(rect.getP10(), rect.getP00());
Shinya Kitaoka 120a6e
  return TSegment();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Help function. precPoint -> point */
Shinya Kitaoka 120a6e
bool isClockwise(TRectD bbox, int segmentIndex, TThickPoint precPoint,
Shinya Kitaoka 120a6e
                 TThickPoint point) {
Shinya Kitaoka 120a6e
  if (segmentIndex == 0) return precPoint.y > point.y;
Shinya Kitaoka 120a6e
  if (segmentIndex == 1) return precPoint.x > point.x;
Shinya Kitaoka 120a6e
  if (segmentIndex == 2) return precPoint.y < point.y;
Shinya Kitaoka 120a6e
  if (segmentIndex == 3) return precPoint.x < point.x;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Help function.*/
Shinya Kitaoka 120a6e
void addPointToVector(TThickPoint point, std::vector<tthickpoint> &points,</tthickpoint>
Shinya Kitaoka 120a6e
                      bool insertMiddlePoint) {
Shinya Kitaoka 120a6e
  if (insertMiddlePoint)
Shinya Kitaoka 120a6e
    points.push_back((points[points.size() - 1] + point) * 0.5);
Shinya Kitaoka 120a6e
  points.push_back(point);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Return intersection between \b bbox and \b chuck;
Toshihiro Shimizu 890ddd
    set segmentIndex to index of segment that contains intersection. */
Toshihiro Shimizu 890ddd
TThickPoint getIntersectionPoint(TRectD bbox, const TThickQuadratic *chunk,
Shinya Kitaoka 120a6e
                                 int &segmentIndex,
Shinya Kitaoka 120a6e
                                 bool secondChunkIntersection) {
Shinya Kitaoka 120a6e
  TStroke stroke;
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
  points.push_back(chunk->getThickP0());
Shinya Kitaoka 120a6e
  points.push_back(chunk->getThickP1());
Shinya Kitaoka 120a6e
  points.push_back(chunk->getThickP2());
Shinya Kitaoka 120a6e
  stroke.reshape(&points[0], points.size());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<doublepair> intersectionInfo;</doublepair>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<doublepair> intersections;</doublepair>
Shinya Kitaoka 120a6e
  TSegment segment0(bbox.getP00(), bbox.getP01());
Shinya Kitaoka 120a6e
  int count0 = intersect(stroke, segment0, intersections);
Shinya Kitaoka 120a6e
  if (count0 > 0) {
Shinya Kitaoka 120a6e
    DoublePair pair;
Shinya Kitaoka 120a6e
    pair.first  = intersections[0].first;
Shinya Kitaoka 120a6e
    pair.second = 0;
Shinya Kitaoka 120a6e
    intersectionInfo.push_back(pair);
Shinya Kitaoka 120a6e
    intersections.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TSegment segment1(bbox.getP01(), bbox.getP11());
Shinya Kitaoka 120a6e
  int count1 = intersect(stroke, segment1, intersections);
Shinya Kitaoka 120a6e
  if (count1 > 0) {
Shinya Kitaoka 120a6e
    DoublePair pair;
Shinya Kitaoka 120a6e
    pair.first  = intersections[0].first;
Shinya Kitaoka 120a6e
    pair.second = 1;
Shinya Kitaoka 120a6e
    intersectionInfo.push_back(pair);
Shinya Kitaoka 120a6e
    intersections.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TSegment segment2(bbox.getP11(), bbox.getP10());
Shinya Kitaoka 120a6e
  int count2 = intersect(stroke, segment2, intersections);
Shinya Kitaoka 120a6e
  if (count2 > 0) {
Shinya Kitaoka 120a6e
    DoublePair pair;
Shinya Kitaoka 120a6e
    pair.first  = intersections[0].first;
Shinya Kitaoka 120a6e
    pair.second = 2;
Shinya Kitaoka 120a6e
    intersectionInfo.push_back(pair);
Shinya Kitaoka 120a6e
    intersections.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TSegment segment3(bbox.getP10(), bbox.getP00());
Shinya Kitaoka 120a6e
  int count3 = intersect(stroke, segment3, intersections);
Shinya Kitaoka 120a6e
  if (count3 > 0) {
Shinya Kitaoka 120a6e
    DoublePair pair;
Shinya Kitaoka 120a6e
    pair.first  = intersections[0].first;
Shinya Kitaoka 120a6e
    pair.second = 3;
Shinya Kitaoka 120a6e
    intersectionInfo.push_back(pair);
Shinya Kitaoka 120a6e
    intersections.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int infoSize = intersectionInfo.size();
Shinya Kitaoka 120a6e
  assert(infoSize <= 2);
Shinya Kitaoka 120a6e
  if (infoSize == 1) {
Shinya Kitaoka 120a6e
    segmentIndex = intersectionInfo[0].second;
Shinya Kitaoka 120a6e
    return stroke.getPoint(intersectionInfo[0].first);
Shinya Kitaoka 120a6e
  } else if (infoSize == 2) {
Shinya Kitaoka 120a6e
    double firstT  = intersectionInfo[0].first;
Shinya Kitaoka 120a6e
    double secondT = intersectionInfo[1].first;
Shinya Kitaoka 120a6e
    if (!secondChunkIntersection) {
Shinya Kitaoka 120a6e
      if (firstT < secondT) {
Shinya Kitaoka 120a6e
        segmentIndex = intersectionInfo[0].second;
Shinya Kitaoka 120a6e
        return stroke.getPoint(intersectionInfo[0].first);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        segmentIndex = intersectionInfo[1].second;
Shinya Kitaoka 120a6e
        return stroke.getPoint(intersectionInfo[1].first);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (firstT > secondT) {
Shinya Kitaoka 120a6e
        segmentIndex = intersectionInfo[0].second;
Shinya Kitaoka 120a6e
        return stroke.getPoint(intersectionInfo[0].first);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        segmentIndex = intersectionInfo[1].second;
Shinya Kitaoka 120a6e
        return stroke.getPoint(intersectionInfo[1].first);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  segmentIndex = -1;
Shinya Kitaoka 120a6e
  return TThickPoint();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
/*! Insert \b bbox corners in \b points if \b bbox corners are contained in \b
Shinya Kitaoka 120a6e
 * outPoints stroke. */
Shinya Kitaoka 120a6e
void insertBoxCorners(TRectD bbox, std::vector<tthickpoint> &points,</tthickpoint>
Shinya Kitaoka 120a6e
                      std::vector<tthickpoint> outPoints,</tthickpoint>
Shinya Kitaoka 120a6e
                      int currentSegmentIndex, int precSegmentIndex) {
Shinya Kitaoka 120a6e
  if (outPoints[0] != outPoints[(int)outPoints.size() - 1])
Shinya Kitaoka 120a6e
    addPointToVector(outPoints[0], outPoints, true);
Shinya Kitaoka 120a6e
  assert((int)outPoints.size() % 2 == 1);
Shinya Kitaoka 120a6e
  TStroke *outPointsStroke = new TStroke();
Shinya Kitaoka 120a6e
  outPointsStroke->reshape(&(outPoints[0]), outPoints.size());
Shinya Kitaoka 120a6e
  TVectorImageP vi(new TVectorImage());
Shinya Kitaoka 120a6e
  vi->addStroke(outPointsStroke);
Shinya Kitaoka 120a6e
  vi->findRegions();
Shinya Kitaoka 120a6e
  assert((int)vi->getRegionCount() > 0);
Shinya Kitaoka 120a6e
  bool sameIndex = (precSegmentIndex == currentSegmentIndex);
Shinya Kitaoka 120a6e
  if (currentSegmentIndex == -1) return;
Shinya Kitaoka 120a6e
  int j;
Shinya Kitaoka 120a6e
  for (j = sameIndex ? 1 : 0; j < 2; j++) {
Shinya Kitaoka 120a6e
    bool clockwise = j;
Shinya Kitaoka 120a6e
    if (sameIndex)
Shinya Kitaoka 120a6e
      clockwise = isClockwise(bbox, currentSegmentIndex,
Shinya Kitaoka 120a6e
                              outPoints[outPoints.size() - 2],
Shinya Kitaoka 120a6e
                              outPoints[outPoints.size() - 1]);
Shinya Kitaoka 120a6e
    int segmentIndex = precSegmentIndex;
Shinya Kitaoka 120a6e
    if (sameIndex)
Shinya Kitaoka 120a6e
      segmentIndex =
Shinya Kitaoka 120a6e
          clockwise ? currentSegmentIndex - 1 : currentSegmentIndex + 1;
Shinya Kitaoka 120a6e
    if (segmentIndex < 0) segmentIndex = 3;
Shinya Kitaoka 120a6e
    if (segmentIndex > 3) segmentIndex = 0;
Shinya Kitaoka 120a6e
    while (segmentIndex != currentSegmentIndex) {
Shinya Kitaoka 120a6e
      if (sameIndex)  // controllo anche il segmento di partenza.
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        segmentIndex = currentSegmentIndex;
Shinya Kitaoka 120a6e
        sameIndex    = false;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      TSegment s         = getSegmentByIndex(bbox, segmentIndex);
Shinya Kitaoka 120a6e
      TThickPoint corner = clockwise ? s.getP0() : s.getP1();
Shinya Kitaoka 120a6e
      int i;
Shinya Kitaoka 120a6e
      for (i = 0; i < (int)vi->getRegionCount(); i++)
Shinya Kitaoka 120a6e
        if (vi->getRegion(i)->contains(corner)) {
Shinya Kitaoka 120a6e
          if ((int)points.size() % 2 == 1)
Shinya Kitaoka 120a6e
            points.push_back((points[points.size() - 1] + corner) * 0.5);
Shinya Kitaoka 120a6e
          points.push_back(corner);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      segmentIndex = clockwise ? segmentIndex - 1 : segmentIndex + 1;
Shinya Kitaoka 120a6e
      if (segmentIndex < 0) segmentIndex = 3;
Shinya Kitaoka 120a6e
      if (segmentIndex > 3) segmentIndex = 0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke getStrokeByRect(TRectD r) {
Shinya Kitaoka 120a6e
  TStroke stroke;
Shinya Kitaoka 120a6e
  if (r.isEmpty()) return stroke;
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points;</tthickpoint>
Shinya Kitaoka 120a6e
  points.push_back(r.getP00());
Shinya Kitaoka 120a6e
  points.push_back((r.getP00() + r.getP01()) * 0.5);
Shinya Kitaoka 120a6e
  points.push_back(r.getP01());
Shinya Kitaoka 120a6e
  points.push_back((r.getP01() + r.getP11()) * 0.5);
Shinya Kitaoka 120a6e
  points.push_back(r.getP11());
Shinya Kitaoka 120a6e
  points.push_back((r.getP11() + r.getP10()) * 0.5);
Shinya Kitaoka 120a6e
  points.push_back(r.getP10());
Shinya Kitaoka 120a6e
  points.push_back((r.getP10() + r.getP00()) * 0.5);
Shinya Kitaoka 120a6e
  points.push_back(r.getP00());
Shinya Kitaoka 120a6e
  stroke.reshape(&(points[0]), points.size());
Shinya Kitaoka 120a6e
  stroke.setSelfLoop(true);
Shinya Kitaoka 120a6e
  return stroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke getIntersectedStroke(TStroke &stroke, TRectD bbox) {
Shinya Kitaoka 120a6e
  int cpCount = stroke.getControlPointCount();
Shinya Kitaoka 120a6e
  if (cpCount == 0) return stroke;
Shinya Kitaoka 120a6e
  // isFirstTime, startSegmentIndex e startOutPoints sono usati nel il caso in
Shinya Kitaoka 120a6e
  // cui lo stroke inizia fuori dalla bbox.
Shinya Kitaoka 120a6e
  bool isFirstTime = true;
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points, outPoints, startOutPoints;</tthickpoint>
Shinya Kitaoka 120a6e
  TThickPoint precPoint    = stroke.getControlPoint(0);
Shinya Kitaoka 120a6e
  bool isPrecPointInternal = bbox.contains(precPoint);
Shinya Kitaoka 120a6e
  if (isPrecPointInternal)
Shinya Kitaoka 120a6e
    points.push_back(precPoint);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    outPoints.push_back(precPoint);
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  int precSegmentIndex, currentSegmentIndex, startSegmentIndex,
Shinya Kitaoka 120a6e
      precChunkIndex = -1;
Shinya Kitaoka 120a6e
  for (i = 1; i < stroke.getControlPointCount(); i++) {
Shinya Kitaoka 120a6e
    TThickPoint point    = stroke.getControlPoint(i);
Shinya Kitaoka 120a6e
    bool isPointInternal = bbox.contains(point);
Shinya Kitaoka 120a6e
    if (isPointInternal && isPrecPointInternal)
Shinya Kitaoka 120a6e
      addPointToVector(point, points, (int)points.size() % 2 != i % 2);
Shinya Kitaoka 120a6e
    if (!isPointInternal && !isPrecPointInternal)
Shinya Kitaoka 120a6e
      addPointToVector(
Shinya Kitaoka 120a6e
          point, outPoints,
Shinya Kitaoka 120a6e
          (int)outPoints.size() > 0 && (int)outPoints.size() % 2 != i % 2);
Shinya Kitaoka 120a6e
    if (isPointInternal != isPrecPointInternal) {
Shinya Kitaoka 120a6e
      // Devo trovare l'intersezione
Shinya Kitaoka 120a6e
      int chunkIndex = (i % 2 == 0) ? (i * 0.5) - 1 : i * 0.5;
Shinya Kitaoka 120a6e
      TThickPoint p  = getIntersectionPoint(bbox, stroke.getChunk(chunkIndex),
Shinya Kitaoka 120a6e
                                           currentSegmentIndex,
Shinya Kitaoka 120a6e
                                           chunkIndex == precChunkIndex);
Shinya Kitaoka 120a6e
      precChunkIndex = chunkIndex;
Shinya Kitaoka 120a6e
      addPointToVector(p, outPoints, (int)outPoints.size() % 2 == 1);
Shinya Kitaoka 120a6e
      if (!isPrecPointInternal && points.size() > 0 && outPoints.size() > 0) {
Shinya Kitaoka 120a6e
        insertBoxCorners(bbox, points, outPoints, currentSegmentIndex,
Shinya Kitaoka 120a6e
                         precSegmentIndex);
Shinya Kitaoka 120a6e
        outPoints.clear();
Shinya Kitaoka 120a6e
      } else if (outPoints.size() > 0 && isFirstTime) {
Shinya Kitaoka 120a6e
        startSegmentIndex = currentSegmentIndex;
Shinya Kitaoka 120a6e
        startOutPoints    = outPoints;
Shinya Kitaoka 120a6e
        outPoints.clear();
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      isFirstTime      = false;
Shinya Kitaoka 120a6e
      precSegmentIndex = currentSegmentIndex;
Shinya Kitaoka 120a6e
      addPointToVector(p, points, (int)points.size() % 2 == 1);
Shinya Kitaoka 120a6e
      addPointToVector(p, outPoints, (int)outPoints.size() % 2 == 1);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (isPointInternal && !isPrecPointInternal)
Shinya Kitaoka 120a6e
      addPointToVector(point, points, (int)points.size() % 2 != i % 2);
Shinya Kitaoka 120a6e
    if (!isPointInternal && isPrecPointInternal)
Shinya Kitaoka 120a6e
      addPointToVector(
Shinya Kitaoka 120a6e
          point, outPoints,
Shinya Kitaoka 120a6e
          (int)outPoints.size() > 0 && (int)outPoints.size() % 2 != i % 2);
Shinya Kitaoka 120a6e
    isPrecPointInternal = isPointInternal;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // Caso in cui lo stroke aveva il primo punto fuori dalla bbox
Shinya Kitaoka 120a6e
  if (!isPrecPointInternal && points.size() > 0 && outPoints.size() > 0) {
Shinya Kitaoka 120a6e
    int t;
Shinya Kitaoka 120a6e
    for (t = 0; t < (int)outPoints.size(); t++)
Shinya Kitaoka 120a6e
      addPointToVector(outPoints[t], startOutPoints,
Shinya Kitaoka 120a6e
                       (int)startOutPoints.size() % 2 != 2);
Shinya Kitaoka 120a6e
    insertBoxCorners(bbox, points, startOutPoints, startSegmentIndex,
Shinya Kitaoka 120a6e
                     currentSegmentIndex);
Shinya Kitaoka 120a6e
    outPoints.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Caso particolare in cui lo stroke non ha intersezione con la bbox
Shinya Kitaoka 120a6e
  if (points.size() == 0) {  // Lo stroke e' completamente contenuto nella bbox
Shinya Kitaoka 120a6e
    if (bbox.contains(precPoint))
Shinya Kitaoka 120a6e
      return stroke;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return getStrokeByRect(bbox);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (points[0] != points[(int)points.size() - 1])
Shinya Kitaoka 120a6e
    addPointToVector(points[0], points, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert((int)points.size() % 2 == 1);
Shinya Kitaoka 120a6e
  TStroke intersectedStroke;
Shinya Kitaoka 120a6e
  intersectedStroke.reshape(&(points[0]), points.size());
Shinya Kitaoka 120a6e
  intersectedStroke.setSelfLoop(true);
Shinya Kitaoka 120a6e
  return intersectedStroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// RasterSelection
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
RasterSelection::RasterSelection()
Shinya Kitaoka 120a6e
    : TSelection()
Shinya Kitaoka 120a6e
    , m_currentImage()
Shinya Kitaoka 120a6e
    , m_oldPalette(0)
Shinya Kitaoka 120a6e
    , m_selectionBbox()
Shinya Kitaoka 120a6e
    , m_affine()
Shinya Kitaoka 120a6e
    , m_startPosition()
Shinya Kitaoka 120a6e
    , m_floatingSelection()
Shinya Kitaoka 120a6e
    , m_originalfloatingSelection()
Shinya Kitaoka 120a6e
    , m_fid()
Shinya Kitaoka 120a6e
    , m_transformationCount(0)
Shinya Kitaoka 120a6e
    , m_isPastedSelection(false)
Shinya Kitaoka 120a6e
    , m_noAntialiasing(false) {
Shinya Kitaoka 120a6e
  m_strokes.clear();
Shinya Kitaoka 120a6e
  m_originalStrokes.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
RasterSelection::RasterSelection(const RasterSelection &src)
Shinya Kitaoka 120a6e
    : TSelection()
Shinya Kitaoka 120a6e
    , m_currentImage(src.m_currentImage)
Shinya Kitaoka 120a6e
    , m_oldPalette(src.m_oldPalette)
Shinya Kitaoka 120a6e
    , m_selectionBbox(src.m_selectionBbox)
Shinya Kitaoka 120a6e
    , m_strokes(src.m_strokes)
Shinya Kitaoka 120a6e
    , m_originalStrokes(src.m_originalStrokes)
Shinya Kitaoka 120a6e
    , m_affine(src.m_affine)
Shinya Kitaoka 120a6e
    , m_startPosition(src.m_startPosition)
Shinya Kitaoka 120a6e
    , m_fid(src.m_fid)
Shinya Kitaoka 120a6e
    , m_transformationCount(src.m_transformationCount)
Shinya Kitaoka 120a6e
    , m_isPastedSelection(src.m_isPastedSelection)
Shinya Kitaoka 120a6e
    , m_noAntialiasing(src.m_noAntialiasing)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  setView(src.getView());
Shinya Kitaoka 120a6e
  if (src.isFloating()) {
Shinya Kitaoka 120a6e
    m_floatingSelection = src.m_floatingSelection->clone();
Shinya Kitaoka 120a6e
    if (src.m_originalfloatingSelection)
Shinya Kitaoka 120a6e
      m_originalfloatingSelection = src.m_originalfloatingSelection->clone();
Shinya Kitaoka 120a6e
    assert(isFloating());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Returns the clone of this selection
Shinya Kitaoka 120a6e
TSelection *RasterSelection::clone() const {
Shinya Kitaoka 120a6e
  RasterSelection *rs = new RasterSelection(*this);
Shinya Kitaoka 120a6e
  return rs;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Notify to the viewer that the selection is changed.
Shinya Kitaoka 120a6e
void RasterSelection::notify() {
Shinya Kitaoka 120a6e
  RasterSelection *selection = dynamic_cast<rasterselection *="">(</rasterselection>
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentSelection()->getSelection());
Shinya Kitaoka 120a6e
  if (selection) selection->notifyView();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Empty the selection.
Shinya Kitaoka 120a6e
//! If the selection is floating, the floating image is pasted using the current
Shinya Kitaoka 120a6e
//! tranformation.
Shinya Kitaoka 120a6e
void RasterSelection::selectNone() {
Shinya Kitaoka 120a6e
  if (isFloating()) {
Shinya Kitaoka 120a6e
    pasteFloatingSelection();
Shinya Kitaoka 120a6e
    notify();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_selectionBbox = TRectD();
Shinya Kitaoka 120a6e
  m_strokes.clear();
Shinya Kitaoka 120a6e
  m_originalStrokes.clear();
Shinya Kitaoka 120a6e
  m_affine                    = TAffine();
Shinya Kitaoka 120a6e
  m_startPosition             = TPoint();
Shinya Kitaoka 120a6e
  m_floatingSelection         = TRasterP();
Shinya Kitaoka 120a6e
  m_originalfloatingSelection = TRasterP();
Shinya Kitaoka 120a6e
  m_transformationCount       = 0;
Shinya Kitaoka 120a6e
  m_isPastedSelection         = false;
Shinya Kitaoka 120a6e
  m_oldPalette                = 0;
Shinya Kitaoka 120a6e
  notify();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::select(TStroke &stroke) {
Shinya Kitaoka 120a6e
  TRect box                 = getRaster(m_currentImage)->getBounds();
Shinya Kitaoka 120a6e
  TRectD rasterBbox         = convertRasterToWorld(box, m_currentImage);
Shinya Kitaoka 120a6e
  TStroke intersectedStroke = getIntersectedStroke(stroke, rasterBbox);
Shinya Kitaoka 120a6e
  if ((int)intersectedStroke.getControlPointCount() == 0) return;
Shinya Kitaoka 120a6e
  m_strokes.push_back(intersectedStroke);
Shinya Kitaoka 120a6e
  m_originalStrokes.push_back(intersectedStroke);
Shinya Kitaoka 120a6e
  notify();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::select(const TRectD &rect) {
Shinya Kitaoka 120a6e
  assert(!!m_currentImage);
Shinya Kitaoka 120a6e
  TRectD r  = rect;
Shinya Kitaoka 120a6e
  TRect box = getRaster(m_currentImage)->getBounds();
Shinya Kitaoka 120a6e
  r *= convertRasterToWorld(box, m_currentImage);
Shinya Kitaoka 120a6e
  if (!r.isEmpty()) {
Shinya Kitaoka 120a6e
    TStroke stroke = getStrokeByRect(r);
Shinya Kitaoka 120a6e
    if ((int)stroke.getControlPointCount() == 0) return;
Shinya Kitaoka 120a6e
    m_strokes.push_back(stroke);
Shinya Kitaoka 120a6e
    m_originalStrokes.push_back(stroke);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  notify();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::selectAll() {
Shinya Kitaoka 120a6e
  if (!m_currentImage) return;
Shinya Kitaoka 120a6e
  selectNone();
Shinya Kitaoka 120a6e
  TRectD wRect = convertRasterToWorld(getRaster(m_currentImage)->getBounds(),
Shinya Kitaoka 120a6e
                                      m_currentImage);
Shinya Kitaoka 120a6e
  select(wRect);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool RasterSelection::isEmpty() const {
Shinya Kitaoka 120a6e
  return getStrokesBound(m_strokes).isEmpty();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::enableCommands() {
Shinya Kitaoka 120a6e
  enableCommand(this, MI_Clear, &RasterSelection::deleteSelection);
Shinya Kitaoka 120a6e
  enableCommand(this, MI_Cut, &RasterSelection::cutSelection);
Shinya Kitaoka 120a6e
  enableCommand(this, MI_Copy, &RasterSelection::copySelection);
Shinya Kitaoka 120a6e
  enableCommand(this, MI_Paste, &RasterSelection::pasteSelection);
Shinya Kitaoka 120a6e
  enableCommand(this, MI_SelectAll, &RasterSelection::selectAll);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool RasterSelection::isFloating() const { return m_floatingSelection; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::transform(const TAffine &affine) {
Shinya Kitaoka 120a6e
  m_affine = affine * m_affine;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::makeFloating() {
Shinya Kitaoka 120a6e
  if (isEmpty()) return;
Shinya Kitaoka 120a6e
  if (!m_currentImage) return;
Shinya Kitaoka 120a6e
  m_floatingSelection         = getImageFromSelection(m_currentImage, *this);
Shinya Kitaoka 120a6e
  m_originalfloatingSelection = m_floatingSelection->clone();
Shinya Kitaoka 120a6e
  deleteSelectionWithoutUndo(m_currentImage, m_strokes);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToolUtils::updateSaveBox();
Shinya Kitaoka 120a6e
  TTool *tool = TTool::getApplication()->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  tool->notifyImageChanged(m_fid);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::pasteFloatingSelection() {
Shinya Kitaoka 120a6e
  if (!isFloating()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(m_transformationCount != -1 && m_transformationCount != -2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_isPastedSelection)
Shinya Kitaoka 120a6e
    TUndoManager::manager()->popUndo(m_transformationCount + 1);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    TUndoManager::manager()->popUndo(m_transformationCount);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_transformationCount > 0 || m_isPastedSelection)
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(new UndoPasteFloatingSelection(
Shinya Kitaoka 120a6e
        this, m_oldPalette.getPointer(), m_noAntialiasing));
Shinya Kitaoka 120a6e
  else if (m_transformationCount == 0)
Shinya Kitaoka 120a6e
    TUndoManager::manager()->popUndo(-1, true);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRectD wRect = getSelectionBbox();
Shinya Kitaoka 120a6e
  pasteFloatingSelectionWithoutUndo(m_currentImage, m_floatingSelection,
Shinya Kitaoka 120a6e
                                    m_affine, wRect, m_noAntialiasing);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ToolUtils::updateSaveBox(m_currentImageCell.getSimpleLevel(),
Shinya Kitaoka 120a6e
                           m_currentImageCell.getFrameId());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  setFloatingSeletion(TRasterP());
Shinya Kitaoka 120a6e
  selectNone();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TTool *tool = TTool::getApplication()->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  tool->notifyImageChanged(m_fid);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::deleteSelection() {
Shinya Kitaoka 120a6e
  if (!m_currentImage) return;
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TXshSimpleLevel *level  = app->getCurrentLevel()->getSimpleLevel();
Shinya Kitaoka 120a6e
  // we have to remove all undo transformation and the undo for the makeFloating
Shinya Kitaoka 120a6e
  // operation!
Shinya Kitaoka 120a6e
  if (isFloating()) {
Shinya Kitaoka 120a6e
    assert(m_transformationCount != -1 && m_transformationCount != -2);
Shinya Kitaoka 120a6e
    if (m_isPastedSelection)
Shinya Kitaoka 120a6e
      TUndoManager::manager()->popUndo(m_transformationCount + 1);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      TUndoManager::manager()->popUndo(m_transformationCount);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!isPastedSelection() && !isEmpty())
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(new UndoDeleteSelection(this, level));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isFloating())
Shinya Kitaoka 120a6e
    deleteSelectionWithoutUndo(m_currentImage, m_strokes);
Shinya Kitaoka 120a6e
  else if (m_oldPalette)
Shinya Kitaoka 120a6e
    m_currentImage->getPalette()->assign(m_oldPalette.getPointer());
Shinya Kitaoka 120a6e
  m_floatingSelection         = TRasterP();
Shinya Kitaoka 120a6e
  m_originalfloatingSelection = TRasterP();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToolUtils::updateSaveBox();
Shinya Kitaoka 120a6e
  selectNone();
Shinya Kitaoka 120a6e
  app->getPaletteController()->getCurrentLevelPalette()->notifyPaletteChanged();
Shinya Kitaoka 120a6e
  TTool *tool = app->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  tool->notifyImageChanged(m_fid);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::copySelection() {
Shinya Kitaoka 120a6e
  if (isEmpty() || !m_currentImage) return;
Shinya Kitaoka 120a6e
  TRasterP ras;
Shinya Kitaoka 120a6e
  if (!isFloating())
Shinya Kitaoka 120a6e
    ras = getImageFromSelection(m_currentImage, *this);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    ras = m_floatingSelection;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double dpix, dpiy;
Shinya Kitaoka 120a6e
  std::vector<trectd> rect;</trectd>
Shinya Kitaoka 120a6e
  if (TToonzImageP ti = (TToonzImageP)(m_currentImage)) {
Shinya Kitaoka 120a6e
    ToonzImageData *data = new ToonzImageData();
Shinya Kitaoka 120a6e
    ti->getDpi(dpix, dpiy);
Shinya Kitaoka 120a6e
    data->setData(ras, ti->getPalette(), dpix, dpiy, ti->getSize(), rect,
Shinya Kitaoka 120a6e
                  m_strokes, m_originalStrokes, m_affine);
Shinya Kitaoka 120a6e
    QApplication::clipboard()->setMimeData(cloneData(data));
Shinya Kitaoka 120a6e
  } else if (TRasterImageP ri = (TRasterImageP)(m_currentImage)) {
Shinya Kitaoka 120a6e
    FullColorImageData *data = new FullColorImageData();
Shinya Kitaoka 120a6e
    ri->getDpi(dpix, dpiy);
Shinya Kitaoka 120a6e
    data->setData(ras, ri->getPalette(), dpix, dpiy, ri->getRaster()->getSize(),
Shinya Kitaoka 120a6e
                  rect, m_strokes, m_originalStrokes, m_affine);
Shinya Kitaoka 120a6e
    QApplication::clipboard()->setMimeData(cloneData(data));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::cutSelection() {
Shinya Kitaoka 120a6e
  copySelection();
Shinya Kitaoka 120a6e
  deleteSelection();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::pasteSelection(const RasterImageData *riData) {
Shinya Kitaoka 120a6e
  std::vector<trectd> rect;</trectd>
Shinya Kitaoka 120a6e
  double currentDpiX, currentDpiY;
Shinya Kitaoka 120a6e
  double dpiX, dpiY;
Shinya Kitaoka 120a6e
  const ToonzImageData *toonzImageData =
Shinya Kitaoka 120a6e
      dynamic_cast<const *="" toonzimagedata="">(riData);</const>
Shinya Kitaoka 120a6e
  const FullColorImageData *fullColorData =
Shinya Kitaoka 120a6e
      dynamic_cast<const *="" fullcolorimagedata="">(riData);</const>
Shinya Kitaoka 120a6e
  if (TToonzImageP ti = (TToonzImageP)m_currentImage) {
Shinya Kitaoka 120a6e
    ti->getDpi(currentDpiX, currentDpiY);
Shinya Kitaoka 120a6e
    TRasterP cmRas;
Shinya Kitaoka 120a6e
    if (fullColorData) {
Shinya Kitaoka 120a6e
      DVGui::error(QObject::tr(
Shinya Kitaoka 120a6e
          "The copied selection cannot be pasted in the current drawing."));
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    riData->getData(cmRas, dpiX, dpiY, rect, m_strokes, m_originalStrokes,
Shinya Kitaoka 120a6e
                    m_affine, m_currentImage->getPalette());
Shinya Kitaoka 120a6e
    if (!cmRas) return;
Shinya Kitaoka 120a6e
    m_floatingSelection = cmRas;
Shinya Kitaoka 120a6e
  } else if (TRasterImageP ri = (TRasterImageP)m_currentImage) {
Shinya Kitaoka 120a6e
    ri->getDpi(currentDpiX, currentDpiY);
Shinya Kitaoka 120a6e
    TRasterP ras;
Shinya Kitaoka 120a6e
    riData->getData(ras, dpiX, dpiY, rect, m_strokes, m_originalStrokes,
Shinya Kitaoka 120a6e
                    m_affine, ri->getPalette());
Shinya Kitaoka 120a6e
    if (!ras) return;
Shinya Kitaoka 120a6e
    if (TRasterCM32P rasCM = ras) {
Shinya Kitaoka 120a6e
      TDimension dim = rasCM->getSize();
Shinya Kitaoka 120a6e
      TRaster32P app = TRaster32P(dim.lx, dim.ly);
Shinya Kitaoka 120a6e
      TRop::convert(app, rasCM, ri->getPalette());
Shinya Kitaoka 120a6e
      ras = app;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_floatingSelection = ras;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (m_floatingSelection)
Shinya Kitaoka 120a6e
    m_originalfloatingSelection = m_floatingSelection->clone();
Shinya Kitaoka 120a6e
  TScale sc;
Shinya Kitaoka 120a6e
  if (dpiX != 0 && dpiY != 0 && currentDpiX != 0 && currentDpiY != 0)
Shinya Kitaoka 120a6e
    sc     = TScale(currentDpiX / dpiX, currentDpiY / dpiY);
Shinya Kitaoka 120a6e
  m_affine = m_affine * sc;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::pasteSelection() {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TTool *tool             = app->getCurrentTool()->getTool();
Shinya Kitaoka 120a6e
  TImageP image           = tool->getImage(true);
Shinya Kitaoka 120a6e
  m_currentImage          = image;
Shinya Kitaoka 120a6e
  m_fid                   = tool->getCurrentFid();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QClipboard *clipboard = QApplication::clipboard();
Shinya Kitaoka 120a6e
  const RasterImageData *riData =
Shinya Kitaoka 120a6e
      dynamic_cast<const *="" rasterimagedata="">(clipboard->mimeData());</const>
Shinya Kitaoka 120a6e
  const StrokesData *stData =
Shinya Kitaoka 120a6e
      dynamic_cast<const *="" strokesdata="">(clipboard->mimeData());</const>
Shinya Kitaoka 120a6e
  if (!riData && !stData) return;
Shinya Kitaoka 120a6e
  if (isFloating()) pasteFloatingSelection();
Shinya Kitaoka 120a6e
  selectNone();
Shinya Kitaoka 120a6e
  m_isPastedSelection = true;
Shinya Kitaoka 120a6e
  m_oldPalette        = m_currentImage->getPalette()->clone();
Shinya Kitaoka 120a6e
  if (stData) {
Shinya Kitaoka 120a6e
    if (TToonzImageP ti = m_currentImage)
Shinya Kitaoka 120a6e
      riData = stData->toToonzImageData(ti);
Shinya Kitaoka 120a6e
    else {
Shinya Kitaoka 120a6e
      TRasterImageP ri = m_currentImage;
Shinya Kitaoka 120a6e
      assert(ri);
Shinya Kitaoka 120a6e
      double dpix, dpiy;
Shinya Kitaoka 120a6e
      ri->getDpi(dpix, dpiy);
Shinya Kitaoka 120a6e
      if (dpix == 0 || dpiy == 0) {
Shinya Kitaoka 120a6e
        TPointD dpi =
Shinya Kitaoka 120a6e
            tool->getXsheet()->getScene()->getCurrentCamera()->getDpi();
Shinya Kitaoka 120a6e
        dpix = dpi.x;
Shinya Kitaoka 120a6e
        dpiy = dpi.y;
Shinya Kitaoka 120a6e
        ri->setDpi(dpix, dpiy);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      riData = stData->toFullColorImageData(ri);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!riData) return;
Shinya Kitaoka 120a6e
  pasteSelection(riData);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  app->getPaletteController()->getCurrentLevelPalette()->notifyPaletteChanged();
Shinya Kitaoka 120a6e
  notify();
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(new UndoPasteSelection(this));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool RasterSelection::isTransformed() { return !m_affine.isIdentity(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD RasterSelection::getStrokesBound(std::vector<tstroke> strokes) const {</tstroke>
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  TRectD box = TRectD();
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)strokes.size(); i++) box += strokes[i].getBBox();
Shinya Kitaoka 120a6e
  return box;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD RasterSelection::getSelectionBound() const {
Shinya Kitaoka 120a6e
  if (m_strokes.size() == 0) return TRectD();
Shinya Kitaoka 120a6e
  TRectD selectionBox            = getStrokesBound(m_strokes);
Shinya Kitaoka 120a6e
  if (isFloating()) selectionBox = m_affine * selectionBox;
Shinya Kitaoka 120a6e
  return selectionBox;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD RasterSelection::getOriginalSelectionBound() const {
Shinya Kitaoka 120a6e
  if (m_originalStrokes.size() == 0) return TRectD();
Shinya Kitaoka 120a6e
  return getStrokesBound(m_originalStrokes);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD RasterSelection::getSelectionBbox() const {
Shinya Kitaoka 120a6e
  TRectD rect            = m_selectionBbox;
Shinya Kitaoka 120a6e
  if (isFloating()) rect = m_affine * m_selectionBbox;
Shinya Kitaoka 120a6e
  return rect;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void RasterSelection::setSelectionBbox(const TRectD &rect) {
Shinya Kitaoka 120a6e
  m_selectionBbox = rect;
Toshihiro Shimizu 890ddd
}