Issue #1638 Made string rendering always look right despite extent proportions so it is never warped. Moved dataURI map creation to DataURIUtil. Fixed double dispose of controls in VizDisplayPane, also made resize non interface method.

Amend: Fixed menu mix up and making sure perspective bar is on by default

Change-Id: I0c19e5fbf0f0d29cdca0f63afb33ca964a145b94

Former-commit-id: 1d3c378dde [formerly c8fcaf06d1 [formerly b91b706701] [formerly 1d3c378dde [formerly 53e42aa3925399271cc3ad4ee964476ddffc8eb6]]]
Former-commit-id: c8fcaf06d1 [formerly b91b706701]
Former-commit-id: c8fcaf06d1
Former-commit-id: 259982918f
This commit is contained in:
Max Schenkelberg 2013-04-18 17:52:22 -05:00
parent ff8e51282d
commit 22b44301a6
14 changed files with 171 additions and 115 deletions

View file

@ -83,6 +83,23 @@ public class DrawableString extends AbstractDrawableObject {
*/ */
public RGB boxColor; public RGB boxColor;
public DrawableString(DrawableString that) {
this.basics.alpha = that.basics.alpha;
this.basics.color = that.basics.color;
this.basics.xOrColors = that.basics.xOrColors;
this.setCoordinates(that.basics.x, that.basics.y, that.basics.z);
this.text = that.text;
this.colors = that.colors;
this.font = that.font;
this.horizontalAlignment = that.horizontalAlignment;
this.verticallAlignment = that.verticallAlignment;
this.magnification = that.magnification;
this.rotation = that.rotation;
this.textStyle = that.textStyle;
this.shadowColor = that.shadowColor;
this.boxColor = that.boxColor;
}
/** /**
* Construct parameters with text, splits by newline, all text will be drawn * Construct parameters with text, splits by newline, all text will be drawn
* with color "color" * with color "color"

View file

@ -90,12 +90,6 @@ public interface IDisplayPane {
*/ */
public abstract void refresh(); public abstract void refresh();
/**
* Perform the resize computations
*
*/
public abstract void resize();
/** /**
* Get bounds of pane * Get bounds of pane
* *

View file

@ -41,7 +41,7 @@
id="com.raytheon.uf.viz.personalities.cave.openPerspective"> id="com.raytheon.uf.viz.personalities.cave.openPerspective">
</dynamic> </dynamic>
</menu> </menu>
<menu id="cave.browsers" <menu id="browsers"
label="Data Browsers"> label="Data Browsers">
<!-- Place holder for data browsers --> <!-- Place holder for data browsers -->
</menu> </menu>

View file

@ -237,12 +237,23 @@ public class VizWorkbenchAdvisor extends WorkbenchAdvisor {
* (org.eclipse.ui.application.IWorkbenchWindowConfigurer) * (org.eclipse.ui.application.IWorkbenchWindowConfigurer)
*/ */
@Override @Override
public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( public final WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(
IWorkbenchWindowConfigurer configurer) { IWorkbenchWindowConfigurer configurer) {
if (createdMenus == false) { if (createdMenus == false) {
createdMenus = true; createdMenus = true;
createDynamicMenus(); createDynamicMenus();
} }
return createNewWindowAdvisor(configurer);
}
/**
* Create a new {@link WorkbenchWindowAdvisor}
*
* @param configurer
* @return
*/
protected WorkbenchWindowAdvisor createNewWindowAdvisor(
IWorkbenchWindowConfigurer configurer) {
return new VizWorkbenchWindowAdvisor(configurer); return new VizWorkbenchWindowAdvisor(configurer);
} }

View file

@ -78,7 +78,7 @@ public class VizWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); IWorkbenchWindowConfigurer configurer = getWindowConfigurer();
configurer.setShowProgressIndicator(true); configurer.setShowProgressIndicator(true);
configurer.setInitialSize(new Point(1024, 768)); configurer.setInitialSize(new Point(1024, 768));
// Don't show perspective bar if running a specific perspective? configurer.setShowPerspectiveBar(true);
configurer.setShowCoolBar(true); configurer.setShowCoolBar(true);
configurer.setShowStatusLine(true); configurer.setShowStatusLine(true);

