tmf: Show closest event tool tip when hovering over blank space
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / widgets / timegraph / widgets / TimeGraphControl.java
index 681f842cfe9559f99f691c04dbc64b760d656540..13438c859bb5988f436a8425747a0b4aa3555e21 100644 (file)
@@ -23,11 +23,13 @@ package org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jface.action.IStatusLineManager;
 import org.eclipse.jface.resource.JFaceResources;
 import org.eclipse.jface.resource.LocalResourceManager;
@@ -56,6 +58,8 @@ import org.eclipse.swt.events.TraverseListener;
 import org.eclipse.swt.events.TypedEvent;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
 import org.eclipse.swt.graphics.GC;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
@@ -119,6 +123,9 @@ public class TimeGraphControl extends TimeGraphBaseControl
 
     private static final int MAX_LABEL_LENGTH = 256;
 
+    private static final int PPI = 72; // points per inch
+    private static final int DPI = Display.getDefault().getDPI().y;
+
     /** Resource manager */
     private LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
 
@@ -132,6 +139,8 @@ public class TimeGraphControl extends TimeGraphBaseControl
     private boolean fIsInFocus = false;
     private boolean fMouseOverSplitLine = false;
     private int fGlobalItemHeight = CUSTOM_ITEM_HEIGHT;
+    private int fHeightAdjustment = 0;
+    private Map<Integer, Font> fFonts = new HashMap<>();
     private boolean fBlendSubPixelEvents = false;
     private int fMinimumItemWidth = 0;
     private int fTopIndex = 0;
@@ -158,7 +167,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
     private final Cursor fResizeCursor = Display.getDefault().getSystemCursor(SWT.CURSOR_IBEAM);
     private final Cursor fWaitCursor = Display.getDefault().getSystemCursor(SWT.CURSOR_WAIT);
     private final Cursor fZoomCursor = Display.getDefault().getSystemCursor(SWT.CURSOR_SIZEWE);
-    private final List<ViewerFilter> fFilters = new ArrayList<>();
+    private final List<@NonNull ViewerFilter> fFilters = new ArrayList<>();
     private MenuDetectEvent fPendingMenuDetectEvent = null;
     private boolean fGridLinesVisible = true;
     private Color fGridLineColor = Display.getDefault().getSystemColor(SWT.COLOR_GRAY);
@@ -197,6 +206,9 @@ public class TimeGraphControl extends TimeGraphBaseControl
     public void dispose() {
         super.dispose();
         fResourceManager.dispose();
+        for (Font font : fFonts.values()) {
+            font.dispose();
+        }
     }
 
     /**
@@ -956,6 +968,34 @@ public class TimeGraphControl extends TimeGraphBaseControl
         fTimeProvider.setStartFinishTimeNotify(time0, time1);
     }
 
+    /**
+     * Zoom vertically.
+     *
+     * @param zoomIn
+     *            true to zoom in, false to zoom out
+     * @since 2.0
+     */
+    public void verticalZoom(boolean zoomIn) {
+        if (zoomIn) {
+            fHeightAdjustment++;
+        } else {
+            fHeightAdjustment--;
+        }
+        fItemData.refreshData();
+        redraw();
+    }
+
+    /**
+     * Reset the vertical zoom to default.
+     *
+     * @since 2.0
+     */
+    public void resetVerticalZoom() {
+        fHeightAdjustment = 0;
+        fItemData.refreshData();
+        redraw();
+    }
+
     /**
      * Set the grid lines visibility. The default is true.
      *
@@ -1714,14 +1754,14 @@ public class TimeGraphControl extends TimeGraphBaseControl
         if (item.fEntry.hasTimeEvents()) {
             gc.setClipping(new Rectangle(nameSpace, 0, bounds.width - nameSpace, bounds.height));
             fillSpace(rect, gc, selected);
-            /*
-             * State rectangle is smaller than item bounds. Use a margin height
-             * of 3 pixels, keep at least 3 pixels for the state, but not more
-             * than the item height. Favor the top margin for the remainder.
-             */
-            int height = Math.min(rect.height, Math.max(3, rect.height - 6));
-            int margin = (rect.height - height + 1) / 2;
-            Rectangle stateRect = new Rectangle(rect.x, rect.y + margin, rect.width, height);
+
+            int margins = getMarginForHeight(rect.height);
+            int height = rect.height - margins;
+            int topMargin = (margins + 1) / 2;
+            Rectangle stateRect = new Rectangle(rect.x, rect.y + topMargin, rect.width, height);
+
+            /* Set the font for this item */
+            setFontForHeight(height, gc);
 
             long maxDuration = (timeProvider.getTimeSpace() == 0) ? Long.MAX_VALUE : 1 * (time1 - time0) / timeProvider.getTimeSpace();
             Iterator<ITimeEvent> iterator = entry.getTimeEventsIterator(time0, time1, maxDuration);
@@ -1916,6 +1956,9 @@ public class TimeGraphControl extends TimeGraphBaseControl
             return;
         }
 
+        int height = bounds.height - getMarginForHeight(bounds.height);
+        setFontForHeight(height, gc);
+
         int leftMargin = MARGIN + item.fLevel * EXPAND_SIZE;
         if (item.fHasChildren) {
             gc.setForeground(getColorScheme().getFgColorGroup(false, false));
@@ -2083,6 +2126,34 @@ public class TimeGraphControl extends TimeGraphBaseControl
         gc.drawLine(rect.x, midy, rect.x + rect.width, midy);
     }
 
