Datatip detached position property 32/18332/7
Caio SOUZA [Thu, 30 Jun 2016 20:10:23 +0000 (17:10 -0300)]
* The graphics entity "Datatip" has a new property `detached_position`
  which accepts `[]` or a 3-components vector to set the position in
  axes coordinates to draw the datatip text box.

Change-Id: Ibfcdc1272b1afbd9cc5d65ed596b1e09047b1afa

18 files changed:
scilab/CHANGES.md
scilab/modules/graphic_objects/includes/graphicObjectProperties.h
scilab/modules/graphic_objects/src/java/org/scilab/modules/graphic_objects/datatip/Datatip.java
scilab/modules/graphic_objects/src/java/org/scilab/modules/graphic_objects/graphicObject/GraphicObjectProperties.java
scilab/modules/graphic_objects/src/scripts/propertiesMap.properties
scilab/modules/graphics/demos/datatips/datatip_detach.sce [new file with mode: 0644]
scilab/modules/graphics/demos/datatips/datatips.dem.gateway.sce
scilab/modules/graphics/help/en_US/datatips/datatip_properties.xml
scilab/modules/graphics/macros/%h_p.sci
scilab/modules/graphics/src/c/getHandleProperty/GetHashTable.c
scilab/modules/graphics/src/c/getHandleProperty/SetHashTable.c
scilab/modules/graphics/src/c/getHandleProperty/getHandleProperty.h
scilab/modules/graphics/src/c/getHandleProperty/get_datatip_property.c
scilab/modules/graphics/src/c/getHandleProperty/setHandleProperty.h
scilab/modules/graphics/src/c/getHandleProperty/set_datatip_property.c
scilab/modules/hdf5/src/cpp/handle_properties.hxx
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/DrawerVisitor.java
scilab/modules/renderer/src/java/org/scilab/modules/renderer/JoGLView/datatip/DatatipTextDrawer.java

index d947ab5..51adef7 100644 (file)
@@ -149,6 +149,7 @@ Feature changes and additions
    - `bitxor` is now vectorized and fast.
 * The zoom rubber box now can start/finish from points lying outside the axes bounds.
 * The zoom rubber box now can select multiple and overlying axes at once. Changed behavior of scroll zoom, scrolling over overlying axes will zoom all of them together, using the CTRL key while scrolling will zoom all axes in the current figure.
+* The graphics entity "Datatip" has a new property `detached_position` which accepts `[]` or a 3-components vector to set the position in axes coordinates to draw the datatip text box.
 
 
 Help pages:
index c53ad96..18ffa88 100755 (executable)
 #define __GO_DATATIP_BOX_MODE__ 338
 #define __GO_DATATIP_LABEL_MODE__ 339
 #define __GO_DATATIP_MARK__ 340
