diff --git a/src/css/style.css b/src/css/style.css index 2a0a53d1..d855d70f 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -55,3 +55,7 @@ body { vertical-align: -2px; margin-left: 0; } + +.tooltip-shortcut { + color:gold; +} \ No newline at end of file diff --git a/src/css/toolbox-animated-preview.css b/src/css/toolbox-animated-preview.css index 06be9c51..2fb27cff 100644 --- a/src/css/toolbox-animated-preview.css +++ b/src/css/toolbox-animated-preview.css @@ -34,11 +34,11 @@ overflow:hidden; } -.tiled-frame-container { +.preview-container .background-image-frame-container { height: 100%; width: 100%; position: relative; - background-repeat : repeat; + background-position: center; } .display-fps { @@ -80,26 +80,56 @@ color : gold; } -.open-popup-preview-button { +.preview-contextual-actions { position : absolute; z-index: 500; right : 10px; top : 10px; - width : 24px; - height: 18px; - border : 2px solid white; - background : rgba(0,0,0,0.3); cursor : pointer; opacity: 0; transition: 0.3s opacity, 0.3s border-color; } -.minimap-container:hover .open-popup-preview-button { +.minimap-container:hover .preview-contextual-actions { opacity: 1; } +.original-size-button { + width : 18px; + height: 18px; + line-height: 18px; + margin: 0 5px; + + border: 2px solid white; + background-color: rgba(0, 0, 0, 0.3); + color: white; + + font-size: 10px; + font-weight: bold; + font-family: Tahoma; +} + +.original-size-button-enabled { + color: gold; + border-color: gold; +} + +.preview-contextual-action { + float: left; +} + +.open-popup-preview-button { + width : 18px; + height: 18px; + + border : 2px solid white; + background-image: url(../img/popup-preview-arrow-white.png); + background-color : rgba(0,0,0,0.3); +} + .open-popup-preview-button:hover { border-color: gold; + background-image: url(../img/popup-preview-arrow-gold.png); } diff --git a/src/css/tools.css b/src/css/tools.css index 7c262f12..c2a7be7c 100644 --- a/src/css/tools.css +++ b/src/css/tools.css @@ -251,10 +251,6 @@ padding-bottom: 5px; } -.tools-tooltip-shortcut { - color:gold; -} - .tools-tooltip-descriptor { color:#999; } diff --git a/src/img/popup-preview-arrow-gold.png b/src/img/popup-preview-arrow-gold.png new file mode 100644 index 00000000..dcf38951 Binary files /dev/null and b/src/img/popup-preview-arrow-gold.png differ diff --git a/src/img/popup-preview-arrow-white.png b/src/img/popup-preview-arrow-white.png new file mode 100644 index 00000000..27b78b98 Binary files /dev/null and b/src/img/popup-preview-arrow-white.png differ diff --git a/src/js/Events.js b/src/js/Events.js index 8b71a254..8f1ddeb4 100644 --- a/src/js/Events.js +++ b/src/js/Events.js @@ -30,6 +30,13 @@ var Events = { CLOSE_SETTINGS_DRAWER : 'CLOSE_SETTINGS_DRAWER', + /** + * Fire this event to update the opacity of the overlay frame. + * Payload : + * 1st argument : opacity {Number} between 0 and 1 + */ + SET_OVERLAY_OPACITY : 'SET_OVERLAY_OPACITY', + /** * The framesheet was reseted and is now probably drastically different. * Number of frames, content of frames, color used for the palette may have changed. diff --git a/src/js/controller/DrawingController.js b/src/js/controller/DrawingController.js index 2abd9379..e0562da2 100644 --- a/src/js/controller/DrawingController.js +++ b/src/js/controller/DrawingController.js @@ -62,8 +62,9 @@ $(window).resize($.proxy(this.startResizeTimer_, this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); - $.subscribe(Events.FRAME_SIZE_CHANGED, $.proxy(this.onFrameSizeChange_, this)); + $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); + $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); + $.subscribe(Events.SET_OVERLAY_OPACITY, this.onSetOverlayOpacity_.bind(this)); pskl.app.shortcutService.addShortcut('0', this.resetZoom_.bind(this)); pskl.app.shortcutService.addShortcut('+', this.increaseZoom_.bind(this, 1)); @@ -136,6 +137,10 @@ $.publish(Events.ZOOM_CHANGED); }; + ns.DrawingController.prototype.onSetOverlayOpacity_ = function (evt, opacity) { + this.overlayRenderer.setCanvasOpacity(opacity); + }; + /** * @private */ @@ -220,17 +225,24 @@ }; ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) { - var event = jQueryEvent.originalEvent; + var evt = jQueryEvent.originalEvent; // Ratio between wheelDeltaY (mousewheel event) and deltaY (wheel event) is -40 var delta; if (pskl.utils.UserAgent.isChrome) { - delta = event.wheelDeltaY; + delta = evt.wheelDeltaY; } else if (pskl.utils.UserAgent.isIE11) { - delta = event.wheelDelta; + delta = evt.wheelDelta; } else if (pskl.utils.UserAgent.isFirefox) { - delta = -40 * event.deltaY; + delta = -40 * evt.deltaY; } var modifier = Math.abs(delta / 120); + + if (pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey) { + modifier = modifier * 5; + // prevent default to prevent the default browser UI resize + evt.preventDefault(); + } + if (delta > 0) { this.increaseZoom_(modifier); } else if (delta < 0) { @@ -417,7 +429,7 @@ }; ns.DrawingController.prototype.getZoomStep_ = function () { - return this.calculateZoom_() / 10; + return Math.max(0.1, this.renderer.getZoom() / 15); }; ns.DrawingController.prototype.setZoom_ = function (zoom) { diff --git a/src/js/controller/preview/PopupPreviewController.js b/src/js/controller/preview/PopupPreviewController.js index 27d8febc..f93eda5b 100644 --- a/src/js/controller/preview/PopupPreviewController.js +++ b/src/js/controller/preview/PopupPreviewController.js @@ -33,7 +33,7 @@ pskl.utils.Event.addEventListener(this.popup, 'resize', this.onWindowResize_, this); pskl.utils.Event.addEventListener(this.popup, 'unload', this.onPopupClosed_, this); var container = this.popup.document.querySelector('.preview-container'); - this.renderer = new pskl.rendering.frame.TiledFrameRenderer($(container)); + this.renderer = new pskl.rendering.frame.BackgroundImageFrameRenderer($(container)); this.updateZoom_(); this.renderFlag = true; }; diff --git a/src/js/controller/preview/PreviewController.js b/src/js/controller/preview/PreviewController.js index 2dc7fd80..1cd282e8 100644 --- a/src/js/controller/preview/PreviewController.js +++ b/src/js/controller/preview/PreviewController.js @@ -15,12 +15,14 @@ this.fpsRangeInput = document.querySelector('#preview-fps'); this.fpsCounterDisplay = document.querySelector('#display-fps'); + this.openPopupPreview = document.querySelector('.open-popup-preview-button'); + this.originalSizeButton = document.querySelector('.original-size-button'); this.setFPS(Constants.DEFAULT.FPS); var frame = this.piskelController.getCurrentFrame(); - this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container); + this.renderer = new pskl.rendering.frame.BackgroundImageFrameRenderer(this.container); this.popupPreviewController = new ns.PopupPreviewController(piskelController); }; @@ -33,9 +35,11 @@ this.toggleOnionSkinEl = document.querySelector('.preview-toggle-onion-skin'); this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); - pskl.utils.Event.addEventListener('.open-popup-preview-button', 'click', this.onOpenPopupPreviewClick_, this); + pskl.utils.Event.addEventListener(this.openPopupPreview, 'click', this.onOpenPopupPreviewClick_, this); + pskl.utils.Event.addEventListener(this.originalSizeButton, 'click', this.onOriginalSizeButtonClick_, this); pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); + pskl.app.shortcutService.addShortcut('alt+1', this.onOriginalSizeButtonClick_.bind(this)); $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); @@ -47,6 +51,7 @@ this.updateZoom_(); this.updateOnionSkinPreview_(); + this.updateOriginalSizeButton_(); this.updateMaxFPS_(); this.updateContainerDimensions_(); }; @@ -55,6 +60,11 @@ this.popupPreviewController.open(); }; + ns.PreviewController.prototype.onOriginalSizeButtonClick_ = function () { + var isEnabled = pskl.UserSettings.get(pskl.UserSettings.ORIGINAL_SIZE_PREVIEW); + pskl.UserSettings.set(pskl.UserSettings.ORIGINAL_SIZE_PREVIEW, !isEnabled); + }; + ns.PreviewController.prototype.onUserSettingsChange_ = function (evt, name, value) { if (name == pskl.UserSettings.ONION_SKIN) { this.updateOnionSkinPreview_(); @@ -62,17 +72,21 @@ this.updateMaxFPS_(); } else { this.updateZoom_(); + this.updateOriginalSizeButton_(); this.updateContainerDimensions_(); } }; ns.PreviewController.prototype.updateOnionSkinPreview_ = function () { var enabledClassname = 'preview-toggle-onion-skin-enabled'; - if (pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN)) { - this.toggleOnionSkinEl.classList.add(enabledClassname); - } else { - this.toggleOnionSkinEl.classList.remove(enabledClassname); - } + var isEnabled = pskl.UserSettings.get(pskl.UserSettings.ONION_SKIN); + this.toggleOnionSkinEl.classList.toggle(enabledClassname, isEnabled); + }; + + ns.PreviewController.prototype.updateOriginalSizeButton_ = function () { + var enabledClassname = 'original-size-button-enabled'; + var isEnabled = pskl.UserSettings.get(pskl.UserSettings.ORIGINAL_SIZE_PREVIEW); + this.originalSizeButton.classList.toggle(enabledClassname, isEnabled); }; ns.PreviewController.prototype.updateMaxFPS_ = function () { @@ -82,8 +96,11 @@ }; ns.PreviewController.prototype.updateZoom_ = function () { - var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); - var zoom = isTiled ? 1 : this.calculateZoom_(); + var originalSizeEnabled = pskl.UserSettings.get(pskl.UserSettings.ORIGINAL_SIZE_PREVIEW); + var tiledPreviewEnabled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); + var useOriginalSize = originalSizeEnabled || tiledPreviewEnabled; + + var zoom = useOriginalSize ? 1 : this.calculateZoom_(); this.renderer.setZoom(zoom); this.setRenderFlag_(true); }; @@ -172,8 +189,9 @@ }; ns.PreviewController.prototype.updateContainerDimensions_ = function () { - var containerEl = this.container.get(0); var isTiled = pskl.UserSettings.get(pskl.UserSettings.TILED_PREVIEW); + this.renderer.setRepeated(isTiled); + var height, width; if (isTiled) { @@ -186,6 +204,7 @@ width = frame.getWidth() * zoom; } + var containerEl = this.container.get(0); containerEl.style.height = height + 'px'; containerEl.style.width = width + 'px'; diff --git a/src/js/rendering/frame/BackgroundImageFrameRenderer.js b/src/js/rendering/frame/BackgroundImageFrameRenderer.js new file mode 100644 index 00000000..f03e1827 --- /dev/null +++ b/src/js/rendering/frame/BackgroundImageFrameRenderer.js @@ -0,0 +1,51 @@ +(function () { + var ns = $.namespace('pskl.rendering.frame'); + + ns.BackgroundImageFrameRenderer = function (container, zoom) { + this.container = container; + this.setZoom(zoom); + + var containerEl = container.get(0); + var containerDocument = containerEl.ownerDocument; + this.frameContainer = containerDocument.createElement('div'); + this.frameContainer.classList.add('background-image-frame-container'); + container.get(0).appendChild(this.frameContainer); + + this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); + this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); + }; + + ns.BackgroundImageFrameRenderer.prototype.frameToDataUrl_ = function (frame) { + var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); + return canvas.toDataURL('image/png'); + }; + + ns.BackgroundImageFrameRenderer.prototype.render = function (frame) { + var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); + this.frameContainer.style.backgroundImage = 'url(' + imageSrc + ')'; + }; + + ns.BackgroundImageFrameRenderer.prototype.show = function () { + if (this.frameContainer) { + this.frameContainer.style.display = 'block'; + } + }; + + ns.BackgroundImageFrameRenderer.prototype.setZoom = function (zoom) { + this.zoom = zoom; + }; + + ns.BackgroundImageFrameRenderer.prototype.getZoom = function () { + return this.zoom; + }; + + ns.BackgroundImageFrameRenderer.prototype.setRepeated = function (repeat) { + var repeatValue; + if (repeat) { + repeatValue = 'repeat'; + } else { + repeatValue = 'no-repeat'; + } + this.frameContainer.style.backgroundRepeat = repeatValue; + }; +})(); diff --git a/src/js/rendering/frame/FrameRenderer.js b/src/js/rendering/frame/FrameRenderer.js index 6d584594..11da4f74 100644 --- a/src/js/rendering/frame/FrameRenderer.js +++ b/src/js/rendering/frame/FrameRenderer.js @@ -75,24 +75,36 @@ }; ns.FrameRenderer.prototype.setZoom = function (zoom) { - if (zoom > Constants.MINIMUM_ZOOM) { - // back up center coordinates - var centerX = this.offset.x + (this.displayWidth / (2 * this.zoom)); - var centerY = this.offset.y + (this.displayHeight / (2 * this.zoom)); - - this.zoom = zoom; - // recenter - this.setOffset( - centerX - (this.displayWidth / (2 * this.zoom)), - centerY - (this.displayHeight / (2 * this.zoom)) - ); + if (zoom < Constants.MINIMUM_ZOOM) { + zoom = Constants.MINIMUM_ZOOM; } + + if (zoom == this.zoom) { + return; + } + + // back up center coordinates + var centerX = this.offset.x + (this.displayWidth / (2 * this.zoom)); + var centerY = this.offset.y + (this.displayHeight / (2 * this.zoom)); + + this.zoom = zoom; + // recenter + this.setOffset( + centerX - (this.displayWidth / (2 * this.zoom)), + centerY - (this.displayHeight / (2 * this.zoom)) + ); }; ns.FrameRenderer.prototype.getZoom = function () { return this.zoom; }; + ns.FrameRenderer.prototype.setCanvasOpacity = function (opacity) { + if (this.displayCanvas) { + this.displayCanvas.style.opacity = opacity; + } + }; + ns.FrameRenderer.prototype.setDisplaySize = function (width, height) { this.displayWidth = width; this.displayHeight = height; diff --git a/src/js/rendering/frame/TiledFrameRenderer.js b/src/js/rendering/frame/TiledFrameRenderer.js deleted file mode 100644 index 9bd8c8c3..00000000 --- a/src/js/rendering/frame/TiledFrameRenderer.js +++ /dev/null @@ -1,41 +0,0 @@ -(function () { - var ns = $.namespace('pskl.rendering.frame'); - - ns.TiledFrameRenderer = function (container, zoom) { - this.container = container; - this.setZoom(zoom); - - var containerEl = container.get(0); - var containerDocument = containerEl.ownerDocument; - this.displayContainer = containerDocument.createElement('div'); - this.displayContainer.classList.add('tiled-frame-container'); - container.get(0).appendChild(this.displayContainer); - - this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToDataUrl_.bind(this)); - }; - - ns.TiledFrameRenderer.prototype.frameToDataUrl_ = function (frame) { - var canvas = new pskl.utils.FrameUtils.toImage(frame, this.zoom); - return canvas.toDataURL('image/png'); - }; - - ns.TiledFrameRenderer.prototype.render = function (frame) { - var imageSrc = this.cachedFrameProcessor.get(frame, this.zoom); - this.displayContainer.style.backgroundImage = 'url(' + imageSrc + ')'; - }; - - ns.TiledFrameRenderer.prototype.show = function () { - if (this.displayContainer) { - this.displayContainer.style.display = 'block'; - } - }; - - ns.TiledFrameRenderer.prototype.setZoom = function (zoom) { - this.zoom = zoom; - }; - - ns.TiledFrameRenderer.prototype.getZoom = function () { - return this.zoom; - }; -})(); diff --git a/src/js/service/keyboard/CheatsheetService.js b/src/js/service/keyboard/CheatsheetService.js index 396e9af6..d9b81373 100644 --- a/src/js/service/keyboard/CheatsheetService.js +++ b/src/js/service/keyboard/CheatsheetService.js @@ -84,6 +84,7 @@ this.toDescriptor_('N', 'Create new frame'), this.toDescriptor_('shift + N', 'Duplicate selected frame'), this.toDescriptor_('shift + ?', 'Open/Close this popup'), + this.toDescriptor_('alt + 1', 'Toggle original size preview'), this.toDescriptor_('alt + O', 'Toggle Onion Skin'), this.toDescriptor_('alt + L', 'Toggle Layer Preview') ]; diff --git a/src/js/tools/drawing/selection/BaseSelect.js b/src/js/tools/drawing/selection/BaseSelect.js index 4b1620cd..59b3c752 100644 --- a/src/js/tools/drawing/selection/BaseSelect.js +++ b/src/js/tools/drawing/selection/BaseSelect.js @@ -35,6 +35,8 @@ this.lastCol = col; this.lastRow = row; + $.publish(Events.SET_OVERLAY_OPACITY, [0.5]); + // The select tool can be in two different state. // If the inital click of the tool is not on a selection, we go in 'select' // mode to create a selection. @@ -67,9 +69,10 @@ if (this.mode == 'select') { this.onSelectEnd_(col, row, color, frame, overlay); } else if (this.mode == 'moveSelection') { - this.onSelectionDragEnd_(col, row, color, frame, overlay); } + + $.publish(Events.SET_OVERLAY_OPACITY, [1]); }; /** @@ -110,19 +113,12 @@ for (var i = 0, l = pixels.length; i < l ; i++) { var pixel = pixels[i]; var hasColor = pixel.color && pixel.color !== Constants.TRANSPARENT_COLOR ; - var color = hasColor ? this.getTransparentVariant(pixel.color) : Constants.SELECTION_TRANSPARENT_COLOR; + var color = hasColor ? pixel.color : Constants.SELECTION_TRANSPARENT_COLOR; overlay.setPixel(pixels[i].col, pixels[i].row, color); } }; - ns.BaseSelect.prototype.getTransparentVariant = function (colorStr) { - var color = window.tinycolor(colorStr); - color = window.tinycolor.lighten(color, 10); - color.setAlpha(0.5); - return color.toRgbString(); - }; - // The list of callbacks to implement by specialized tools to implement the selection creation behavior. /** @protected */ ns.BaseSelect.prototype.onSelectStart_ = function (col, row, color, frame, overlay) {}; diff --git a/src/js/utils/UserSettings.js b/src/js/utils/UserSettings.js index 79c177a8..3fe2f583 100644 --- a/src/js/utils/UserSettings.js +++ b/src/js/utils/UserSettings.js @@ -8,6 +8,7 @@ CANVAS_BACKGROUND : 'CANVAS_BACKGROUND', SELECTED_PALETTE : 'SELECTED_PALETTE', TILED_PREVIEW : 'TILED_PREVIEW', + ORIGINAL_SIZE_PREVIEW : 'ORIGINAL_SIZE_PREVIEW', ONION_SKIN : 'ONION_SKIN', LAYER_PREVIEW : 'LAYER_PREVIEW', LAYER_OPACITY : 'LAYER_OPACITY', @@ -22,6 +23,7 @@ 'CANVAS_BACKGROUND' : 'lowcont-dark-canvas-background', 'SELECTED_PALETTE' : Constants.CURRENT_COLORS_PALETTE_ID, 'TILED_PREVIEW' : false, + 'ORIGINAL_SIZE_PREVIEW' : false, 'ONION_SKIN' : false, 'LAYER_OPACITY' : 0.2, 'LAYER_PREVIEW' : true diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index fc520f48..3583713a 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -81,7 +81,7 @@ "js/rendering/layer/LayersRenderer.js", "js/rendering/frame/FrameRenderer.js", "js/rendering/OnionSkinRenderer.js", - "js/rendering/frame/TiledFrameRenderer.js", + "js/rendering/frame/BackgroundImageFrameRenderer.js", "js/rendering/frame/CachedFrameRenderer.js", "js/rendering/CanvasRenderer.js", "js/rendering/FramesheetRenderer.js", diff --git a/src/templates/drawing-tools.html b/src/templates/drawing-tools.html index 20fb8290..08f4bbac 100644 --- a/src/templates/drawing-tools.html +++ b/src/templates/drawing-tools.html @@ -41,7 +41,7 @@ diff --git a/src/templates/popup-preview.html b/src/templates/popup-preview.html index be408762..4996cec6 100644 --- a/src/templates/popup-preview.html +++ b/src/templates/popup-preview.html @@ -4,7 +4,7 @@ body, .popup-container , .preview-container, - .tiled-frame-container { + .background-image-frame-container { width : 100%; height : 100%; } @@ -22,7 +22,7 @@ position: relative; } - .tiled-frame-container { + .background-image-frame-container { position: relative; background-repeat : no-repeat; } diff --git a/src/templates/preview.html b/src/templates/preview.html index 5b245a35..468a6054 100644 --- a/src/templates/preview.html +++ b/src/templates/preview.html @@ -1,6 +1,10 @@
-
+
+
1x
+
+
+