+    private static int getMarginForHeight(int height) {
+        /*
+         * State rectangle is smaller than the item bounds when height is > 4.
+         * Don't use any margin if the height is below or equal that threshold.
+         * Use a maximum of 6 pixels for both margins, otherwise try to use 13
+         * pixels for the state height, but with a minimum margin of 1.
+         */
+        final int MARGIN_THRESHOLD = 4;
+        final int PREFERRED_HEIGHT = 13;
+        final int MIN_MARGIN = 1;
+        final int MAX_MARGIN = 6;
+        return height <= MARGIN_THRESHOLD ? 0 :
+            Math.max(Math.min(height - PREFERRED_HEIGHT, MAX_MARGIN), MIN_MARGIN);
+    }
+
+    private void setFontForHeight(int pixels, GC gc) {
+        /* convert font height from pixels to points */
+        int height = Math.max(pixels * PPI / DPI, 1);
+        Font font = fFonts.get(height);
+        if (font == null) {
+            FontData fontData = gc.getFont().getFontData()[0];
+            fontData.setHeight(height);
+            font = new Font(gc.getDevice(), fontData);
+            fFonts.put(height, font);
+        }
+        gc.setFont(font);
+    }
+
     @Override
     public void keyTraversed(TraverseEvent e) {
         if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)) {
@@ -2150,6 +2221,12 @@ public class TimeGraphControl extends TimeGraphBaseControl
                 }
             }
             idx = -1;
+        } else if ((e.character == '+' || e.character == '=') && ((e.stateMask & SWT.CTRL) != 0)) {
+            verticalZoom(true);
+        } else if (e.character == '-' && ((e.stateMask & SWT.CTRL) != 0)) {
+            verticalZoom(false);
+        } else if (e.character == '0' && ((e.stateMask & SWT.CTRL) != 0)) {
+            resetVerticalZoom();
         }
         if (idx >= 0) {
             selectItem(idx, false);
@@ -2554,42 +2631,53 @@ public class TimeGraphControl extends TimeGraphBaseControl
         if (fDragState != DRAG_NONE) {
             return;
         }
-        boolean zoomScroll = false;
+        boolean horizontalZoom = false;
         boolean horizontalScroll = false;
+        boolean verticalZoom = false;
         Point p = getParent().toControl(getDisplay().getCursorLocation());
         Point parentSize = getParent().getSize();
         if (p.x >= 0 && p.x < parentSize.x && p.y >= 0 && p.y < parentSize.y) {
             // over the parent control
             if (e.x > getSize().x) {
                 // over the vertical scroll bar
-                zoomScroll = false;
+                if ((e.stateMask & SWT.MODIFIER_MASK) == (SWT.SHIFT | SWT.CTRL)) {
+                    verticalZoom = true;
+                }
             } else if (e.y < 0) {
                 // over the time scale
-                zoomScroll = true;
+                horizontalZoom = true;
             } else if (e.y >= getSize().y) {
                 // over the horizontal scroll bar
                 if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.CTRL) {
-                    zoomScroll = true;
+                    horizontalZoom = true;
                 } else {
                     horizontalScroll = true;
                 }
             } else {
-                if (e.x < fTimeProvider.getNameSpace()) {
+                if ((e.stateMask & SWT.MODIFIER_MASK) == (SWT.SHIFT | SWT.CTRL)) {
+                    verticalZoom = true;
+                } else if (e.x < fTimeProvider.getNameSpace()) {
                     // over the name space
-                    zoomScroll = false;
+                    horizontalZoom = false;
                 } else {
                     // over the state area
                     if ((e.stateMask & SWT.MODIFIER_MASK) == SWT.CTRL) {
                         // over the state area, CTRL pressed
-                        zoomScroll = true;
+                        horizontalZoom = true;
                     } else {
                         // over the state area, CTRL not pressed
-                        zoomScroll = false;
+                        horizontalZoom = false;
                     }
                 }
             }
         }
-        if (zoomScroll && fTimeProvider.getTime0() != fTimeProvider.getTime1()) {
+        if (verticalZoom) {
+            if (e.count > 0) {
+                verticalZoom(true);
+            } else if (e.count < 0) {
+                verticalZoom(false);
+            }
+        } else if (horizontalZoom && fTimeProvider.getTime0() != fTimeProvider.getTime1()) {
             if (e.count > 0) {
                 zoom(true);
             } else if (e.count < 0) {
@@ -2741,7 +2829,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
     /**
      * @param filter The filter object to be attached to the view
      */
-    public void addFilter(ViewerFilter filter) {
+    public void addFilter(@NonNull ViewerFilter filter) {
         if (!fFilters.contains(filter)) {
             fFilters.add(filter);
         }
@@ -2750,7 +2838,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
     /**
      * @param filter The filter object to be attached to the view
      */
-    public void removeFilter(ViewerFilter filter) {
+    public void removeFilter(@NonNull ViewerFilter filter) {
         fFilters.remove(filter);
     }
 
@@ -2760,7 +2848,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
      * @return an array of viewer filters
      * @since 2.0
      */
-    public ViewerFilter[] getFilters() {
+    public @NonNull ViewerFilter[] getFilters() {
         return Iterables.toArray(fFilters, ViewerFilter.class);
     }
 
@@ -2771,7 +2859,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
      *            an array of viewer filters, or null
      * @since 2.0
      */
-    public void setFilters(ViewerFilter[] filters) {
+    public void setFilters(@NonNull ViewerFilter[] filters) {
         fFilters.clear();
         if (filters != null) {
             fFilters.addAll(Arrays.asList(filters));
@@ -2849,6 +2937,7 @@ public class TimeGraphControl extends TimeGraphBaseControl
             } else {
                 item.fItemHeight = fGlobalItemHeight;
             }
+            item.fItemHeight = Math.max(1, item.fItemHeight + fHeightAdjustment);
             itemMap.put(entry, item);
             if (entry.hasChildren()) {
                 Item oldItem = fItemMap.get(entry);
This page took 0.026956 seconds and 5 git commands to generate.