// get next word
 Stroke getNextStroke(BufferedReader logReader) {
   Stroke stroke = new Stroke();
   String line = null;
   try {
     line = logReader.readLine();
     int indexOfTransl = -1;
     if (line != null) indexOfTransl = line.indexOf("Translation");
     if (line != null && indexOfTransl > -1) {
       boolean isMultipleWorld = false;
       int indexOfLast = 1 + line.indexOf(",) : ");
       if (indexOfLast < 1) {
         isMultipleWorld = true;
         indexOfLast = line.indexOf(" : ");
       }
       if (indexOfTransl == 24) {
         stroke.isDelete = false;
       } else {
         stroke.isDelete = true;
       }
       stroke.stroke = getStroke(line, indexOfTransl + 14, indexOfLast - 2);
       stroke.word = line.substring(indexOfLast + (isMultipleWorld ? 2 : 3), line.length() - 1);
       return stroke;
     } else {
       return null;
     }
   } catch (Exception e) {
     println("Error while reading stroke from Plover log file: " + e.getMessage());
   }
   return null;
 }
Example #2
0
 static {
   Stroke stroke = new BasicStroke(2);
   selectionShape = stroke.createStrokedShape(hitRect);
   format.setMinimumIntegerDigits(1);
   format.setMinimumFractionDigits(1);
   format.setMaximumFractionDigits(2);
 }
Example #3
0
 public void draw(GraphicsWrapper gw) {
   gw.setLineWidth(5);
   for (Stroke s : strokes) {
     s.draw(gw);
   }
   gw.setLineWidth(1);
 }
Example #4
0
 public AlignedRectangle2D getBoundingRectangle() {
   if (isBoundingRectangleDirty) {
     boundingRectangle.clear();
     for (Stroke s : strokes) {
       boundingRectangle.bound(s.getBoundingRectangle());
     }
     isBoundingRectangleDirty = false;
   }
   return boundingRectangle;
 }
Example #5
0
  public void draw(GraphicsWrapper gw) {

    palette.draw(gw);

    // draw filled rectangles over the selected strokes
    gw.setCoordinateSystemToWorldSpaceUnits();
    for (Stroke s : selectedStrokes) {
      AlignedRectangle2D r = s.getBoundingRectangle();
      gw.setColor(1.0f, 0.5f, 0, 0.2f); // transparent orange
      Vector2D diagonal = r.getDiagonal();
      gw.fillRect(r.getMin().x(), r.getMin().y(), diagonal.x(), diagonal.y());
    }

    gw.setCoordinateSystemToPixels();

    // draw cursors
    for (int i = 0; i < cursorContainer.getNumCursors(); ++i) {
      MyCursor cursor = cursorContainer.getCursorByIndex(i);
      if (cursor.type == MyCursor.TYPE_NOTHING)
        gw.setColor(0.5f, 0, 0, 0.65f); // red (because this cursor is being ignored)
      else gw.setColor(0, 0.5f, 0.5f, 0.65f); // cyan
      gw.fillCircle(cursor.getCurrentPosition().x() - 10, cursor.getCurrentPosition().y() - 10, 10);

      if (cursor.type == MyCursor.TYPE_INKING) {
        // draw ink trail
        gw.setColor(0, 0, 0);
        gw.drawPolyline(cursor.getPositions());
      } else if (cursor.type == MyCursor.TYPE_SELECTION) {
        if (cursor.doesDragLookLikeLassoGesture()) {
          // draw filled polygon
          gw.setColor(0, 0, 0, 0.2f);
          gw.fillPolygon(cursor.getPositions());
        } else {
          // draw polyline to indicate that a lasso could be started
          gw.setColor(0, 0, 0);
          gw.drawPolyline(cursor.getPositions());

          // also draw selection rectangle
          gw.setColor(0, 0, 0, 0.2f);
          Vector2D diagonal = Point2D.diff(cursor.getCurrentPosition(), cursor.getFirstPosition());
          gw.fillRect(
              cursor.getFirstPosition().x(),
              cursor.getFirstPosition().y(),
              diagonal.x(),
              diagonal.y());
        }
      }
    }
  }