-#define __GO_AMBIENTCOLOR__ 341
-#define __GO_DIFFUSECOLOR__ 342
-#define __GO_SPECULARCOLOR__ 343
-#define __GO_COLOR_MATERIAL__ 344
-#define __GO_MATERIAL_SHININESS__ 345
-#define __GO_LIGHT__ 346
-#define __GO_LIGHT_TYPE__ 347
-#define __GO_DATATIPS__ 348
-#define __GO_DATATIPS_COUNT__ 349
-#define __GO_DATATIP_INDEXES__ 350
-#define __GO_DATA_MODEL_DISPLAY_FUNCTION__ 351
-#define __GO_DATA_MODEL_DISPLAY_FUNCTION_SIZE__ 352
-#define __GO_RESIZE__ 353
-#define __GO_TOOLBAR__ 354
-#define __GO_TOOLBAR_VISIBLE__ 355
-#define __GO_MENUBAR__ 356
-#define __GO_MENUBAR_VISIBLE__ 357
-#define __GO_INFOBAR_VISIBLE__ 358
-#define __GO_DOCKABLE__ 359
-#define __GO_LAYOUT__ 360
-#define __GO_LAYOUT_SET__ 361
-#define __GO_UI_TAB__ 362
-#define __GO_UI_GRIDBAG_GRID__ 363
-#define __GO_UI_GRIDBAG_WEIGHT__ 364
-#define __GO_UI_GRIDBAG_FILL__ 365
-#define __GO_UI_GRIDBAG_ANCHOR__ 366
-#define __GO_UI_GRIDBAG_PADDING__ 367
-#define __GO_UI_GRIDBAG_PREFERREDSIZE__ 368
-#define __GO_UI_GRID_GRID__ 369
-#define __GO_UI_GRID_PADDING__ 370
-#define __GO_UI_BORDER_POSITION__ 371
-#define __GO_UI_BORDER_PREFERREDSIZE__ 372
-#define __GO_GRID_OPT_GRID__ 373
-#define __GO_GRID_OPT_PADDING__ 374
-#define __GO_BORDER_OPT_PADDING__ 375
-#define __GO_UI_FRAME_BORDER__ 376
-#define __GO_UI_FRAME_BORDER_COLOR__ 377
-#define __GO_UI_FRAME_BORDER_HIGHLIGHT_IN__ 378
-#define __GO_UI_FRAME_BORDER_HIGHLIGHT_OUT__ 379
-#define __GO_UI_FRAME_BORDER_IN_BORDER__ 380
-#define __GO_UI_FRAME_BORDER_JUSTIFICATION__ 381
-#define __GO_UI_FRAME_BORDER_OUT_BORDER__ 382
-#define __GO_UI_FRAME_BORDER_ROUNDED__ 383
-#define __GO_UI_FRAME_BORDER_SHADOW_IN__ 384
-#define __GO_UI_FRAME_BORDER_SHADOW_OUT__ 385
-#define __GO_UI_FRAME_BORDER_TITLE__ 386
-#define __GO_UI_FRAME_BORDER_POSITION__ 387
-#define __GO_UI_FRAME_BORDER_STYLE__ 388
-#define __GO_UI_GROUP_NAME__ 389
-#define __GO_UI_TITLE_POSITION__ 390
-#define __GO_UI_TITLE_SCROLL__ 391
-#define __GO_UI_FRAME_BORDER_TYPE__ 392
-#define __GO_UI_SCROLLABLE__ 393
-#define __GO_COLOR_SET__ 394
-#define __GO_MARK_SIZES__ 395
-#define __GO_NUM_MARK_SIZES__ 396
-#define __GO_MARK_FOREGROUNDS__ 397
-#define __GO_NUM_MARK_FOREGROUNDS__ 398
-#define __GO_MARK_BACKGROUNDS__ 399
-#define __GO_NUM_MARK_BACKGROUNDS__ 400
+#define __GO_DATATIP_DETACHED_MODE__ 341
+#define __GO_DATATIP_DETACHED_POSITION__ 342
+#define __GO_AMBIENTCOLOR__ 343
+#define __GO_DIFFUSECOLOR__ 344
+#define __GO_SPECULARCOLOR__ 345
+#define __GO_COLOR_MATERIAL__ 346
+#define __GO_MATERIAL_SHININESS__ 347
+#define __GO_LIGHT__ 348
+#define __GO_LIGHT_TYPE__ 349
+#define __GO_DATATIPS__ 350
+#define __GO_DATATIPS_COUNT__ 351
+#define __GO_DATATIP_INDEXES__ 352
+#define __GO_DATA_MODEL_DISPLAY_FUNCTION__ 353
+#define __GO_DATA_MODEL_DISPLAY_FUNCTION_SIZE__ 354
+#define __GO_RESIZE__ 355
+#define __GO_TOOLBAR__ 356
+#define __GO_TOOLBAR_VISIBLE__ 357
+#define __GO_MENUBAR__ 358
+#define __GO_MENUBAR_VISIBLE__ 359
+#define __GO_INFOBAR_VISIBLE__ 360
+#define __GO_DOCKABLE__ 361
+#define __GO_LAYOUT__ 362
+#define __GO_LAYOUT_SET__ 363
+#define __GO_UI_TAB__ 364
+#define __GO_UI_GRIDBAG_GRID__ 365
+#define __GO_UI_GRIDBAG_WEIGHT__ 366
+#define __GO_UI_GRIDBAG_FILL__ 367
+#define __GO_UI_GRIDBAG_ANCHOR__ 368
+#define __GO_UI_GRIDBAG_PADDING__ 369
+#define __GO_UI_GRIDBAG_PREFERREDSIZE__ 370
+#define __GO_UI_GRID_GRID__ 371
+#define __GO_UI_GRID_PADDING__ 372
+#define __GO_UI_BORDER_POSITION__ 373
+#define __GO_UI_BORDER_PREFERREDSIZE__ 374
+#define __GO_GRID_OPT_GRID__ 375
+#define __GO_GRID_OPT_PADDING__ 376
+#define __GO_BORDER_OPT_PADDING__ 377
+#define __GO_UI_FRAME_BORDER__ 378
+#define __GO_UI_FRAME_BORDER_COLOR__ 379
+#define __GO_UI_FRAME_BORDER_HIGHLIGHT_IN__ 380
+#define __GO_UI_FRAME_BORDER_HIGHLIGHT_OUT__ 381
+#define __GO_UI_FRAME_BORDER_IN_BORDER__ 382
+#define __GO_UI_FRAME_BORDER_JUSTIFICATION__ 383
+#define __GO_UI_FRAME_BORDER_OUT_BORDER__ 384
+#define __GO_UI_FRAME_BORDER_ROUNDED__ 385
+#define __GO_UI_FRAME_BORDER_SHADOW_IN__ 386
+#define __GO_UI_FRAME_BORDER_SHADOW_OUT__ 387
+#define __GO_UI_FRAME_BORDER_TITLE__ 388
+#define __GO_UI_FRAME_BORDER_POSITION__ 389
+#define __GO_UI_FRAME_BORDER_STYLE__ 390
+#define __GO_UI_GROUP_NAME__ 391
+#define __GO_UI_TITLE_POSITION__ 392
+#define __GO_UI_TITLE_SCROLL__ 393
+#define __GO_UI_FRAME_BORDER_TYPE__ 394
+#define __GO_UI_SCROLLABLE__ 395
+#define __GO_COLOR_SET__ 396
+#define __GO_MARK_SIZES__ 397
+#define __GO_NUM_MARK_SIZES__ 398
+#define __GO_MARK_FOREGROUNDS__ 399
+#define __GO_NUM_MARK_FOREGROUNDS__ 400
+#define __GO_MARK_BACKGROUNDS__ 401
+#define __GO_NUM_MARK_BACKGROUNDS__ 402
 
 #endif /* !__GRAPHIC_OBJECT_PROPERTIES_H__ */
index 3e8aad3..c3ab68b 100755 (executable)
@@ -25,6 +25,8 @@ import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProp
 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_LABEL_MODE__;
 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_ORIENTATION__;
 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_INDEXES__;
