From 53e3a25840acd79b51475137cd9615d52b5684cd Mon Sep 17 00:00:00 2001 From: Marc Englund Date: Wed, 12 Jun 2013 11:34:33 +0300 Subject: [PATCH] DebugWindow resize/move improved, fixes #11937 (also implements shift-resize and alt-move, improves bounds-check) Change-Id: Ic313e545940a6073e30171a610f6d02c38a90037 --- .../VAADIN/themes/base/debug/debug.scss | 24 +- .../client/debug/internal/VDebugWindow.java | 346 ++++++++++-------- 2 files changed, 218 insertions(+), 152 deletions(-) diff --git a/WebContent/VAADIN/themes/base/debug/debug.scss b/WebContent/VAADIN/themes/base/debug/debug.scss index d71575c818..168c666923 100644 --- a/WebContent/VAADIN/themes/base/debug/debug.scss +++ b/WebContent/VAADIN/themes/base/debug/debug.scss @@ -73,6 +73,25 @@ color: $maincolor; font-size: 13px; + + .v-debugwindow-handle { + position: absolute; + bottom: 0; + background-color: #fff; + -moz-opacity: 0; + -webkit-opacity: 0; + opacity: 0; + z-index: 1000; + } + .v-debugwindow-handle-sw { + width: 7px; + height: 7px; + } + .v-debugwindow-handle-se { + right: 0; + width: 14px; + height: 14px; + } } .v-debugwindow:hover { -moz-opacity: 1; @@ -95,8 +114,7 @@ .v-debugwindow-head { text-align: right; - cursor: move; - bakcground-color: transparent; + background-color: transparent; } .v-debugwindow-tabs { @@ -143,6 +161,8 @@ box-shadow: 0px 0px 7px 0 rgba(55,55,55,0.6); min-height: 1.5em; + + padding-left: 5px; } .v-debugwindow-button { diff --git a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java index 6c05658fe1..48d7b9974a 100644 --- a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java +++ b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java @@ -37,6 +37,7 @@ import com.google.gwt.http.client.UrlBuilder; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.storage.client.Storage; +import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.Event.NativePreviewHandler; @@ -77,9 +78,11 @@ public final class VDebugWindow extends VOverlay { // drag this far before actually moving window protected static final int MOVE_TRESHOLD = 5; - // window minimum sizes + // window minimum height, minimum width comes from tab+controls protected static final int MIN_HEIGHT = 40; - protected static final int HANDLE_SIZE = 5; + + // size of area to grab for resize; bottom corners size in CSS + protected static final int HANDLE_SIZE = 7; // identifiers for localStorage private static final String STORAGE_PREFIX = "v-debug-"; @@ -129,14 +132,9 @@ public final class VDebugWindow extends VOverlay { // sections protected ArrayList
sections = new ArrayList
(); - // handles resizing (mouse) - protected ResizeHandler resizeHandler = new ResizeHandler(); - protected HandlerRegistration resizeReg = null; - protected HandlerRegistration resizeReg2 = null; - - // handles window movement (mouse) - protected MoveHandler moveHandler = new MoveHandler(); - protected HandlerRegistration moveReg = null; + // handles resize/move + protected HandlerRegistration mouseDownHandler = null; + protected HandlerRegistration mouseMoveHandler = null; // TODO this class should really be a singleton. static VDebugWindow instance; @@ -187,6 +185,8 @@ public final class VDebugWindow extends VOverlay { head.add(sectionHead); window.add(content); + addHandles(); + head.setStylePrimaryName(STYLENAME_HEAD); tabs.setStylePrimaryName(STYLENAME_TABS); controls.setStylePrimaryName(STYLENAME_CONTROLS); @@ -221,14 +221,31 @@ public final class VDebugWindow extends VOverlay { Style s = content.getElement().getStyle(); s.setOverflow(Overflow.AUTO); - // window can be moved by dragging header - moveReg = head.addDomHandler(moveHandler, MouseDownEvent.getType()); - // resize from all sides and corners - resizeReg = content.addDomHandler(resizeHandler, + // move/resize + final MouseHandler mouseHandler = new MouseHandler(); + mouseDownHandler = this.addDomHandler(mouseHandler, MouseDownEvent.getType()); - // changes mouse pointer when hovering sides / corners - resizeReg2 = content.addDomHandler(resizeHandler, + mouseMoveHandler = this.addDomHandler(mouseHandler, MouseMoveEvent.getType()); + + } + + /** + * Adds dummy handle elements to the bottom corners that might have + * scrollbars that interfere with resizing on some platforms. + * + * @since 7.1 + */ + private void addHandles() { + Element el = DOM.createDiv(); + el.setClassName(VDebugWindow.STYLENAME + "-handle " + + VDebugWindow.STYLENAME + "-handle-sw"); + content.getElement().appendChild(el); + + el = DOM.createDiv(); + el.setClassName(VDebugWindow.STYLENAME + "-handle " + + VDebugWindow.STYLENAME + "-handle-se"); + content.getElement().appendChild(el); } /** @@ -248,10 +265,11 @@ public final class VDebugWindow extends VOverlay { */ public void close() { // TODO disable even more - if (resizeReg != null) { - resizeReg.removeHandler(); - resizeReg2.removeHandler(); - moveReg.removeHandler(); + if (mouseDownHandler != null) { + mouseDownHandler.removeHandler(); + mouseMoveHandler.removeHandler(); + mouseDownHandler = null; + mouseMoveHandler = null; } Highlight.hideAll(); hide(); @@ -446,6 +464,16 @@ public final class VDebugWindow extends VOverlay { content.setHeight(fullH + "px"); } + applyBounds(x, y); + } + + private void applyBounds() { + int x = getPopupLeft(); + int y = getPopupTop(); + applyBounds(x, y); + } + + private void applyBounds(int x, int y) { // bounds check if (x < 0) { x = 0; @@ -462,6 +490,7 @@ public final class VDebugWindow extends VOverlay { } setPopupPosition(x, y); + } /** @@ -635,8 +664,8 @@ public final class VDebugWindow extends VOverlay { */ static String getTimingTooltip(int sinceStart, int sinceReset) { String title = formatDuration(sinceStart) + " since start"; - title += ", " + formatDuration(sinceReset) + " since timer reset"; - title += " @ " + title += ", " + formatDuration(sinceReset) + " since timer reset"; + title += " @ " + DateTimeFormat.getFormat("HH:mm:ss.SSS").format(new Date()); return title; } @@ -861,31 +890,120 @@ public final class VDebugWindow extends VOverlay { } /** - * Handler for moving window. + * Handler for resizing and moving window, also updates cursor on mousemove. * * @since 7.1 * @author Vaadin Ltd */ - protected class MoveHandler implements MouseDownHandler, + protected class MouseHandler implements MouseMoveHandler, MouseDownHandler, NativePreviewHandler { - HandlerRegistration handler; + boolean resizeLeft; + boolean resizeRight; + boolean resizeUp; + boolean resizeDown; + boolean move; + boolean sizing; + + // dragging stopped, remove handler on next event + boolean stop; + + HandlerRegistration dragHandler; + int startX; int startY; + int startW; + int startH; int startTop; int startLeft; - // moving stopped, remove handler on next event - boolean stop; + @Override + public void onMouseMove(MouseMoveEvent event) { + if (null == dragHandler) { + updateResizeFlags(event); + updateCursor(); + } + } + + @Override + public void onMouseDown(MouseDownEvent event) { + if (event.getNativeButton() != NativeEvent.BUTTON_LEFT + || dragHandler != null) { + return; + } + updateResizeFlags(event); + if (sizing || move) { + // some os/browsers don't pass events trough scrollbars; hide + // while dragging (esp. important for resize from right/bottom) + content.getElement().getStyle().setOverflow(Overflow.HIDDEN); + + startX = event.getClientX(); + startY = event.getClientY(); + + startW = content.getOffsetWidth(); + startH = content.getOffsetHeight(); + + startTop = getPopupTop(); + startLeft = getPopupLeft(); + + dragHandler = Event.addNativePreviewHandler(this); + + event.preventDefault(); + + stop = false; + } + + } @Override public void onPreviewNativeEvent(NativePreviewEvent event) { if (event.getTypeInt() == Event.ONMOUSEMOVE && !stop && hasMoved(event.getNativeEvent())) { + int dx = event.getNativeEvent().getClientX() - startX; int dy = event.getNativeEvent().getClientY() - startY; - setPopupPosition(startLeft + dx, startTop + dy); + if (sizing) { + int minWidth = tabs.getOffsetWidth() + + controls.getOffsetWidth(); + + if (resizeLeft) { + int w = startW - dx; + if (w < minWidth) { + w = minWidth; + dx = startW - minWidth; + } + content.setWidth(w + "px"); + setPopupPosition(startLeft + dx, getPopupTop()); + + } else if (resizeRight) { + int w = startW + dx; + if (w < minWidth) { + w = minWidth; + } + content.setWidth(w + "px"); + } + if (resizeUp) { + int h = startH - dy; + if (h < MIN_HEIGHT) { + h = MIN_HEIGHT; + dy = startH - MIN_HEIGHT; + } + content.setHeight(h + "px"); + setPopupPosition(getPopupLeft(), startTop + dy); + + } else if (resizeDown) { + int h = startH + dy; + if (h < MIN_HEIGHT) { + h = MIN_HEIGHT; + } + content.setHeight(h + "px"); + + } + + } else if (move) { + setPopupPosition(startLeft + dx, startTop + dy); + } event.cancel(); } else if (event.getTypeInt() == Event.ONMOUSEUP) { @@ -902,12 +1020,23 @@ public final class VDebugWindow extends VOverlay { } else if (stop) { stop = false; - handler.removeHandler(); - handler = null; + dragHandler.removeHandler(); + dragHandler = null; + sizing = false; + move = false; + + // restore scrollbars + content.getElement().getStyle().setOverflow(Overflow.AUTO); + + updateCursor(); + applyBounds(); readPositionAndSize(); writeStoredState(); + + event.cancel(); } + } private boolean hasMoved(NativeEvent event) { @@ -915,75 +1044,8 @@ public final class VDebugWindow extends VOverlay { || Math.abs(startY - event.getClientY()) > MOVE_TRESHOLD; } - @Override - public void onMouseDown(MouseDownEvent event) { - if (handler == null) { - handler = Event.addNativePreviewHandler(MoveHandler.this); - } - startX = event.getClientX(); - startY = event.getClientY(); - startLeft = getPopupLeft(); - startTop = getPopupTop(); - stop = false; - event.preventDefault(); - } - - } - - /** - * Handler for resizing window. - * - * @since 7.1 - * @author Vaadin Ltd - */ - protected class ResizeHandler implements MouseDownHandler, - MouseMoveHandler, NativePreviewHandler { - - boolean resizeLeft; - boolean resizeRight; - boolean resizeUp; - boolean resizeDown; - - boolean sizing; - - HandlerRegistration dragHandler; - - int startX; - int startY; - int startW; - int startH; - int startTop; - int startLeft; - - @Override - public void onMouseDown(MouseDownEvent event) { - sizing = updateResizeFlags(event); - - if (sizing) { - startX = event.getClientX(); - startY = event.getClientY(); - - startW = content.getOffsetWidth(); - startH = content.getOffsetHeight(); - - startTop = getPopupTop(); - startLeft = getPopupLeft(); - - dragHandler = Event.addNativePreviewHandler(this); - - event.preventDefault(); - } - - } - - @Override - public void onMouseMove(MouseMoveEvent event) { - updateResizeFlags(event); - updateCursor(); - } - private void updateCursor() { - Element c = content.getElement(); + Element c = getElement(); if (resizeLeft) { if (resizeUp) { c.getStyle().setCursor(Cursor.NW_RESIZE); @@ -1004,70 +1066,54 @@ public final class VDebugWindow extends VOverlay { c.getStyle().setCursor(Cursor.N_RESIZE); } else if (resizeDown) { c.getStyle().setCursor(Cursor.S_RESIZE); + } else if (move) { + c.getStyle().setCursor(Cursor.MOVE); } else { c.getStyle().setCursor(Cursor.AUTO); } } - private boolean updateResizeFlags(MouseEvent event) { + protected void updateResizeFlags(MouseEvent event) { + if (event.isShiftKeyDown()) { + // resize from lower right + resizeUp = false; + resizeLeft = false; + resizeRight = true; + resizeDown = true; + move = false; + sizing = true; + return; + + } else if (event.isAltKeyDown()) { + // move it + move = true; + resizeUp = false; + resizeLeft = false; + resizeRight = false; + resizeDown = false; + sizing = false; + return; + } + Element c = getElement(); int w = c.getOffsetWidth(); - int h = c.getOffsetHeight() - head.getOffsetHeight(); + int h = c.getOffsetHeight(); int x = event.getRelativeX(c); - int y = event.getRelativeY(c) - head.getOffsetHeight(); - - resizeLeft = x < HANDLE_SIZE; - resizeRight = x > (w - HANDLE_SIZE); - resizeUp = y < HANDLE_SIZE; - resizeDown = y > (h - HANDLE_SIZE); - - return resizeLeft || resizeRight || resizeUp || resizeDown; - - } + int y = event.getRelativeY(c); - @Override - public void onPreviewNativeEvent(NativePreviewEvent event) { - if (event.getTypeInt() == Event.ONMOUSEMOVE) { - - int dx = event.getNativeEvent().getClientX() - startX; - int dy = event.getNativeEvent().getClientY() - startY; + resizeLeft = x < HANDLE_SIZE && y > tabs.getOffsetHeight(); + resizeRight = (x > (w - HANDLE_SIZE) && y > tabs.getOffsetHeight()) + || (x > (w - 2 * HANDLE_SIZE) && y > (h - 2 * HANDLE_SIZE)); + resizeUp = y > tabs.getOffsetHeight() + && y < tabs.getOffsetHeight() + HANDLE_SIZE; + resizeDown = y > (h - HANDLE_SIZE) + || (x > (w - 2 * HANDLE_SIZE) && y > (h - 2 * HANDLE_SIZE)); - int minw = tabs.getOffsetWidth() + controls.getOffsetWidth(); - if (resizeLeft) { - int w = startW - dx; - if (w >= minw) { - content.setWidth(w + "px"); - setPopupPosition(startLeft + dx, getPopupTop()); - } - } else if (resizeRight) { - int w = startW + dx; - if (w >= minw) { - content.setWidth(w + "px"); - } - } - if (resizeUp) { - int h = startH - dy; - if (h >= MIN_HEIGHT) { - content.setHeight(h + "px"); - setPopupPosition(getPopupLeft(), startTop + dy); - } - } else if (resizeDown) { - int h = startH + dy; - if (h >= MIN_HEIGHT) { - content.setHeight(h + "px"); - } - } + move = !resizeDown && !resizeLeft && !resizeRight && !resizeUp + && y < head.getOffsetHeight(); - } else if (event.getTypeInt() == Event.ONMOUSEUP) { - dragHandler.removeHandler(); - dragHandler = null; - content.getElement().getStyle().setCursor(Cursor.AUTO); - sizing = false; - readPositionAndSize(); - writeStoredState(); - } + sizing = resizeLeft || resizeRight || resizeUp || resizeDown; - event.cancel(); } } -- 2.39.5