Example #6
0
 @Override
 public Mark copy() {
   Mark copy = new Mark();
   copy.wellKnown = wellKnown;
   copy.fill = fill.copy();
   copy.stroke = stroke.copy();
   copy.markIndex = markIndex;
   // these two should be safe to just copy the references:
   copy.shape = shape;
   copy.font = font;
   return copy;
 }
Example #7
0
 public void paintComponent(Graphics g) {
   super.paintComponent(g);
   this.setBackground(Color.WHITE);
   Graphics2D g2d = (Graphics2D) g;
   RenderingHints rh =
       new RenderingHints(
           RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
   g2d.setRenderingHints(rh);
   for (int i = 0; i < strokes.size(); i++) {
     Stroke currentStroke = strokes.get(i);
     g2d.setPaint(currentStroke.getColor());
     g2d.setStroke(new BasicStroke(currentStroke.getThickness()));
     ArrayList<Point2D> currentStrokePoints = currentStroke.getPoints();
     for (int j = 1; j < currentStrokePoints.size(); j++) {
       g2d.drawLine(
           (int) (currentStrokePoints.get(j - 1).getX() * this.getSize().getWidth()),
           (int) (currentStrokePoints.get(j - 1).getY() * this.getSize().getHeight()),
           (int) (currentStrokePoints.get(j).getX() * this.getSize().getWidth()),
           (int) (currentStrokePoints.get(j).getY() * this.getSize().getHeight()));
     }
   }
 }
 public void setStroke(Stroke s) {
   if (s != null) {
     m_localGraphicsState.setStroke(s);
     if (s.equals(m_psGraphicsState.getStroke())) {
       return;
     }
     m_psGraphicsState.setStroke(s);
   } else {
     m_localGraphicsState.setStroke(new BasicStroke());
     m_psGraphicsState.setStroke(getStroke());
   }
   // ouput postscript here to set stroke.
 }
Example #9
0
 public ArrayList<Integer> strokesToPrimitives(ArrayList<Stroke> strokes) {
   if (strokes == null) return null;
   ArrayList<Integer> primitives = new ArrayList<Integer>();
   for (Stroke stroke : strokes) {
     String type = stroke.StrokeGetType();
     if (type.equals("arc")) primitives.add(Line(stroke.StrokeGetArc()));
     if (type.equals("cubicbezier")) primitives.add(BezierCubic(stroke.StrokeGet3Bezier()));
     if (type.equals("line")) primitives.add(Line(stroke.StrokeGetLine()));
     if (type.equals("quadraticbezier"))
       primitives.add(BezierQuadratic(stroke.StrokeGet2Bezier()));
   }
   return primitives;
 }
  public void doPost(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
    try {
      ServletFileUpload upload = new ServletFileUpload();
      res.setContentType("text/plain");

      KanjiDao dao = new KanjiDao();

      FileItemIterator iterator = upload.getItemIterator(req);
      while (iterator.hasNext()) {
        FileItemStream item = iterator.next();
        InputStream stream = item.openStream();

        if (item.isFormField()) {
          log.warning("Got a form field: " + item.getFieldName());
        } else {
          log.info("Got an uploaded file: " + item.getFieldName() + ", name = " + item.getName());

          KanjSvgParser parser = new KanjSvgParser(stream);
          Kanji kanji = parser.parse();
          if (kanji == null) {
            log.warning("Could not parse SVG");
            continue;
          }

          PersistenceManager pm = PMF.get().getPersistenceManager();
          try {
            Kanji existing = dao.findKanji(pm, kanji.getUnicodeNumber());
            if (existing == null) {
              log.warning(
                  String.format("Kanji %s not found. Nothing to update", kanji.getUnicodeNumber()));
              continue;
            }

            List<Stroke> newStrokes = kanji.getStrokes();
            List<Stroke> existingStrokes = existing.getStrokes();
            for (int i = 0; i < existingStrokes.size(); i++) {
              Stroke s = newStrokes.get(i);
              Stroke old = existingStrokes.get(i);
              log.info("old stroke: " + old);
              log.info("new stroke: " + s);

              old.setPath(s.getPath());
              old.setNumber(s.getNumber());
            }

            log.info(
                String.format(
                    "Updated strokes for %s(%s)",
                    existing.getMidashi(), existing.getUnicodeNumber()));
            log.info(String.format("Removing %s from cache", existing.getUnicodeNumber()));
            CacheController.remove(existing.getUnicodeNumber());
          } finally {
            pm.close();
          }
        }

        res.sendRedirect("/update-strokes.xhtml");
      }
    } catch (Exception ex) {
      throw new ServletException(ex);
    }
  }
Example #11
0
 public Mark() {
   stroke.color = BLACK;
 }
Example #12
0
  // returns true if a redraw is requested
  public boolean processMultitouchInputEvent(
      int id,
      float x, // in pixels
      float y, // in pixels
      int type,
      GraphicsWrapper gw,
      boolean doOtherUserContextsHaveCursors) {
    // Find the cursor that corresponds to the event id, if such a cursor already exists.
    // If no such cursor exists, the below index will be -1, and the reference to cursor will be
    // null.
    int cursorIndex = cursorContainer.findIndexOfCursorById(id);
    MyCursor cursor = (cursorIndex == -1) ? null : cursorContainer.getCursorByIndex(cursorIndex);

    if (cursor == null) {

      if (type == MultitouchFramework.TOUCH_EVENT_UP) {
        // This should never happen, but if it does, just ignore the event.
        return false;
      }

      // The event does not correspond to any existing cursor.
      // In other words, this is a new finger touching the screen.
      // The event is probably of type TOUCH_EVENT_DOWN.
      // A new cursor will need to be created for the event.

      if (palette.contains(x, y)) {
        // The event occurred inside the palette.

        if (cursorContainer.getNumCursors() == 0) {
          // There are currently no cursors engaged for this user context.
          // In other words, this new finger is the only finger for the user context.
          // So, we allow the event for the new finger to activate a button in the palette.
          // We branch according to the button under the event.
          //
          int indexOfButton = palette.indexOfButtonContainingTheGivenPoint(x, y);
          if (indexOfButton == palette.movePalette_buttonIndex) {
            palette.buttons.get(indexOfButton).isPressed = true;

            // Cause a new cursor to be created to keep track of this event id in the future
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton);
          } else if (indexOfButton == palette.ink_buttonIndex
              || indexOfButton == palette.select_buttonIndex
              || indexOfButton == palette.manipulate_buttonIndex
              || indexOfButton == palette.camera_buttonIndex) {
            // We transition to the mode corresponding to the button
            palette.buttons.get(palette.currentlyActiveModalButton).isPressed = false;
            palette.currentlyActiveModalButton = indexOfButton;
            palette.buttons.get(indexOfButton).isPressed = true;

            // Cause a new cursor to be created to keep track of this event id in the future
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton);
          } else if (indexOfButton == palette.black_buttonIndex
              || indexOfButton == palette.red_buttonIndex
              || indexOfButton == palette.green_buttonIndex) {
            // We transition to the color corresponding to the button
            palette.buttons.get(palette.currentlyActiveColorButton).isPressed = false;
            palette.currentlyActiveColorButton = indexOfButton;
            palette.buttons.get(indexOfButton).isPressed = true;

            if (indexOfButton == palette.black_buttonIndex) {
              palette.current_red = 0;
              palette.current_green = 0;
              palette.current_blue = 0;
            } else if (indexOfButton == palette.red_buttonIndex) {
              palette.current_red = 1.0f;
              palette.current_green = 0;
              palette.current_blue = 0;
            } else if (indexOfButton == palette.green_buttonIndex) {
              palette.current_red = 0;
              palette.current_green = 1.0f;
              palette.current_blue = 0;
            }

            // Cause a new cursor to be created to keep track of this event id in the future
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton);
          } else if (indexOfButton == palette.horizFlip_buttonIndex) {
            palette.buttons.get(indexOfButton).isPressed = true;

            // Cause a new cursor to be created to keep track of this event id in the future
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton);

            // Flip the selected strokes horizontally (around a vertical axis)
            for (Stroke s : selectedStrokes) {
              Point2D center = s.getBoundingRectangle().getCenter();
              for (Point2D p : s.getPoints()) {
                p.copy(center.x() - (p.x() - center.x()), p.y());
              }
              s.markBoundingRectangleDirty();
            }
            drawing.markBoundingRectangleDirty();
          } else if (indexOfButton == palette.frameAll_buttonIndex) {
            palette.buttons.get(indexOfButton).isPressed = true;

            // Cause a new cursor to be created to keep track of this event id in the future
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_INTERACTING_WITH_WIDGET, indexOfButton);

            // Frame the entire drawing
            gw.frame(drawing.getBoundingRectangle(), true);
          } else {
            // The event occurred on some part of the palette where there are no buttons.
            // We cause a new cursor to be created to keep track of this event id in the future.
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);

            // Prevent the cursor from doing anything in the future.
            cursor.setType(MyCursor.TYPE_NOTHING);
          }
        } else {
          // There is already at least one cursor.
          // In other words, there is already one or more other fingers being tracked in this user
          // context
          // (possibly on a palette button, and/or over the drawing).
          // To keep things simple, we prevent this new finger from doing anything.

          // We create a new cursor ...
          cursorIndex = cursorContainer.updateCursorById(id, x, y);
          cursor = cursorContainer.getCursorByIndex(cursorIndex);

          // ... and prevent the cursor from doing anything in the future.
          cursor.setType(MyCursor.TYPE_NOTHING);
        }
      } else {
        // The event did not occur inside the palette.
        // This new finger may have been placed down to start
        // drawing a stroke, or start camera manipulation, etc.
        // We branch according to the current mode.
        //
        if (palette.currentlyActiveModalButton == palette.ink_buttonIndex) {
          // start drawing a stroke
          cursorIndex = cursorContainer.updateCursorById(id, x, y);
          cursor = cursorContainer.getCursorByIndex(cursorIndex);
          cursor.setType(MyCursor.TYPE_INKING);
        } else if (palette.currentlyActiveModalButton == palette.select_buttonIndex) {
          // The new finger should only start selecting
          // if there is not already another finger performing selection.
          if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_SELECTION) == 0) {
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_SELECTION);
          } else {
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_NOTHING);
          }
        } else if (palette.currentlyActiveModalButton == palette.manipulate_buttonIndex) {
          // The new finger should only manipulate the selection
          // if there are not already 2 fingers manipulating the selection.
          if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_DIRECT_MANIPULATION) < 2) {
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_DIRECT_MANIPULATION);
          } else {
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_NOTHING);
          }
        } else if (palette.currentlyActiveModalButton == palette.camera_buttonIndex) {
          // The new finger should only manipulate the camera
          // if there are not already 2 fingers manipulating the camera.
          if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_CAMERA_PAN_ZOOM) < 2) {
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_CAMERA_PAN_ZOOM);
          } else {
            cursorIndex = cursorContainer.updateCursorById(id, x, y);
            cursor = cursorContainer.getCursorByIndex(cursorIndex);
            cursor.setType(MyCursor.TYPE_NOTHING);
          }
        }
      }
    } else {
      // The event corresponds to an already existing cursor
      // (and the cursor was probably created during an earlier event of type TOUCH_EVENT_DOWN).
      // The current event is probably of type TOUCH_EVENT_MOVE or TOUCH_EVENT_UP.

      if (type == MultitouchFramework.TOUCH_EVENT_MOVE) {
        // The event is a move event, and corresponds to an existing cursor.
        // Is the location of the event different from the last reported location?
        Point2D newPosition = new Point2D(x, y);
        if (cursor.getCurrentPosition().equals(newPosition)) {
          // The event's location is the same as last time.
          // Don't bother processing the event any further.
          return false; // do not request a redraw
        }
      }

      // We branch according to the type of cursor.
      //
      if (cursor.type == MyCursor.TYPE_NOTHING) {
        // Update the cursor with its new position.
        cursorContainer.updateCursorById(id, x, y);

        if (type == MultitouchFramework.TOUCH_EVENT_UP)
          cursorContainer.removeCursorByIndex(cursorIndex);
      } else if (cursor.type == MyCursor.TYPE_INTERACTING_WITH_WIDGET) {
        if (type == MultitouchFramework.TOUCH_EVENT_UP) {
          // The user lifted their finger off of a palette button.
          cursorContainer.removeCursorByIndex(cursorIndex);

          if (!palette.buttons.get(cursor.indexOfButton).isSticky) {
            palette.buttons.get(cursor.indexOfButton).isPressed = false;
          }
        } else {
          // Earlier, the user pressed down on a button in the palette,
          // and now they are dragging their finger over the button
          // (and possibly onto other buttons).
          // If this is the "move palette" button, we move the palette.
          if (cursor.indexOfButton == palette.movePalette_buttonIndex) {
            movePalette(x - cursor.getCurrentPosition().x(), y - cursor.getCurrentPosition().y());
          }
          cursorIndex = cursorContainer.updateCursorById(id, x, y);
        }
      } else if (cursor.type == MyCursor.TYPE_INKING) {
        if (type == MultitouchFramework.TOUCH_EVENT_UP) {
          // up event
          cursorIndex = cursorContainer.updateCursorById(id, x, y);

          // Add the newly drawn stroke to the drawing
          Stroke newStroke = new Stroke();
          newStroke.setColor(palette.current_red, palette.current_green, palette.current_blue);
          for (Point2D p : cursor.getPositions()) {
            newStroke.addPoint(gw.convertPixelsToWorldSpaceUnits(p));
          }
          drawing.addStroke(newStroke);

          cursorContainer.removeCursorByIndex(cursorIndex);
        } else {
          // drag event; just update the cursor with the new position
          cursorIndex = cursorContainer.updateCursorById(id, x, y);
        }
      } else if (cursor.type == MyCursor.TYPE_CAMERA_PAN_ZOOM) {
        if (type == MultitouchFramework.TOUCH_EVENT_UP) {
          // up event
          cursorContainer.removeCursorByIndex(cursorIndex);
        } else {
          // drag event
          cursorIndex = cursorContainer.updateCursorById(id, x, y);

          if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_CAMERA_PAN_ZOOM) == 2) {
            MyCursor cursor0 = cursorContainer.getCursorByType(MyCursor.TYPE_CAMERA_PAN_ZOOM, 0);
            MyCursor cursor1 = cursorContainer.getCursorByType(MyCursor.TYPE_CAMERA_PAN_ZOOM, 1);
            gw.panAndZoomBasedOnDisplacementOfTwoPoints(
                id == cursor0.id ? cursor0.getPreviousPosition() : cursor0.getCurrentPosition(),
                id == cursor1.id ? cursor1.getPreviousPosition() : cursor1.getCurrentPosition(),
                cursor0.getCurrentPosition(),
                cursor1.getCurrentPosition());
          } else if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_CAMERA_PAN_ZOOM) == 1) {
            gw.pan(
                cursor.getCurrentPosition().x() - cursor.getPreviousPosition().x(),
                cursor.getCurrentPosition().y() - cursor.getPreviousPosition().y());
          }
        }
      } else if (cursor.type == MyCursor.TYPE_SELECTION) {
        if (type == MultitouchFramework.TOUCH_EVENT_UP) {
          // up event
          cursorIndex = cursorContainer.updateCursorById(id, x, y);

          // Update the selection
          if (cursor.doesDragLookLikeLassoGesture()) {
            // complete a lasso selection

            // Need to transform the positions of the cursor from pixels to world space coordinates.
            // We will store the world space coordinates in the following data structure.
            ArrayList<Point2D> lassoPolygonPoints = new ArrayList<Point2D>();
            for (Point2D p : cursor.getPositions()) {
              lassoPolygonPoints.add(gw.convertPixelsToWorldSpaceUnits(p));
            }

            selectedStrokes.clear();
            for (Stroke s : drawing.strokes) {
              if (s.isContainedInLassoPolygon(lassoPolygonPoints)) selectedStrokes.add(s);
            }
          } else {
            // complete a rectangle selection

            AlignedRectangle2D selectedRectangle =
                new AlignedRectangle2D(
                    gw.convertPixelsToWorldSpaceUnits(cursor.getFirstPosition()),
                    gw.convertPixelsToWorldSpaceUnits(cursor.getCurrentPosition()));

            selectedStrokes.clear();
            for (Stroke s : drawing.strokes) {
              if (s.isContainedInRectangle(selectedRectangle)) selectedStrokes.add(s);
            }
          }

          cursorContainer.removeCursorByIndex(cursorIndex);
        } else {
          // drag event; just update the cursor with the new position
          cursorIndex = cursorContainer.updateCursorById(id, x, y);
        }
      } else if (cursor.type == MyCursor.TYPE_DIRECT_MANIPULATION) {
        if (type == MultitouchFramework.TOUCH_EVENT_UP) {
          // up event
          cursorContainer.removeCursorByIndex(cursorIndex);
        } else {
          // drag event
          cursorIndex = cursorContainer.updateCursorById(id, x, y);

          if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_DIRECT_MANIPULATION) == 2) {
            MyCursor cursor0 =
                cursorContainer.getCursorByType(MyCursor.TYPE_DIRECT_MANIPULATION, 0);
            MyCursor cursor1 =
                cursorContainer.getCursorByType(MyCursor.TYPE_DIRECT_MANIPULATION, 1);

            // convert cursor positions to world space
            Point2D cursor0_currentPosition_worldSpace =
                gw.convertPixelsToWorldSpaceUnits(cursor0.getCurrentPosition());
            Point2D cursor1_currentPosition_worldSpace =
                gw.convertPixelsToWorldSpaceUnits(cursor1.getCurrentPosition());
            Point2D cursor0_previousPosition_worldSpace =
                gw.convertPixelsToWorldSpaceUnits(cursor0.getPreviousPosition());
            Point2D cursor1_previousPosition_worldSpace =
                gw.convertPixelsToWorldSpaceUnits(cursor1.getPreviousPosition());

            for (Stroke s : selectedStrokes) {
              Point2DUtil.transformPointsBasedOnDisplacementOfTwoPoints(
                  s.getPoints(),
                  id == cursor0.id
                      ? cursor0_previousPosition_worldSpace
                      : cursor0_currentPosition_worldSpace,
                  id == cursor1.id
                      ? cursor1_previousPosition_worldSpace
                      : cursor1_currentPosition_worldSpace,
                  cursor0_currentPosition_worldSpace,
                  cursor1_currentPosition_worldSpace);
              s.markBoundingRectangleDirty();
            }
            drawing.markBoundingRectangleDirty();
          } else if (cursorContainer.getNumCursorsOfGivenType(MyCursor.TYPE_DIRECT_MANIPULATION)
              == 1) {
            // convert cursor positions to world space
            Point2D cursor_currentPosition_worldSpace =
                gw.convertPixelsToWorldSpaceUnits(cursor.getCurrentPosition());
            Point2D cursor_previousPosition_worldSpace =
                gw.convertPixelsToWorldSpaceUnits(cursor.getPreviousPosition());

            // compute translation vector
            Vector2D translationVector =
                Point2D.diff(cursor_currentPosition_worldSpace, cursor_previousPosition_worldSpace);

            // apply the translation to the selected strokes
            for (Stroke s : selectedStrokes) {
              for (Point2D p : s.getPoints()) {
                p.copy(Point2D.sum(p, translationVector));
              }
              s.markBoundingRectangleDirty();
            }
            drawing.markBoundingRectangleDirty();
          }
        }
      }
    }

    return true; // request a redraw
  }