+import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DETACHED_MODE__;
+import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DETACHED_POSITION__;
 
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
@@ -62,7 +64,10 @@ public class Datatip extends Text {
     Double ratio;
 
 
-    enum DatatipObjectProperty { TIP_DATA, TIP_BOX_MODE, TIP_LABEL_MODE, TIP_ORIENTATION, TIP_AUTOORIENTATION, TIP_DISPLAY_COMPONENTS, TIP_INTERP_MODE, TIP_DISPLAY_FNC, TIP_INDEXES};
+    enum DatatipObjectProperty { TIP_DATA, TIP_BOX_MODE, TIP_LABEL_MODE, TIP_ORIENTATION, TIP_AUTOORIENTATION, TIP_DISPLAY_COMPONENTS,
+                                 TIP_INTERP_MODE, TIP_DISPLAY_FNC, TIP_INDEXES, TIP_DETACHED_MODE, TIP_DETACHED_POSITION
+                               };
+
     enum TipOrientation { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, LEFT, RIGHT, TOP, BOTTOM;
 
                           /**
@@ -95,6 +100,9 @@ public class Datatip extends Text {
 
     TipOrientation currentOrientation;
 
+    Boolean detachedMode;
+    Double[] detachedPosition;
+
     /**
      * Initializes the datatip, setup format, orientation and mark.
      */
@@ -111,6 +119,9 @@ public class Datatip extends Text {
         fb.setDecimalFormatSymbols(decimalFormatSymbols);
         tipTextFormat = new UserDefinedFormat(fb, "%g", 1, 0);
 
+        detachedMode = false;
+        detachedPosition = new Double[] {0.0, 0.0, 0.0};
+
         tipBoxMode = true;
         tipLabelMode = true;
         interpMode = true;
@@ -120,6 +131,7 @@ public class Datatip extends Text {
         setVisible(true);
         setBox(true);
         setLineMode(true);
+        setLineStyle(3);
         setFillMode(true);
         setBackground(-2);
         setClipStateAsEnum(ClipStateType.OFF);
@@ -159,6 +171,10 @@ public class Datatip extends Text {
                 return DatatipObjectProperty.TIP_DISPLAY_FNC;
             case __GO_DATATIP_INDEXES__ :
                 return DatatipObjectProperty.TIP_INDEXES;
+            case __GO_DATATIP_DETACHED_MODE__:
+                return DatatipObjectProperty.TIP_DETACHED_MODE;
+            case __GO_DATATIP_DETACHED_POSITION__:
+                return DatatipObjectProperty.TIP_DETACHED_POSITION;
             default:
                 return super.getPropertyFromName(propertyName);
         }
@@ -188,6 +204,10 @@ public class Datatip extends Text {
                     return getDisplayFunction();
                 case TIP_INDEXES:
                     return getIndexes();
+                case TIP_DETACHED_MODE:
+                    return getDetachedMode();
+                case TIP_DETACHED_POSITION:
+                    return getDetachedPosition();
             }
         }
 
@@ -218,6 +238,10 @@ public class Datatip extends Text {
                     return setDisplayFunction((String) value);
                 case TIP_INDEXES:
                     return setIndexes((Double[]) value);
+                case TIP_DETACHED_MODE:
+                    return setDetachedMode((Boolean)value);
+                case TIP_DETACHED_POSITION:
+                    return setDetachedPosition((Double[])value);
             }
         }
 
@@ -499,6 +523,45 @@ public class Datatip extends Text {
     }
 
     /**
+     * @return detached mode
+     */
+    public Boolean getDetachedMode() {
+        return detachedMode;
+    }
+
+    /**
+     * Sets the detached mode, when true datatip position
+     * is given by detachedPosition.
+     * @param status true for enable detached mode
+     */
+    public UpdateStatus setDetachedMode(Boolean status) {
+        detachedMode = status;
+        return UpdateStatus.Success;
+    }
+
+    /**
+     * Position is only used when detachedMode is true.
+     * @return datatip detached position
+     */
+    public Double[] getDetachedPosition() {
+        return detachedPosition;
+    }
+
+    /**
+     * Sets the datatip detached position
+     * @param pos detached position
+     */
+    public UpdateStatus setDetachedPosition(Double[] pos) {
+        if (pos.length != 3) {
+            return UpdateStatus.Fail;
+        }
+        for (int i = 0; i < 3; ++i) {
+            detachedPosition[i] = pos[i];
+        }
+        return UpdateStatus.Success;
+    }
+
+    /**
      * @return Type as String
      */
     public Integer getType() {
index ac7f80d..189d56c 100755 (executable)
@@ -361,65 +361,67 @@ public class GraphicObjectProperties {
     public static final int __GO_DATATIP_BOX_MODE__ = 338;
     public static final int __GO_DATATIP_LABEL_MODE__ = 339;
     public static final int __GO_DATATIP_MARK__ = 340;
-    public static final int __GO_AMBIENTCOLOR__ = 341;
-    public static final int __GO_DIFFUSECOLOR__ = 342;
-    public static final int __GO_SPECULARCOLOR__ = 343;
-    public static final int __GO_COLOR_MATERIAL__ = 344;
-    public static final int __GO_MATERIAL_SHININESS__ = 345;
-    public static final int __GO_LIGHT__ = 346;
-    public static final int __GO_LIGHT_TYPE__ = 347;
-    public static final int __GO_DATATIPS__ = 348;
-    public static final int __GO_DATATIPS_COUNT__ = 349;
-    public static final int __GO_DATATIP_INDEXES__ = 350;
-    public static final int __GO_DATA_MODEL_DISPLAY_FUNCTION__ = 351;
-    public static final int __GO_DATA_MODEL_DISPLAY_FUNCTION_SIZE__ = 352;
-    public static final int __GO_RESIZE__ = 353;
-    public static final int __GO_TOOLBAR__ = 354;
-    public static final int __GO_TOOLBAR_VISIBLE__ = 355;
-    public static final int __GO_MENUBAR__ = 356;
-    public static final int __GO_MENUBAR_VISIBLE__ = 357;
-    public static final int __GO_INFOBAR_VISIBLE__ = 358;
-    public static final int __GO_DOCKABLE__ = 359;
-    public static final int __GO_LAYOUT__ = 360;
-    public static final int __GO_LAYOUT_SET__ = 361;
-    public static final int __GO_UI_TAB__ = 362;
-    public static final int __GO_UI_GRIDBAG_GRID__ = 363;
-    public static final int __GO_UI_GRIDBAG_WEIGHT__ = 364;
-    public static final int __GO_UI_GRIDBAG_FILL__ = 365;
-    public static final int __GO_UI_GRIDBAG_ANCHOR__ = 366;
-    public static final int __GO_UI_GRIDBAG_PADDING__ = 367;
-    public static final int __GO_UI_GRIDBAG_PREFERREDSIZE__ = 368;
-    public static final int __GO_UI_GRID_GRID__ = 369;
-    public static final int __GO_UI_GRID_PADDING__ = 370;
-    public static final int __GO_UI_BORDER_POSITION__ = 371;
-    public static final int __GO_UI_BORDER_PREFERREDSIZE__ = 372;
-    public static final int __GO_GRID_OPT_GRID__ = 373;
-    public static final int __GO_GRID_OPT_PADDING__ = 374;
-    public static final int __GO_BORDER_OPT_PADDING__ = 375;
-    public static final int __GO_UI_FRAME_BORDER__ = 376;
-    public static final int __GO_UI_FRAME_BORDER_COLOR__ = 377;
-    public static final int __GO_UI_FRAME_BORDER_HIGHLIGHT_IN__ = 378;
-    public static final int __GO_UI_FRAME_BORDER_HIGHLIGHT_OUT__ = 379;
-    public static final int __GO_UI_FRAME_BORDER_IN_BORDER__ = 380;
-    public static final int __GO_UI_FRAME_BORDER_JUSTIFICATION__ = 381;
-    public static final int __GO_UI_FRAME_BORDER_OUT_BORDER__ = 382;
-    public static final int __GO_UI_FRAME_BORDER_ROUNDED__ = 383;
-    public static final int __GO_UI_FRAME_BORDER_SHADOW_IN__ = 384;
-    public static final int __GO_UI_FRAME_BORDER_SHADOW_OUT__ = 385;
-    public static final int __GO_UI_FRAME_BORDER_TITLE__ = 386;
-    public static final int __GO_UI_FRAME_BORDER_POSITION__ = 387;
-    public static final int __GO_UI_FRAME_BORDER_STYLE__ = 388;
-    public static final int __GO_UI_GROUP_NAME__ = 389;
-    public static final int __GO_UI_TITLE_POSITION__ = 390;
-    public static final int __GO_UI_TITLE_SCROLL__ = 391;
-    public static final int __GO_UI_FRAME_BORDER_TYPE__ = 392;
-    public static final int __GO_UI_SCROLLABLE__ = 393;
-    public static final int __GO_COLOR_SET__ = 394;
-    public static final int __GO_MARK_SIZES__ = 395;
-    public static final int __GO_NUM_MARK_SIZES__ = 396;
-    public static final int __GO_MARK_FOREGROUNDS__ = 397;
-    public static final int __GO_NUM_MARK_FOREGROUNDS__ = 398;
-    public static final int __GO_MARK_BACKGROUNDS__ = 399;
-    public static final int __GO_NUM_MARK_BACKGROUNDS__ = 400;
+    public static final int __GO_DATATIP_DETACHED_MODE__ = 341;
+    public static final int __GO_DATATIP_DETACHED_POSITION__ = 342;
+    public static final int __GO_AMBIENTCOLOR__ = 343;
+    public static final int __GO_DIFFUSECOLOR__ = 344;
+    public static final int __GO_SPECULARCOLOR__ = 345;
+    public static final int __GO_COLOR_MATERIAL__ = 346;
+    public static final int __GO_MATERIAL_SHININESS__ = 347;
+    public static final int __GO_LIGHT__ = 348;
+    public static final int __GO_LIGHT_TYPE__ = 349;
+    public static final int __GO_DATATIPS__ = 350;
+    public static final int __GO_DATATIPS_COUNT__ = 351;
+    public static final int __GO_DATATIP_INDEXES__ = 352;
+    public static final int __GO_DATA_MODEL_DISPLAY_FUNCTION__ = 353;
+    public static final int __GO_DATA_MODEL_DISPLAY_FUNCTION_SIZE__ = 354;
+    public static final int __GO_RESIZE__ = 355;
+    public static final int __GO_TOOLBAR__ = 356;
+    public static final int __GO_TOOLBAR_VISIBLE__ = 357;
+    public static final int __GO_MENUBAR__ = 358;
+    public static final int __GO_MENUBAR_VISIBLE__ = 359;
+    public static final int __GO_INFOBAR_VISIBLE__ = 360;
+    public static final int __GO_DOCKABLE__ = 361;
+    public static final int __GO_LAYOUT__ = 362;
+    public static final int __GO_LAYOUT_SET__ = 363;
+    public static final int __GO_UI_TAB__ = 364;
+    public static final int __GO_UI_GRIDBAG_GRID__ = 365;
+    public static final int __GO_UI_GRIDBAG_WEIGHT__ = 366;
+    public static final int __GO_UI_GRIDBAG_FILL__ = 367;
+    public static final int __GO_UI_GRIDBAG_ANCHOR__ = 368;
+    public static final int __GO_UI_GRIDBAG_PADDING__ = 369;
+    public static final int __GO_UI_GRIDBAG_PREFERREDSIZE__ = 370;
+    public static final int __GO_UI_GRID_GRID__ = 371;
+    public static final int __GO_UI_GRID_PADDING__ = 372;
+    public static final int __GO_UI_BORDER_POSITION__ = 373;
+    public static final int __GO_UI_BORDER_PREFERREDSIZE__ = 374;
+    public static final int __GO_GRID_OPT_GRID__ = 375;
+    public static final int __GO_GRID_OPT_PADDING__ = 376;
+    public static final int __GO_BORDER_OPT_PADDING__ = 377;
+    public static final int __GO_UI_FRAME_BORDER__ = 378;
+    public static final int __GO_UI_FRAME_BORDER_COLOR__ = 379;
+    public static final int __GO_UI_FRAME_BORDER_HIGHLIGHT_IN__ = 380;
+    public static final int __GO_UI_FRAME_BORDER_HIGHLIGHT_OUT__ = 381;
+    public static final int __GO_UI_FRAME_BORDER_IN_BORDER__ = 382;
+    public static final int __GO_UI_FRAME_BORDER_JUSTIFICATION__ = 383;
+    public static final int __GO_UI_FRAME_BORDER_OUT_BORDER__ = 384;
+    public static final int __GO_UI_FRAME_BORDER_ROUNDED__ = 385;
+    public static final int __GO_UI_FRAME_BORDER_SHADOW_IN__ = 386;
+    public static final int __GO_UI_FRAME_BORDER_SHADOW_OUT__ = 387;
+    public static final int __GO_UI_FRAME_BORDER_TITLE__ = 388;
+    public static final int __GO_UI_FRAME_BORDER_POSITION__ = 389;
+    public static final int __GO_UI_FRAME_BORDER_STYLE__ = 390;
+    public static final int __GO_UI_GROUP_NAME__ = 391;
+    public static final int __GO_UI_TITLE_POSITION__ = 392;
+    public static final int __GO_UI_TITLE_SCROLL__ = 393;
+    public static final int __GO_UI_FRAME_BORDER_TYPE__ = 394;
+    public static final int __GO_UI_SCROLLABLE__ = 395;
+    public static final int __GO_COLOR_SET__ = 396;
+    public static final int __GO_MARK_SIZES__ = 397;
+    public static final int __GO_NUM_MARK_SIZES__ = 398;
+    public static final int __GO_MARK_FOREGROUNDS__ = 399;
+    public static final int __GO_NUM_MARK_FOREGROUNDS__ = 400;
+    public static final int __GO_MARK_BACKGROUNDS__ = 401;
+    public static final int __GO_NUM_MARK_BACKGROUNDS__ = 402;
 
 }
index ab5bf32..a69679f 100755 (executable)
@@ -379,6 +379,8 @@ __GO_DATATIP_DISPLAY_FNC__
 __GO_DATATIP_BOX_MODE__
 __GO_DATATIP_LABEL_MODE__
 __GO_DATATIP_MARK__
+__GO_DATATIP_DETACHED_MODE__
+__GO_DATATIP_DETACHED_POSITION__
 
 __GO_AMBIENTCOLOR__
 __GO_DIFFUSECOLOR__
diff --git a/scilab/modules/graphics/demos/datatips/datatip_detach.sce b/scilab/modules/graphics/demos/datatips/datatip_detach.sce
new file mode 100644 (file)
index 0000000..8a86b77
--- /dev/null
@@ -0,0 +1,54 @@
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+//
+// Copyright (C) 2016 - Scilab Enterprises
+// Copyright (C) 2016 - Caio SOUZA
+//
+// This file is hereby licensed under the terms of the GNU GPL v2.0,
+// pursuant to article 5.3.4 of the CeCILL v.2.1.
+// This file was originally licensed under the terms of the CeCILL v2.1,
+// and continues to be available under such terms.
+// For more information, see the COPYING file which you should have received
+// along with this program.
+
+function datatip_detach_demo()
+    h = scf(100001);
+    clf(h,"reset");
+    fig=gcf();
+
+    title(_("Datatips detached from curve"),"fontsize",3);
+
+    x = 0:0.1:3*%pi;
+    y = sin(x);
+    subplot(2,1,1);
+    plot2d(x,y);
+    e=gce();
+    p=e.children(1);
+    l = int(length(x) / 4);
+    d1 = datatipCreate(p, l);
+    d1.foreground = 3
+    d2 = datatipCreate(p, 2*l);
+    d2.foreground = 2
+    d3 = datatipCreate(p, 3*l);
+    d3.foreground = 5;
+
+    subplot(2,1,2);
+    plot2d(x,y);
+    e=gce();
+    p=e.children(1);
+    l = int(length(x) / 4);
+    d1 = datatipCreate(p, l);
+    d1.detached_position = [ 0.5,-0.5,0];
+    d1.foreground = 3
+    d1.line_style = 7
+    d2 = datatipCreate(p, 2*l);
+    d2.detached_position = [ 3.4,0.5,0];
+    d2.foreground = 2
+    d2.line_style = 3
+    d3 = datatipCreate(p, 3*l);
+    d3.detached_position = [ 8,-0.5,0];
+    d3.foreground = 5;
+    d3.line_style = 1;
+endfunction
+
+datatip_detach_demo()
+clear datatip_detach_demo
index 0343144..496647a 100644 (file)
@@ -13,7 +13,8 @@ demopath = get_absolute_file_path("datatips.dem.gateway.sce");
 
 subdemolist=[
 _("2D curves")              , "datatip1.sce";
-_("3D curve")               , "datatip2.sce"];
+_("3D curve")               , "datatip2.sce";
+_("Detach")                 , "datatip_detach.sce"];
 
 
 subdemolist(:,2) = demopath + subdemolist(:,2);
index 4f017aa..c360270 100644 (file)
                 </listitem>
             </varlistentry>
             <varlistentry>
+                <term>detached_position: </term>
+                <listitem>
+                    <para>
+                        This field sets the position to draw the datatip text box. When its value  is <literal>[]</literal>
+                        the datatip text box is drawn attached to its anchor point in the polyline, if its value is a 3-components
+                        vector <literal>[x y z]</literal>, the text box is drawn in the given position.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
                 <term>font_foreground: </term>
                 <listitem>
                     <para>
                 </listitem>
             </varlistentry>
             <varlistentry>
+                <term>line_style: </term>
+                <listitem>
+                    <para>
+                        This field contains the <literal>line_style</literal> used in the line linking
+                        the datatip anchor point to its text box when <literal>detached_position</literal>
+                        is set.
+                    </para>
+                    <para>See 
+                        <literal>
+                            <link linkend="polyline_properties">polyline_properties</link>
+                        </literal>
+                        help page.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
                 <term>mark_mode: </term>
                 <listitem>
                     <para>See 
index a3cc1ed..9651273 100755 (executable)
@@ -608,9 +608,11 @@ function %h_p(h)
             "auto_orientation = "+sci2exp(h.auto_orientation)
             "interp_mode = "+sci2exp(h.interp_mode)
             "display_function = "+sci2exp(h.display_function)
+            "detached_position = "+sci2exp(h.detached_position)
             "font_foreground = "+string(h.font_foreground)
             "foreground = "+string(h.foreground)
             "background = "+string(h.background)
+            "line_style = "+string(h.line_style)
             "mark_mode = "+sci2exp(h.mark_mode)
             "mark_style = "+sci2exp(h.mark_style)
             "mark_size_unit = "+sci2exp(h.mark_size_unit)
index 838ac4a..86d7232 100755 (executable)
@@ -226,6 +226,7 @@ static getHashTableCouple propertyGetTable[] =
     {"box_mode", get_tip_box_mode_property},
     {"label_mode", get_tip_label_mode_property},
     {"display_function", get_tip_disp_function_property},
+    {"detached_position", get_tip_detached_property},
     {"ambient_color", get_ambient_color_property},
     {"diffuse_color", get_diffuse_color_property},
     {"specular_color", get_specular_color_property},
index 50a9376..5746c4d 100755 (executable)
@@ -225,6 +225,7 @@ static setHashTableCouple propertySetTable[] =
     {"box_mode", set_tip_box_mode_property},
     {"label_mode", set_tip_label_mode_property},
     {"display_function", set_tip_disp_function_property},
+    {"detached_position", set_tip_detached_property},
     {"ambient_color", set_ambient_color_property},
     {"diffuse_color", set_diffuse_color_property},
     {"specular_color", set_specular_color_property},
index d132a92..05a9f00 100755 (executable)
@@ -171,6 +171,7 @@ GRAPHICS_IMPEXP void* get_tip_interp_mode_property(void* _pvCtx, int iObjUID);
 GRAPHICS_IMPEXP void* get_tip_box_mode_property(void* _pvCtx, int iObjUID);
 GRAPHICS_IMPEXP void* get_tip_label_mode_property(void* _pvCtx, int iObjUID);
 GRAPHICS_IMPEXP void* get_tip_disp_function_property(void* _pvCtx, int iObjUID);
+GRAPHICS_IMPEXP void* get_tip_detached_property(void* _pvCtx, int iObjUID);
 GRAPHICS_IMPEXP void* get_ambient_color_property(void* _pvCtx, int iObjUID);
 GRAPHICS_IMPEXP void* get_diffuse_color_property(void* _pvCtx, int iObjUID);
 GRAPHICS_IMPEXP void* get_specular_color_property(void* _pvCtx, int iObjUID);
index 8a15277..e61bef2 100755 (executable)
@@ -203,3 +203,27 @@ void* get_tip_disp_function_property(void* _pvCtx, int iObjUID)
 
     return sciReturnString(tip_disp_function);
 }
+
+void* get_tip_detached_property(void* _pvCtx, int iObjUID)
+{
+    int isDetached = 0;
+    int *piDetached = &isDetached;
+    getGraphicObjectProperty(iObjUID, __GO_DATATIP_DETACHED_MODE__, jni_bool, (void **)&piDetached);
+
+    if (piDetached == NULL)
+    {
+        Scierror(999, _("'%s' property does not exist for this handle.\n"), "detached_position");
+        return NULL;
+    }
+
+    if (!isDetached)
+    {
+        return sciReturnEmptyMatrix();
+    }
+    else
+    {
+        double *detached_pos = NULL;
+        getGraphicObjectProperty(iObjUID, __GO_DATATIP_DETACHED_POSITION__, jni_double_vector, (void **)&detached_pos);
+        return sciReturnRowVector(detached_pos, 3);
+    }
+}
index 548dc61..2def651 100755 (executable)
@@ -173,6 +173,7 @@ int set_tip_interp_mode_property(void* _pvCtx, int iObj, void* _pvData, int valu
 int set_tip_box_mode_property(void* _pvCtx, int iObj, void* _pvData, int valueType, int nbRow, int nbCol);
 int set_tip_label_mode_property(void* _pvCtx, int iObj, void* _pvData, int valueType, int nbRow, int nbCol);
 int set_tip_disp_function_property(void* _pvCtx, int iObj, void* _pvData, int valueType, int nbRow, int nbCol);
+int set_tip_detached_property(void* _pvCtx, int iObj, void* _pvData, int valueType, int nbRow, int nbCol);
 int set_ambient_color_property(void* _pvCtx, int iObj, void* _pvData, int valueType, int nbRow, int nbCol);
 int set_diffuse_color_property(void* _pvCtx, int iObj, void* _pvData, int valueType, int nbRow, int nbCol);
 int set_specular_color_property(void* _pvCtx, int iObj, void* _pvData, int valueType, int nbRow, int nbCol);
index 277ea34..63bf0bf 100755 (executable)
@@ -285,3 +285,37 @@ int set_tip_disp_function_property(void* _pvCtx, int iObj, void* _pvData, int va
         return SET_PROPERTY_ERROR;
     }
 }
+
+int set_tip_detached_property(void* _pvCtx, int iObj, void* _pvData, int valueType, int nbRow, int nbCol)
+{
+    BOOL status = FALSE;
+    int isDetached = nbRow * nbCol != 0;
+    double* detached_position = NULL;
+    if (valueType != sci_matrix)
+    {
+        Scierror(999, _("Wrong type for '%s' property: Matrix expected.\n"), "detached_position");
+        return SET_PROPERTY_ERROR;
+    }
+
+
+    if (nbRow * nbCol != 3 && isDetached)
+    {
+        Scierror(999, _("Wrong size for '%s' property: Matrix with length 3 or [] expected.\n"), "detached_position");
+        return SET_PROPERTY_ERROR;
+    }
+    status = setGraphicObjectProperty(iObj, __GO_DATATIP_DETACHED_MODE__, &isDetached, jni_bool, 1);
+    if (isDetached)
+    {
+        status = setGraphicObjectProperty(iObj, __GO_DATATIP_DETACHED_POSITION__, _pvData, jni_double_vector, 3);
+    }
+
+    if (status == TRUE)
+    {
+        return SET_PROPERTY_SUCCEED;
+    }
+    else
+    {
+        Scierror(999, _("'%s' property does not exist for this handle.\n"), "detached_position");
+        return SET_PROPERTY_ERROR;
+    }
+}
index d860211..11150d5 100644 (file)
@@ -419,6 +419,9 @@ struct DatatipHandle
         m.emplace_back("mark_size_unit", std::vector<int>({SAVE_LOAD, __GO_MARK_SIZE_UNIT__, jni_int}));
         m.emplace_back("mark_foreground", std::vector<int>({SAVE_LOAD, __GO_MARK_FOREGROUND__, jni_int}));
         m.emplace_back("mark_background", std::vector<int>({SAVE_LOAD, __GO_MARK_BACKGROUND__, jni_int}));
+        m.emplace_back("detached_position", std::vector<int>({SAVE_LOAD, __GO_DATATIP_DETACHED_POSITION__, jni_double_vector, -1, -3}));
+        m.emplace_back("detached_mode", std::vector<int>({SAVE_LOAD, __GO_DATATIP_DETACHED_MODE__, jni_bool}));
+        m.emplace_back("line_style", std::vector<int>({SAVE_LOAD, __GO_LINE_STYLE__, jni_int}));
 
         //@ don't care
 
index 4ca7209..dfc321b 100755 (executable)
@@ -186,7 +186,7 @@ public class DrawerVisitor implements Visitor, Drawer, GraphicView {
         this.legendDrawer = new LegendDrawer(this);
         this.fecDrawer = new FecDrawer(this);
         this.colorMapTextureDataProvider = new ColorMapTextureDataProvider();
-        this.datatipTextDrawer = new DatatipTextDrawer(canvas.getTextureManager());
+        this.datatipTextDrawer = new DatatipTextDrawer(canvas);
 
         visitorMap.put(figure.getIdentifier(), this);
     }
index 4619186..16e9d99 100644 (file)
 
 package org.scilab.modules.renderer.JoGLView.datatip;
 
+import org.scilab.forge.scirenderer.Canvas;
+import org.scilab.forge.scirenderer.buffers.ElementsBuffer;
+import org.scilab.forge.scirenderer.shapes.appearance.Appearance;
+import org.scilab.forge.scirenderer.shapes.geometry.DefaultGeometry;
+import org.scilab.forge.scirenderer.shapes.geometry.Geometry;
+import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
 import org.scilab.forge.scirenderer.DrawingTools;
 import org.scilab.forge.scirenderer.SciRendererException;
 import org.scilab.forge.scirenderer.texture.AnchorPosition;
@@ -36,6 +42,8 @@ import org.scilab.modules.renderer.JoGLView.util.ScaleUtils;
 import java.awt.Dimension;
 import org.scilab.modules.renderer.JoGLView.text.TextManager;
 
+import java.nio.FloatBuffer;
+
 /**
  * Datatip text drawer
  *
@@ -44,8 +52,18 @@ import org.scilab.modules.renderer.JoGLView.text.TextManager;
 
 public class DatatipTextDrawer extends TextManager {
 
-    public DatatipTextDrawer(TextureManager textureManager) {
-        super(textureManager);
+    ElementsBuffer lineBuffer;
+    Canvas canvas;
+    public DatatipTextDrawer(Canvas canvas) {
+        super(canvas.getTextureManager());
+        this.canvas = canvas;
+        lineBuffer = canvas.getBuffersManager().createElementsBuffer();
+    }
+
+    @Override
+    public void disposeAll() {
+        super.disposeAll();
+        canvas.getBuffersManager().dispose(lineBuffer);
     }
 
     /**
@@ -91,93 +109,104 @@ public class DatatipTextDrawer extends TextManager {
         double r = datatip.getMarkStyle() == 11 ? 1.0 : 2.0;
         finalSize -= (finalSize >= 2.0) ? r : 0.0;
 
-        Vector3d delta = new Vector3d(finalSize, finalSize, 0);
-        /* set up the text position according to the datatip orientation*/
-        if (datatip.isAutoOrientationEnabled()) {
-            int autopos = getAutoOrientation(datatip);
-            if (autopos != -1) {
-                Vector3d cp = cornerPositions[0], d = delta, p;
-                if (autopos == 2 || autopos == 3) {
-                    cp = cp.minus(textBoxVectors[1]);
-                    d = d.setY(-finalSize);
-                }
-                if (autopos == 0 || autopos == 2) {
-                    cp = cp.minus(textBoxVectors[0]);
-                    d = d.setX(-finalSize);
-                }
+        if (!datatip.getDetachedMode()) {
+            Vector3d delta = new Vector3d(finalSize, finalSize, 0);
+            /* set up the text position according to the datatip orientation*/
+            if (datatip.isAutoOrientationEnabled()) {
+                int autopos = getAutoOrientation(datatip);
+                if (autopos != -1) {
+                    Vector3d cp = cornerPositions[0], d = delta, p;
+                    if (autopos == 2 || autopos == 3) {
+                        cp = cp.minus(textBoxVectors[1]);
+                        d = d.setY(-finalSize);
+                    }
+                    if (autopos == 0 || autopos == 2) {
+                        cp = cp.minus(textBoxVectors[0]);
+                        d = d.setX(-finalSize);
+                    }
 
-                p = projection.unproject(cp.plus(textBoxVectors[0]).plus(textBoxVectors[1]));
-                Vector3d ucp = projection.unproject(cp);
-                if (p.getX() < -1 || p.getX() > 1 || p.getY() < -1 || p.getY() > 1 || ucp.getX() < -1 || ucp.getX() > 1 || ucp.getY() < -1 || ucp.getY() > 1) {
-                    autopos = -1;
-                } else {
-                    cornerPositions[0] = cp;
-                    delta = d;
+                    p = projection.unproject(cp.plus(textBoxVectors[0]).plus(textBoxVectors[1]));
+                    Vector3d ucp = projection.unproject(cp);
+                    if (p.getX() < -1 || p.getX() > 1 || p.getY() < -1 || p.getY() > 1 || ucp.getX() < -1 || ucp.getX() > 1 || ucp.getY() < -1 || ucp.getY() > 1) {
+                        autopos = -1;
+                    } else {
+                        cornerPositions[0] = cp;
+                        delta = d;
+                    }
                 }
-            }
 
-            if (autopos == -1) {
-                Vector3d position = projection.unproject(cornerPositions[0].minus(textBoxVectors[0]).plus(textBoxVectors[1]));
-                if (position.getX() >= -1 && position.getX() <= 1 && position.getY() >= -1 && position.getY() <= 1) {
-                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
-                    delta = delta.setX(-finalSize);
-                } else {
-                    position = projection.unproject(cornerPositions[0].plus(textBoxVectors[0]).minus(textBoxVectors[1]));
+                if (autopos == -1) {
+                    Vector3d position = projection.unproject(cornerPositions[0].minus(textBoxVectors[0]).plus(textBoxVectors[1]));
                     if (position.getX() >= -1 && position.getX() <= 1 && position.getY() >= -1 && position.getY() <= 1) {
-                        cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
-                        delta = delta.setY(-finalSize);
+                        cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+                        delta = delta.setX(-finalSize);
                     } else {
-                        position = projection.unproject(cornerPositions[0].minus(textBoxVectors[0]).minus(textBoxVectors[1]));
+                        position = projection.unproject(cornerPositions[0].plus(textBoxVectors[0]).minus(textBoxVectors[1]));
                         if (position.getX() >= -1 && position.getX() <= 1 && position.getY() >= -1 && position.getY() <= 1) {
                             cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
-                            cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
-                            delta = delta.setX(-finalSize);
                             delta = delta.setY(-finalSize);
+                        } else {
+                            position = projection.unproject(cornerPositions[0].minus(textBoxVectors[0]).minus(textBoxVectors[1]));
+                            if (position.getX() >= -1 && position.getX() <= 1 && position.getY() >= -1 && position.getY() <= 1) {
+                                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+                                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+                                delta = delta.setX(-finalSize);
+                                delta = delta.setY(-finalSize);
+                            }
                         }
                     }
                 }
+            } else {
+                if (datatip.getOrientation() == 2 || datatip.getOrientation() == 3) {
+                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+                    delta = delta.setY(-finalSize);
+                }
+                if (datatip.getOrientation() == 0 || datatip.getOrientation() == 2) {
+                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+                    delta = delta.setX(-finalSize);
+                }
+                if (datatip.getOrientation() == 4) {
+                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
+                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1].times(0.5));
+                    delta = delta.setY(0);
+                    delta = delta.setX(Math.sqrt(2) * (-finalSize));
+                }
+                if (datatip.getOrientation() == 5) {
+                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1].times(0.5));
+                    delta = delta.setY(0);
+                    delta = delta.setX(Math.sqrt(2) * finalSize);
+                }
+                if (datatip.getOrientation() == 6) {
+                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0].times(0.5));
+                    delta = delta.setX(0);
+                    delta = delta.setY(Math.sqrt(2) * finalSize);
+                }
+                if (datatip.getOrientation() == 7) {
+                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0].times(0.5));
+                    cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
+                    delta = delta.setX(0);
+                    delta = delta.setY(Math.sqrt(2) * (-finalSize));
+                }
             }