View file

@ -57,4 +57,15 @@
commandId="com.raytheon.uf.viz.productbrowser.productBrowser"> commandId="com.raytheon.uf.viz.productbrowser.productBrowser">
</handler> </handler>
</extension> </extension>
<extension
point="org.eclipse.ui.menus">
<menuContribution
locationURI="menu:browsers">
<command
commandId="com.raytheon.uf.viz.productbrowser.productBrowser"
label="Product Browser"
style="push">
</command>
</menuContribution>
</extension>
</plugin> </plugin>

View file

@ -123,7 +123,8 @@ import com.sun.opengl.util.j2d.TextRenderer;
* Feb 14, 2013 1616 bsteffen Add option for interpolation of colormap * Feb 14, 2013 1616 bsteffen Add option for interpolation of colormap
* parameters, disable colormap * parameters, disable colormap
* interpolation by default. * interpolation by default.
* * Apr 18, 2013 1638 mschenke Made string rendering always occur in canvas space so
* strings are always readable despite extent
* *
* </pre> * </pre>
* *
@ -1200,6 +1201,12 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
new GLFont(java.awt.Font.MONOSPACED, 14.0f, new GLFont(java.awt.Font.MONOSPACED, 14.0f,
new Style[] { Style.BOLD })); new Style[] { Style.BOLD }));
} }
// Set swap interval to 1 refresh
gl.setSwapInterval(1);
// Set swap interval to 0 refresh (disables vsync)
gl.setSwapInterval(0);
releaseContext(); releaseContext();
} }
@ -1811,6 +1818,24 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
return; return;
} }
double glScaleX = getScaleX();
double glScaleY = getScaleY();
double stringScaleX = 1.0;
double stringScaleY = 1.0;
Rectangle bounds = getBounds();
List<DrawableString> copy = new ArrayList<DrawableString>(
parameters.size());
for (DrawableString dString : parameters) {
// Convert strings into canvas location
dString = new DrawableString(dString);
double[] screen = targetView.gridToScreen(new double[] {
dString.basics.x, dString.basics.y, dString.basics.z },
this);
dString.setCoordinates(bounds.x + screen[0], bounds.y + screen[1]);
copy.add(dString);
}
parameters = copy;
// TODO if parameters has different fonts we should ensure that all // TODO if parameters has different fonts we should ensure that all
// strings with the same font are rendered in a group, otherwise this // strings with the same font are rendered in a group, otherwise this
// function ends up calling begin/end rendering lots which slows it down // function ends up calling begin/end rendering lots which slows it down
@ -1822,10 +1847,12 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
gl.glMatrixMode(GL.GL_MODELVIEW); gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glPushMatrix(); gl.glPushMatrix();
try { try {
IExtent extent = targetView.getExtent();
gl.glEnable(GL.GL_BLEND); gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL.GL_TEXTURE_2D); gl.glEnable(GL.GL_TEXTURE_2D);
gl.glScaled(1.0, -1.0, 1.0); gl.glTranslated(extent.getMinX(), extent.getMinY(), 0);
gl.glScaled(glScaleX, -glScaleY, 1.0);
// This loop just draws the box or a blank rectangle. // This loop just draws the box or a blank rectangle.
for (DrawableString dString : parameters) { for (DrawableString dString : parameters) {
@ -1841,14 +1868,13 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
if (verticalAlignment == VerticalAlignment.MIDDLE if (verticalAlignment == VerticalAlignment.MIDDLE
&& dString.getText().length > 1) { && dString.getText().length > 1) {
Rectangle2D totalBounds = getStringsBounds(dString); Rectangle2D totalBounds = getStringsBounds(dString);
double totalHeight = totalBounds.getHeight() double totalHeight = totalBounds.getHeight();
* getScaleY();
yPos -= totalHeight * .5; yPos -= totalHeight * .5;
verticalAlignment = VerticalAlignment.TOP; verticalAlignment = VerticalAlignment.TOP;
} }
double scaleX = getScaleX(); double scaleX = stringScaleX;
double scaleY = getScaleY(); double scaleY = stringScaleY;
if (dString.rotation != 0.0) { if (dString.rotation != 0.0) {
rotatedPoint = getUpdatedCoordinates( rotatedPoint = getUpdatedCoordinates(
@ -1885,14 +1911,14 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
backgroundColor.blue / 255.0, alpha); backgroundColor.blue / 255.0, alpha);
} }
double width = textBounds.getWidth() * scaleX; double width = textBounds.getWidth();
double height = textBounds.getHeight() * scaleY; double height = textBounds.getHeight();
double diff = height + textBounds.getY() * scaleY; double diff = height + textBounds.getY();
double x1 = xy[0] - scaleX; double x1 = xy[0] - scaleX;
double y1 = xy[1] - scaleY - diff; double y1 = xy[1] - scaleY - diff;
double x2 = xy[0] + width + scaleX; double x2 = xy[0] + width;
double y2 = xy[1] + height - diff + scaleY; double y2 = xy[1] + height - diff;
gl.glRectd(x1, y2, x2, y1); gl.glRectd(x1, y2, x2, y1);
@ -1912,9 +1938,9 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
gl.glPolygonMode(GL.GL_BACK, GL.GL_FILL); gl.glPolygonMode(GL.GL_BACK, GL.GL_FILL);
if (verticalAlignment == VerticalAlignment.TOP) { if (verticalAlignment == VerticalAlignment.TOP) {
yPos += textBounds.getHeight() * getScaleY(); yPos += textBounds.getHeight();
} else { } else {
yPos -= textBounds.getHeight() * getScaleY(); yPos -= textBounds.getHeight();
} }
} }
@ -1978,15 +2004,15 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
* magnification; * magnification;
} }
float scaleX = (float) (getScaleX() * fontPercentage); float scaleX = (float) (stringScaleX * fontPercentage);
float scaleY = (float) (getScaleY() * fontPercentage); float scaleY = (float) (stringScaleY * fontPercentage);
double yPos = dString.basics.y; double yPos = dString.basics.y;
VerticalAlignment verticalAlignment = dString.verticallAlignment; VerticalAlignment verticalAlignment = dString.verticallAlignment;
if (verticalAlignment == VerticalAlignment.MIDDLE if (verticalAlignment == VerticalAlignment.MIDDLE
&& dString.getText().length > 1) { && dString.getText().length > 1) {
Rectangle2D totalBounds = getStringsBounds(dString); Rectangle2D totalBounds = getStringsBounds(dString);
double totalHeight = totalBounds.getHeight() * getScaleY(); double totalHeight = totalBounds.getHeight();
yPos -= totalHeight * .5; yPos -= totalHeight * .5;
verticalAlignment = VerticalAlignment.TOP; verticalAlignment = VerticalAlignment.TOP;
} }
@ -2068,9 +2094,9 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
textRenderer.draw3D(string, xy[0], xy[1], 0.0f, scaleY); textRenderer.draw3D(string, xy[0], xy[1], 0.0f, scaleY);
} }
if (verticalAlignment == VerticalAlignment.TOP) { if (verticalAlignment == VerticalAlignment.TOP) {
yPos += textBounds.getHeight() * getScaleY(); yPos += textBounds.getHeight();
} else { } else {
yPos -= textBounds.getHeight() * getScaleY(); yPos -= textBounds.getHeight();
} }
} }
@ -2120,10 +2146,8 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
double width = textBounds.getWidth(); double width = textBounds.getWidth();
double height = textBounds.getHeight(); double height = textBounds.getHeight();
double adjustedWidth = width * getScaleX(); double offset = (height + textBounds.getY());
double adjustedHeight = height * getScaleY(); // double adjustedOffset = (height + textBounds.getY()) * getScaleY();
double adjustedOffset = (height + textBounds.getY()) * getScaleY();
double canvasX1 = 0.0; double canvasX1 = 0.0;
double canvasY1 = 0.0; double canvasY1 = 0.0;
@ -2133,22 +2157,22 @@ public class GLTarget extends AbstractGraphicsTarget implements IGLTarget {
canvasX1 = xPos; canvasX1 = xPos;
} else if (horizontalAlignment == HorizontalAlignment.CENTER) { } else if (horizontalAlignment == HorizontalAlignment.CENTER) {
canvasX1 = xPos - adjustedWidth / 2; canvasX1 = xPos - width / 2;
} else if (horizontalAlignment == HorizontalAlignment.RIGHT) { } else if (horizontalAlignment == HorizontalAlignment.RIGHT) {
canvasX1 = xPos - adjustedWidth; canvasX1 = xPos - width;
} }
// Calculate the vertical point based on alignment // Calculate the vertical point based on alignment
if (verticalAlignment == VerticalAlignment.BOTTOM) { // normal if (verticalAlignment == VerticalAlignment.BOTTOM) { // normal
canvasY1 = yPos; canvasY1 = yPos;
} else if (verticalAlignment == VerticalAlignment.MIDDLE) { } else if (verticalAlignment == VerticalAlignment.MIDDLE) {
canvasY1 = yPos + adjustedHeight / 2; canvasY1 = yPos + height / 2;
} else if (verticalAlignment == VerticalAlignment.TOP) { } else if (verticalAlignment == VerticalAlignment.TOP) {
canvasY1 = yPos + adjustedHeight; canvasY1 = yPos + height;
} }
canvasY1 -= (adjustedOffset); canvasY1 -= (offset);
return new float[] { (float) canvasX1, (float) -canvasY1 }; return new float[] { (float) canvasX1, (float) -canvasY1 };
} }

