private void renderCalloutsLayer() {
    int numOfInfoLines = 0;
    int offset = 0;

    // Print mouse coordinates
    Callout mousePointer = calloutsUpdater.getMousePointerCallout();
    if (mousePointer != null) {
      drawString(
          mousePointer.getText(),
          (int) mousePointer.getPosition().getX(),
          (int) mousePointer.getPosition().getY(),
          (float) 0.0,
          mousePointer.getColor());
    }

    // Print all other callouts
    synchronized (calloutsUpdater.getPrintableCallouts()) {
      for (Callout callout : calloutsUpdater.getPrintableCallouts()) {
        // display multiple info callouts on different lines
        if (callout.getGroup().equalsIgnoreCase("info")) {
          offset = (numOfInfoLines * 50);
          numOfInfoLines++;
          drawString(
              callout.getText(),
              (int) callout.getPosition().getX(),
              (int) callout.getPosition().getY() + offset,
              (float) 0.0,
              callout.getColor());
        } else {
          drawString(
              callout.getText(),
              (int) callout.getPosition().getX(),
              (int) callout.getPosition().getY(),
              (float) 0.0,
              callout.getColor());
        }

        // limit to the last 10 most recent lines
        if (numOfInfoLines > 10) {
          return;
        }
      }
    }
  }
  /** @param edit */
  @Override
  public void setRoomEditMode(boolean edit) {
    roomEditMode = edit;

    if (roomEditMode) {
      Callout callout =
          new Callout(
              this.getClass().getCanonicalName(),
              "info",
              I18n.msg("environment_editing_instructions")
                  + ":\n"
                  + "- "
                  + I18n.msg("environment_editing_instructions_add_new_room")
                  + "\n"
                  + "- "
                  + I18n.msg("environment_editing_instructions_change_room_shape")
                  + "\n"
                  + "- "
                  + I18n.msg("environment_editing_instructions_remove_room")
                  + "\n"
                  + "- "
                  + I18n.msg("environment_editing_instructions_create_draggable_point")
                  + "\n"
                  + "- "
                  + I18n.msg("environment_editing_instructions_delete_draggable_point")
                  + "\n",
              100,
              200,
              0,
              -1);
      createCallout(callout);
      createHandles(null);
      // find the first room and select it
      Room selectedRoom = getCurrEnv().getRooms().get(0);
      if (selectedRoom != null) {
        setSelectedZone(selectedRoom);
      }
    } else {
      handles.clear();
      indicators.clear();
      selectedZone = null;
      calloutsUpdater.clearAll();
    }

    setNeedRepaint(true);
  }
  /** @param e */
  @Override
  public void mouseMoved(MouseEvent e) {
    if (!roomEditMode) {
      EnvObjectLogic obj = mouseOnObject(e.getPoint());

      if ((obj == null) && (selectedObject != null)) {
        removeIndicators();
        mouseExitsObject(selectedObject);
        calloutsUpdater.clear("object.description");
      }

      if (obj != null) {
        // addIndicator(cachedShapes.get(obj));
        if (obj != selectedObject) {
          mouseEntersObject(obj);
          selectedObject = obj;
        }
      }
    } else { // in edit mode but no dragging

      if (!inDrag) {
        Point mouse = toRealCoords(e.getPoint());

        // create a callout which says the coordinates of the mouse in the environment (centimeters)
        Callout callout =
            new Callout(
                this.getClass().getCanonicalName(),
                "mouse",
                (int) mouse.getX() + "cm," + (int) mouse.getY() + "cm",
                (int) mouse.getX(),
                (int) mouse.getY(),
                0,
                -1);
        createCallout(callout);
        repaint();
      }
    }
  }
  /** @param e */
  @Override
  public void mouseClicked(MouseEvent e) {
    if (!roomEditMode) {
      EnvObjectLogic obj = mouseOnObject(e.getPoint());

      if (obj != null) {
        // single click on an object
        if (e.getButton() == MouseEvent.BUTTON1) {
          if (e.getClickCount() == 1) {
            mouseClickObject(obj);
          } else {
            // double click on an object
            if (e.getClickCount() == 2) {
              mouseDoubleClickObject(obj);
            }
          }
        } else {
          // right click on an object
          if (e.getButton() == MouseEvent.BUTTON3) {
            if (e.getClickCount() == 1) {
              mouseRightClickObject(obj);
            }
          }
        }
      } else {
        removeIndicators();
        calloutsUpdater.clearAll();
      }
    } else { // if edit mode
      removeIndicators();
      calloutsUpdater.clearAll();

      toRealCoords(e.getPoint());

      // click on an handle in edit mode
      Handle clickedHandle = mouseOnHandle(e.getPoint());

      // single right click
      if (clickedHandle != null) {
        if ((e.getClickCount() == 1) && (e.getButton() == MouseEvent.BUTTON1)) {
          clickedHandle.setSelected(true);
        } else {
          // double right click
          if ((e.getClickCount() == 2) && (e.getButton() == MouseEvent.BUTTON1)) {
            clickedHandle.addAdiacent();
            setSelectedZone(clickedHandle.getZone());
          } else {
            // single left click
            if ((e.getClickCount() == 1) && (e.getButton() == MouseEvent.BUTTON3)) {
              clickedHandle.remove();
              setSelectedZone(clickedHandle.getZone());
            }
          }
        }
      } else {
        // click on a zone in edit mode if no handle is selected
        ZoneLogic zone = mouseOnZone(e.getPoint());
        if (zone != null) {
          Callout callout =
              new Callout(
                  this.getClass().getCanonicalName(),
                  "info",
                  I18n.msg("room_zone_selected") + " [" + zone.getPojo().getName() + "]",
                  50,
                  150,
                  0,
                  -1);
          createCallout(callout);
          setSelectedZone(zone);
        } else {
          handles.clear();
          // createHandles(null);
        }
      }
      setNeedRepaint(true);
    }
  }
 /** @param callout */
 @Override
 public void createCallout(Callout callout) {
   calloutsUpdater.addCallout(callout);
 }
 private void clear() {
   this.indicators.clear();
   calloutsUpdater.clearAll();
   this.backgroundChanged = true;
 }