-        } else {
-            if (datatip.getOrientation() == 2 || datatip.getOrientation() == 3) {
-                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
-                delta = delta.setY(-finalSize);
-            }
-            if (datatip.getOrientation() == 0 || datatip.getOrientation() == 2) {
-                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
-                delta = delta.setX(-finalSize);
-            }
-            if (datatip.getOrientation() == 4) {
-                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0]);
-                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1].times(0.5));
-                delta = delta.setY(0);
-                delta = delta.setX(Math.sqrt(2) * (-finalSize));
-            }
-            if (datatip.getOrientation() == 5) {
-                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1].times(0.5));
-                delta = delta.setY(0);
-                delta = delta.setX(Math.sqrt(2) * finalSize);
-            }
-            if (datatip.getOrientation() == 6) {
-                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0].times(0.5));
-                delta = delta.setX(0);
-                delta = delta.setY(Math.sqrt(2) * finalSize);
-            }
-            if (datatip.getOrientation() == 7) {
-                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[0].times(0.5));
-                cornerPositions[0] = cornerPositions[0].minus(textBoxVectors[1]);
-                delta = delta.setX(0);
-                delta = delta.setY(Math.sqrt(2) * (-finalSize));
-            }
-        }
-
-        cornerPositions[0] = cornerPositions[0].plus(delta);
-        cornerPositions[1] = cornerPositions[1].plus(delta);
 