View file

@ -1,5 +1,5 @@
org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP = true org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP = true
org.eclipse.ui/presentationFactoryId=com.raytheon.viz.ui.personalities.awips.VizPresentationFactory org.eclipse.ui/presentationFactoryId=com.raytheon.uf.viz.personalities.cave.presentation.VizPresentationFactory
org.eclipse.ui/KEY_CONFIGURATION_ID=com.raytheon.viz.ui.awips.scheme org.eclipse.ui/KEY_CONFIGURATION_ID=com.raytheon.viz.ui.awips.scheme
org.eclipse.ui.editors/lineNumberRuler=true org.eclipse.ui.editors/lineNumberRuler=true
org.eclipse.core.resources/snapshots.operations=2147483647 org.eclipse.core.resources/snapshots.operations=2147483647

View file

@ -27,6 +27,8 @@ import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.ui.IPerspectiveDescriptor; import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.PlatformUI; import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
import org.eclipse.ui.application.WorkbenchWindowAdvisor;
import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.contexts.IContextService; import org.eclipse.ui.contexts.IContextService;
@ -91,6 +93,12 @@ public class AWIPSWorkbenchAdvisor extends VizWorkbenchAdvisor {
"-perspective") != null; "-perspective") != null;
} }
@Override
protected WorkbenchWindowAdvisor createNewWindowAdvisor(
IWorkbenchWindowConfigurer configurer) {
return new AWIPSWorkbenchWindowAdvisor(configurer, singlePerspective);
}
@Override @Override
public String getInitialWindowPerspectiveId() { public String getInitialWindowPerspectiveId() {
if (singlePerspective) { if (singlePerspective) {

View file

@ -198,17 +198,17 @@ public class VizDisplayPane implements IDisplayPane {
boolean enableContextualMenus) throws VizException { boolean enableContextualMenus) throws VizException {
this.container = container; this.container = container;
this.canvasComp = canvasComp; this.canvasComp = canvasComp;
this.canvasComp.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
VizDisplayPane.this.dispose();
}
});
// create the graphics adapter // create the graphics adapter
graphicsAdapter = display.getGraphicsAdapter(); graphicsAdapter = display.getGraphicsAdapter();
// create the canvas // create the canvas
this.canvas = graphicsAdapter.constrcutCanvas(canvasComp); this.canvas = graphicsAdapter.constrcutCanvas(canvasComp);
this.canvas.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
VizDisplayPane.this.dispose();
}
});
// set the renderable display // set the renderable display
setRenderableDisplay(display); setRenderableDisplay(display);
@ -400,10 +400,6 @@ public class VizDisplayPane implements IDisplayPane {
container.notifyRenderableDisplayChangedListeners(this, container.notifyRenderableDisplayChangedListeners(this,
renderableDisplay, DisplayChangeType.REMOVE); renderableDisplay, DisplayChangeType.REMOVE);
} }
if (canvas.isDisposed() == false) {
canvasComp.dispose();
}
} }
} }
@ -812,41 +808,21 @@ public class VizDisplayPane implements IDisplayPane {
/** /**
* Resize the pane * Resize the pane
*/ */
public void resize() { protected void resize() {
synchronized (this) { if (canvas == null || canvas.isDisposed()) {
return;
VizApp.runAsync(new Runnable() {
@Override
public void run() {
if (canvas == null || canvas.isDisposed()) {
return;
}
target.resize();
Rectangle clientArea = canvas.getClientArea();
if (renderableDisplay != null
&& renderableDisplay.getExtent() == null) {
scaleToClientArea();
zoomLevel = renderableDisplay
.recalcZoomLevel(renderableDisplay
.getDimensions());
refresh();
} else if (renderableDisplay != null) {
renderableDisplay.calcPixelExtent(clientArea);
zoomLevel = renderableDisplay
.recalcZoomLevel(renderableDisplay
.getDimensions());
refresh();
}
}
});
} }
target.resize();
Rectangle clientArea = canvas.getClientArea();
if (renderableDisplay != null) {
renderableDisplay.calcPixelExtent(clientArea);
zoomLevel = renderableDisplay.recalcZoomLevel(renderableDisplay
.getDimensions());
}
refresh();
} }
/* /*
@ -914,6 +890,13 @@ public class VizDisplayPane implements IDisplayPane {
return canvas; return canvas;
} }
/**
* @return the pane composite
*/
public Composite getComposite() {
return canvasComp;
}
/* /*
* (non-Javadoc) * (non-Javadoc)
* *

View file

@ -22,7 +22,6 @@ package com.raytheon.uf.common.dataplugin;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.persistence.Column; import javax.persistence.Column;
@ -75,6 +74,7 @@ import com.raytheon.uf.common.util.ConvertUtil;
* Removed unused getIdentfier(). * Removed unused getIdentfier().
* Mar 29, 2013 1638 mschenke Added methods for loading from data map and creating data map from * Mar 29, 2013 1638 mschenke Added methods for loading from data map and creating data map from
* dataURI fields * dataURI fields
* Apr 18, 2013 1638 mschenke Moved dataURI map generation into DataURIUtil
* *
* </pre> * </pre>
* *
@ -227,27 +227,9 @@ public abstract class PluginDataObject extends PersistableDataObject implements
* @throws PluginException * @throws PluginException
*/ */
public Map<String, Object> createDataURIMap() throws PluginException { public Map<String, Object> createDataURIMap() throws PluginException {
try { Map<String, Object> map = DataURIUtil.createDataURIMap(this);
Map<String, Object> map = new HashMap<String, Object>(); map.put("pluginName", getPluginName());
map.put("pluginName", getPluginName()); return map;
Field[] fields = DataURIUtil.getInstance().getAllDataURIFields(
getClass());
for (int i = 0; i < fields.length; ++i) {
String fieldName = PluginDataObject.getDataURIFieldName(
getClass(), i);
String[] nested = fieldName.split("[.]");
Object source = this;
if (nested.length > 0) {
for (int j = 0; j < nested.length; ++j) {
source = PropertyUtils.getProperty(source, nested[j]);
}
map.put(fieldName, source);
}
}
return map;
} catch (Exception e) {
throw new PluginException("Error constructing dataURI mapping", e);
}
} }
/** /**

View file

@ -27,6 +27,11 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.PluginException;
/** /**
* Utility class for working with dataURIs * Utility class for working with dataURIs
* *
@ -37,6 +42,7 @@ import java.util.Map;
* 10/07/2008 1533 bphillip Initial Checkin * 10/07/2008 1533 bphillip Initial Checkin
* Mar 29, 2013 1638 mschenke Added method for recursively getting all * Mar 29, 2013 1638 mschenke Added method for recursively getting all
* dataURI fields for an object * dataURI fields for an object
* Apr 18, 2013 1638 mschenke Moved dataURI map generation into here from PluginDataObject
* *
* </pre> * </pre>
* *
@ -70,6 +76,38 @@ public class DataURIUtil {
return instance; return instance;
} }
/**
* Creates a DataURI map for the specified object based on {@link DataURI}
* annotations
*
* @param object
* @return
* @throws PluginException
*/
public static Map<String, Object> createDataURIMap(Object object)
throws PluginException {
try {
Map<String, Object> map = new HashMap<String, Object>();
Field[] fields = DataURIUtil.getInstance().getAllDataURIFields(
object.getClass());
for (int i = 0; i < fields.length; ++i) {
String fieldName = PluginDataObject.getDataURIFieldName(
object.getClass(), i);
String[] nested = fieldName.split("[.]");
Object source = object;
if (nested.length > 0) {
for (int j = 0; j < nested.length && source != null; ++j) {
source = PropertyUtils.getProperty(source, nested[j]);
}
map.put(fieldName, source);
}
}
return map;
} catch (Exception e) {
throw new PluginException("Error constructing dataURI mapping", e);
}
}
public Field[] getAllDataURIFields(Class<?> obj) { public Field[] getAllDataURIFields(Class<?> obj) {
List<Field> fields = new ArrayList<Field>(); List<Field> fields = new ArrayList<Field>();
getAllDataURIFields(obj, fields); getAllDataURIFields(obj, fields);

View file

@ -347,7 +347,6 @@ public class ResourceBndlLoader implements Runnable { // extends Job {
} }
pane.setZoomLevel( mapDisplay.getZoomLevel() ); pane.setZoomLevel( mapDisplay.getZoomLevel() );
pane.resize();
pane.refresh(); pane.refresh();
return true; return true;

View file

@ -64,17 +64,6 @@ public class NCDisplayPane extends VizDisplayPane {
} }
// if the user has locked the zoom due to a size-of-image reprojection, we
// don't want to change the zoomLevel which is a done in VizPaneDisplay
// TODO : this seems to work except that resize() is called just after an rbd is
// loaded which, when size of image is selected, causes the image not to display.
//
public void resize() {
// if( !((NCMapDescriptor)getDescriptor()).getSuspendZoom() ) {
super.resize();
// }
}
// if we need to get rid of NCDisplayPane we can either go back // if we need to get rid of NCDisplayPane we can either go back
// to having a separate 'no-op' SuspendZoomHandler or add a check // to having a separate 'no-op' SuspendZoomHandler or add a check
// for the descriptor's suspend zoom flag in our NcPanHandler class // for the descriptor's suspend zoom flag in our NcPanHandler class