Example #1
0
TableCell PageItem_Table::cellAt(const QPointF& point) const
{
	QPointF gridPoint = getTransform().inverted().map(point) - gridOffset();

	if (!QRectF(0, 0, tableWidth(), tableHeight()).contains(gridPoint))
		return TableCell(); // Outside table grid.

	return cellAt(
		qUpperBound(m_rowPositions, gridPoint.y()) - m_rowPositions.begin() - 1,
		qUpperBound(m_columnPositions, gridPoint.x()) - m_columnPositions.begin() - 1);
}
Example #2
0
TableHandle PageItem_Table::hitTest(const QPointF& point, double threshold) const
{
	const QPointF framePoint = getTransform().inverted().map(point);
	const QPointF gridPoint = framePoint - gridOffset();
	const QRectF gridRect = QRectF(0.0, 0.0, tableWidth(), tableHeight());

	// Test if hit is outside frame.
	if (!QRectF(0.0, 0.0, width(), height()).contains(framePoint))
		return TableHandle(TableHandle::None);

	// Test if hit is outside table.
	if (!gridRect.adjusted(-threshold, -threshold, threshold, threshold).contains(gridPoint))
		return TableHandle(TableHandle::None);

	const double tableHeight = this->tableHeight();
	const double tableWidth = this->tableWidth();
	const double x = gridPoint.x();
	const double y = gridPoint.y();

	// Test if hit is on left edge of table.
	if (x <= threshold)
		return TableHandle(TableHandle::RowSelect);

	// Test if hit is on top edge of table.
	if (y <= threshold)
		return TableHandle(TableHandle::ColumnSelect);

	// Test if hit is on bottom right corner of table.
	if (x >= tableWidth - threshold && y >= tableHeight - threshold)
		return TableHandle(TableHandle::TableResize);

	// Test if hit is on right edge of table.
	if (y >= tableHeight - threshold && y <= tableHeight + threshold)
		return TableHandle(TableHandle::RowResize, rows() - 1);

	// Test if hit is on bottom edge of table.
	if (x >= tableWidth - threshold && x <= tableWidth + threshold)
		return TableHandle(TableHandle::ColumnResize, columns() - 1);

	const TableCell hitCell = cellAt(point);
	const QRectF hitRect = hitCell.boundingRect();

	// Test if hit is on cell interior.
	if (hitRect.adjusted(threshold, threshold, -threshold, -threshold).contains(gridPoint))
		return TableHandle(TableHandle::CellSelect); // Hit interior of cell.

	const double toLeft = x - hitRect.left();
	const double toRight = hitRect.right() - x;
	const double toTop = y - hitRect.top();
	const double toBottom = hitRect.bottom() - y;
	TableHandle handle(TableHandle::None);

	// Test which side of the cell was hit.
	if (qMin(toLeft, toRight) < qMin(toTop, toBottom))
	{
		handle.setType(TableHandle::ColumnResize);
		handle.setIndex((toLeft < toRight ? hitCell.column() : hitCell.column() + hitCell.columnSpan()) - 1);
	}
	else
	{
		handle.setType(TableHandle::RowResize);
		handle.setIndex((toTop < toBottom ? hitCell.row() : hitCell.row() + hitCell.rowSpan()) - 1);
	}
	return handle;
}
Example #3
0
void PixelsMovement::moveImage(const gfx::Point& pos, MoveModifier moveModifier)
{
  gfx::Transformation::Corners oldCorners;
  m_currentData.transformBox(oldCorners);

  ContextWriter writer(m_reader, 1000);
  gfx::RectF bounds = m_initialData.bounds();
  bool updateBounds = false;
  double dx, dy;

  dx = ((pos.x - m_catchPos.x) *  cos(m_currentData.angle()) +
        (pos.y - m_catchPos.y) * -sin(m_currentData.angle()));
  dy = ((pos.x - m_catchPos.x) *  sin(m_currentData.angle()) +
        (pos.y - m_catchPos.y) *  cos(m_currentData.angle()));

  switch (m_handle) {

    case MoveHandle:
      if ((moveModifier & LockAxisMovement) == LockAxisMovement) {
        if (ABS(dx) < ABS(dy))
          dx = 0.0;
        else
          dy = 0.0;
      }

      bounds.offset(dx, dy);
      updateBounds = true;

      if ((moveModifier & SnapToGridMovement) == SnapToGridMovement) {
        // Snap the x1,y1 point to the grid.
        gfx::Rect gridBounds = App::instance()
          ->preferences().document(m_document).grid.bounds();
        gfx::PointF gridOffset(
          snap_to_grid(
            gridBounds,
            gfx::Point(bounds.origin()),
            PreferSnapTo::ClosestGridVertex));

        // Now we calculate the difference from x1,y1 point and we can
        // use it to adjust all coordinates (x1, y1, x2, y2).
        gridOffset -= bounds.origin();
        bounds.offset(gridOffset);
      }
      break;

    case ScaleNWHandle:
    case ScaleNHandle:
    case ScaleNEHandle:
    case ScaleWHandle:
    case ScaleEHandle:
    case ScaleSWHandle:
    case ScaleSHandle:
    case ScaleSEHandle: {
      static double handles[][2] = {
        { 0.0, 0.0 }, { 0.5, 0.0 }, { 1.0, 0.0 },
        { 0.0, 0.5 },               { 1.0, 0.5 },
        { 0.0, 1.0 }, { 0.5, 1.0 }, { 1.0, 1.0 }
      };
      gfx::PointF pivot;
      gfx::PointF handle(
        handles[m_handle-ScaleNWHandle][0],
        handles[m_handle-ScaleNWHandle][1]);

      if ((moveModifier & ScaleFromPivot) == ScaleFromPivot) {
        pivot.x = m_currentData.pivot().x;
        pivot.y = m_currentData.pivot().y;
      }
      else {
        pivot.x = 1.0 - handle.x;
        pivot.y = 1.0 - handle.y;
        pivot.x = bounds.x + bounds.w*pivot.x;
        pivot.y = bounds.y + bounds.h*pivot.y;
      }

      gfx::PointF a = bounds.origin();
      gfx::PointF b = bounds.point2();

      if ((moveModifier & MaintainAspectRatioMovement) == MaintainAspectRatioMovement) {
        auto u = point2Vector(gfx::PointF(m_catchPos) - pivot);
        auto v = point2Vector(gfx::PointF(pos) - pivot);
        auto w = v.projectOn(u);
        double scale = u.magnitude();
        if (scale != 0.0)
          scale = (std::fabs(w.angle()-u.angle()) < PI/2.0 ? 1.0: -1.0) * w.magnitude() / scale;
        else
          scale = 1.0;

        a.x = int((a.x-pivot.x)*scale + pivot.x);
        a.y = int((a.y-pivot.y)*scale + pivot.y);
        b.x = int((b.x-pivot.x)*scale + pivot.x);
        b.y = int((b.y-pivot.y)*scale + pivot.y);
      }
      else {
        handle.x = bounds.x + bounds.w*handle.x;
        handle.y = bounds.y + bounds.h*handle.y;

        double w = (handle.x-pivot.x);
        double h = (handle.y-pivot.y);

        if (m_handle == ScaleNHandle || m_handle == ScaleSHandle) {
          dx = 0.0;
          w = 1.0;              // Any value != 0.0 to avoid div by zero
        }
        else if (m_handle == ScaleWHandle || m_handle == ScaleEHandle) {
          dy = 0.0;
          h = 1.0;
        }

        a.x = int((a.x-pivot.x)*(1.0+dx/w) + pivot.x);
        a.y = int((a.y-pivot.y)*(1.0+dy/h) + pivot.y);
        b.x = int((b.x-pivot.x)*(1.0+dx/w) + pivot.x);
        b.y = int((b.y-pivot.y)*(1.0+dy/h) + pivot.y);
      }

      // Do not use "gfx::Rect(a, b)" here because if a > b we want to
      // keep a rectangle with negative width or height (to know that
      // it was flipped).
      bounds.x = a.x;
      bounds.y = a.y;
      bounds.w = b.x - a.x;
      bounds.h = b.y - a.y;

      updateBounds = true;
      break;
    }

    case RotateNWHandle:
    case RotateNHandle:
    case RotateNEHandle:
    case RotateWHandle:
    case RotateEHandle:
    case RotateSWHandle:
    case RotateSHandle:
    case RotateSEHandle:
      {
        gfx::PointF abs_initial_pivot = m_initialData.pivot();
        gfx::PointF abs_pivot = m_currentData.pivot();

        double newAngle =
          m_initialData.angle()
          + atan2((double)(-pos.y + abs_pivot.y),
                  (double)(+pos.x - abs_pivot.x))
          - atan2((double)(-m_catchPos.y + abs_initial_pivot.y),
                  (double)(+m_catchPos.x - abs_initial_pivot.x));

        // Put the angle in -180 to 180 range.
        while (newAngle < -PI) newAngle += 2*PI;
        while (newAngle > PI) newAngle -= 2*PI;

        // Is the "angle snap" is activated, we've to snap the angle
        // to common (pixel art) angles.
        if ((moveModifier & AngleSnapMovement) == AngleSnapMovement) {
          // TODO make this configurable
          static const double keyAngles[] = {
            0.0, 26.565, 45.0, 63.435, 90.0, 116.565, 135.0, 153.435, 180.0,
            180.0, -153.435, -135.0, -116, -90.0, -63.435, -45.0, -26.565
          };

          double newAngleDegrees = 180.0 * newAngle / PI;

          int closest = 0;
          int last = sizeof(keyAngles) / sizeof(keyAngles[0]) - 1;
          for (int i=0; i<=last; ++i) {
            if (std::fabs(newAngleDegrees-keyAngles[closest]) >
                std::fabs(newAngleDegrees-keyAngles[i]))
              closest = i;
          }

          newAngle = PI * keyAngles[closest] / 180.0;
        }

        m_currentData.angle(newAngle);
      }
      break;

    case PivotHandle:
      {
        // Calculate the new position of the pivot
        gfx::PointF newPivot(m_initialData.pivot().x + (pos.x - m_catchPos.x),
                             m_initialData.pivot().y + (pos.y - m_catchPos.y));

        m_currentData = m_initialData;
        m_currentData.displacePivotTo(newPivot);
      }
      break;
  }

  if (updateBounds) {
    m_currentData.bounds(bounds);
    m_adjustPivot = true;
  }

  redrawExtraImage();

  m_document->setTransformation(m_currentData);

  // Get the new transformed corners
  gfx::Transformation::Corners newCorners;
  m_currentData.transformBox(newCorners);

  // Create a union of all corners, and that will be the bounds to
  // redraw of the sprite.
  gfx::Rect fullBounds;
  for (int i=0; i<gfx::Transformation::Corners::NUM_OF_CORNERS; ++i) {
    fullBounds = fullBounds.createUnion(gfx::Rect((int)oldCorners[i].x, (int)oldCorners[i].y, 1, 1));
    fullBounds = fullBounds.createUnion(gfx::Rect((int)newCorners[i].x, (int)newCorners[i].y, 1, 1));
  }

  // If "fullBounds" is empty is because the cel was not moved
  if (!fullBounds.isEmpty()) {
    // Notify the modified region.
    m_document->notifySpritePixelsModified(m_sprite, gfx::Region(fullBounds),
                                           m_site.frame());
  }
}