+            cornerPositions[0] = cornerPositions[0].plus(delta);
+            cornerPositions[1] = cornerPositions[1].plus(delta);
+        }
+        Vector3d p = cornerPositions[0];
+
+        if (datatip.getDetachedMode()) {
+            p = projection.project(calculateDetachedPoint(datatip));
+            drawDetachedLine(drawingTools, colorMap, datatip, calculateDetachedLine(p, cornerPositions, textBoxVectors, finalSize));
+            Vector3d diff = cornerPositions[1].minus(cornerPositions[0]);
+            cornerPositions[0] = p;
+            cornerPositions[1] = p.plus(diff);
+        }
         /* The Text object's rotation direction convention is opposite to the standard one, its angle is expressed in radians. */
-        drawingTools.draw(texture, AnchorPosition.LOWER_LEFT, cornerPositions[0], -180.0 * datatip.getFontAngle() / Math.PI);
-
+        drawingTools.draw(texture, AnchorPosition.LOWER_LEFT, p, -180.0 * datatip.getFontAngle() / Math.PI);
         drawingTools.getTransformationManager().useSceneCoordinate();
 
+
+
         /* Compute the corners of the text's bounding box in window coordinates */
         Vector3d[] projCorners;
         if (datatip.getTextBoxMode() == 2) {
@@ -193,6 +222,52 @@ public class DatatipTextDrawer extends TextManager {
         datatip.setCorners(coordinates);
     }
 
+    public void drawDetachedLine(final DrawingTools drawingTools, final ColorMap colorMap, final Datatip datatip, Vector3d[] pos) throws SciRendererException {
+        DefaultGeometry geom = new DefaultGeometry();
+
+        geom.setLineDrawingMode(Geometry.LineDrawingMode.SEGMENTS);
+        geom.setFillDrawingMode(Geometry.FillDrawingMode.NONE);
+        geom.setFaceCullingMode(Geometry.FaceCullingMode.BOTH);
+        Appearance appearance = new Appearance();
+        appearance.setLineColor(ColorFactory.createColor(colorMap, datatip.getLine().getColor()));
+
+        appearance.setLinePattern(datatip.getLineStyleAsEnum().asPattern());
+
+        FloatBuffer vertices = FloatBuffer.allocate(6);
+        vertices.put(0, (float)pos[0].getX());
+        vertices.put(1, (float)pos[0].getY());
+        vertices.put(2, (float)pos[0].getZ());
+
+        vertices.put(3, (float)pos[1].getX());
+        vertices.put(4, (float)pos[1].getY());
+        vertices.put(5, (float)pos[1].getZ());
+        lineBuffer.setData(vertices, 3);
+        geom.setVertices(lineBuffer);
+
+        /* Draws in window coordinates */
+        //visitor.getDrawingTools().getTransformationManager().useWindowCoordinate();
+        drawingTools.draw(geom, appearance);
+        //visitor.getDrawingTools().getTransformationManager().useSceneCoordinate();
+    }
+
+    private Vector3d[] calculateDetachedLine(Vector3d pos, Vector3d[] corners, Vector3d[] textBox, double halfMarkSize) {
+        Vector3d p1 = pos;
+        Vector3d p0 = corners[0];
+        double dx = halfMarkSize;
+        double dy = halfMarkSize;
+
+        if (p1.getX() < corners[0].getX()) {
+            p1 = p1.plus(textBox[0]);
+            dx = -halfMarkSize;
+        }
+        if (p1.getY() < corners[0].getY()) {
+            p1 = p1.plus(textBox[1]);
+            dy = -halfMarkSize;
+        }
+        p0 = p0.plus(new Vector3d(new double[] {dx, dy, 0.0}));
+        return new Vector3d[] {p0, p1};
+    }
+
     /**
      * Update the given datatip text corners
      * @param datatip the given datatip
@@ -285,6 +360,16 @@ public class DatatipTextDrawer extends TextManager {
         return new Vector3d(v.getX() * factors[0][0] + factors[1][0], v.getY() * factors[0][1] + factors[1][1], v.getZ() * factors[0][2] + factors[1][2]);
     }
 
+    public static Vector3d calculateDetachedPoint(Datatip datatip) {
+        Axes axes = (Axes) GraphicController.getController().getObjectFromId(datatip.getParentAxes());
+        double[][] factors = axes.getScaleTranslateFactors();
+        boolean[] logFlags = new boolean[] {axes.getXAxisLogFlag(), axes.getYAxisLogFlag(), axes.getZAxisLogFlag()};
+        Double[] dp = datatip.getDetachedPosition();
+        Vector3d v = ScaleUtils.applyLogScale(new Vector3d(dp[0], dp[1], dp[2]), logFlags);
+
+        return new Vector3d(v.getX() * factors[0][0] + factors[1][0], v.getY() * factors[0][1] + factors[1][1], v.getZ() * factors[0][2] + factors[1][2]);
+    }
+
     private static int getAutoOrientation(Datatip datatip) {
         final double[] dataX = (double[]) PolylineData.getDataX(datatip.getParent());
         int index = datatip.getIndexes();