From 29bb0a4a00487e419ca32aeb7640d3ecfeccef44 Mon Sep 17 00:00:00 2001 From: Amartya Parijat Date: Fri, 19 Apr 2024 12:33:55 +0200 Subject: [PATCH] Multi zoom level support for caret This commit scales the caret on a DPI change event on styled text. It uses the line height of the styled text to set on caret. The height and width field in the caret are storing data in points now and not in pixels. We do so to avail the scaling refernece. Also we use SWT.DEFAULT to ignore setting of width. It is useful when we set the new height on DPI change since the preferred width of the caret is loadeed from preferences on the Caret creation. Contributes to #62 and #127 --- .../org/eclipse/swt/custom/StyledText.java | 22 ++++ .../CommonWidgetsDPIChangeHandlers.java | 13 +++ .../win32/org/eclipse/swt/widgets/Caret.java | 102 ++++++++++-------- 3 files changed, 94 insertions(+), 43 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java index 76ef9a494b0..335acfb8bfb 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java @@ -19,6 +19,7 @@ import java.util.*; +import java.util.function.*; import java.util.stream.*; import org.eclipse.swt.*; @@ -10859,4 +10860,25 @@ void updateSelection(int startOffset, int replacedLength, int newLength) { setCaretLocations(); } +/** + * The method accepts a StyledText and a callback which takes + * all the carets of the StyledText as the argument and executes it. + * The caret is refreshed after the execution of the callback. + * + * @param styledText the StyledText to get the carets from + * @param caretUpdater the callback which works with the carets + * + * @noreference This method is not intended to be referenced by clients. + */ +public static void updateAndRefreshCarets(StyledText styledText, Consumer caretUpdater) { + caretUpdater.accept(styledText.getCaret()); + caretUpdater.accept(styledText.defaultCaret); + for (Caret caret : styledText.carets) { + caretUpdater.accept(caret); + } + styledText.updateCaretVisibility(); + styledText.setCaretLocations(); + +} + } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/CommonWidgetsDPIChangeHandlers.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/CommonWidgetsDPIChangeHandlers.java index 1ac53b67756..55bb0b9571e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/CommonWidgetsDPIChangeHandlers.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/internal/CommonWidgetsDPIChangeHandlers.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.swt.internal; +import org.eclipse.swt.custom.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.*; @@ -31,6 +32,7 @@ public class CommonWidgetsDPIChangeHandlers { public static void registerCommonHandlers() { DPIZoomChangeRegistry.registerHandler(CommonWidgetsDPIChangeHandlers::handleItemDPIChange, Item.class); + DPIZoomChangeRegistry.registerHandler(CommonWidgetsDPIChangeHandlers::handleStyledTextDPIChange, StyledText.class); } private static void handleItemDPIChange(Widget widget, int newZoom, float scalingFactor) { @@ -43,4 +45,15 @@ private static void handleItemDPIChange(Widget widget, int newZoom, float scalin item.setImage(image); } } + + private static void handleStyledTextDPIChange(Widget widget, int newZoom, float scalingFactor) { + if (!(widget instanceof StyledText styledText)) { + return; + } + + StyledText.updateAndRefreshCarets(styledText, caretToRefresh -> { + DPIZoomChangeRegistry.applyChange(caretToRefresh, newZoom, scalingFactor); + Caret.win32_setHeight(caretToRefresh, styledText.getLineHeight()); + }); + } } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java index a8bc59db29a..683e135740e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Caret.java @@ -127,15 +127,15 @@ public Rectangle getBounds () { Rectangle getBoundsInPixels () { if (image != null) { Rectangle rect = image.getBoundsInPixels (); - return new Rectangle (x, y, rect.width, rect.height); + return new Rectangle (getXInPixels(), getYInPixels(), rect.width, rect.height); } if (width == 0) { int [] buffer = new int [1]; if (OS.SystemParametersInfo (OS.SPI_GETCARETWIDTH, 0, buffer, 0)) { - return new Rectangle (x, y, buffer [0], height); + return new Rectangle (getXInPixels(), getYInPixels(), buffer [0], getHeightInPixels()); } } - return new Rectangle (x, y, width, height); + return new Rectangle (getXInPixels(), getYInPixels(), getWidthInPixels(), getHeightInPixels()); } /** @@ -185,10 +185,6 @@ public Image getImage () { */ public Point getLocation () { checkWidget(); - return DPIUtil.scaleDown(getLocationInPixels(), getZoom()); -} - -Point getLocationInPixels () { return new Point (x, y); } @@ -230,10 +226,26 @@ Point getSizeInPixels () { if (width == 0) { int [] buffer = new int [1]; if (OS.SystemParametersInfo (OS.SPI_GETCARETWIDTH, 0, buffer, 0)) { - return new Point (buffer [0], height); + return new Point (buffer [0], getHeightInPixels()); } } - return new Point (width, height); + return new Point (getWidthInPixels(), getHeightInPixels()); +} + +private int getWidthInPixels() { + return DPIUtil.autoScaleUp(width, getZoom()); +} + +private int getHeightInPixels() { + return DPIUtil.autoScaleUp(height, getZoom()); +} + +private int getXInPixels() { + return DPIUtil.autoScaleUp(x, getZoom()); +} + +private int getYInPixels() { + return DPIUtil.autoScaleUp(y, getZoom()); } /** @@ -293,7 +305,7 @@ void killFocus () { void move () { moved = false; setCurrentCaret(this); - if (!OS.SetCaretPos (x, y)) return; + if (!OS.SetCaretPos (getXInPixels(), getYInPixels())) return; resizeIME (); } @@ -354,15 +366,15 @@ void resize () { long hwnd = parent.handle; OS.DestroyCaret (); long hBitmap = image != null ? Image.win32_getHandle(image, getZoom()) : 0; - int width = this.width; - if (image == null && width == 0) { + int widthInPixels = this.getWidthInPixels(); + if (image == null && widthInPixels == 0) { int [] buffer = new int [1]; if (OS.SystemParametersInfo (OS.SPI_GETCARETWIDTH, 0, buffer, 0)) { - width = buffer [0]; + widthInPixels = buffer [0]; } } - OS.CreateCaret (hwnd, hBitmap, width, height); - OS.SetCaretPos (x, y); + OS.CreateCaret (hwnd, hBitmap, widthInPixels, getHeightInPixels()); + OS.SetCaretPos (getXInPixels(), getYInPixels()); OS.ShowCaret (hwnd); move (); } @@ -395,11 +407,6 @@ void restoreIMEFont () { */ public void setBounds (int x, int y, int width, int height) { checkWidget(); - int zoom = getZoom(); - setBoundsInPixels(DPIUtil.autoScaleUp(x, zoom), DPIUtil.autoScaleUp(y, zoom), DPIUtil.autoScaleUp(width, zoom), DPIUtil.autoScaleUp(height, zoom)); -} - -void setBoundsInPixels (int x, int y, int width, int height) { boolean samePosition = this.x == x && this.y == y; boolean sameExtent = this.width == width && this.height == height; if (samePosition && sameExtent && isCurrentCaret()) return; @@ -431,25 +438,21 @@ void setBoundsInPixels (int x, int y, int width, int height) { */ public void setBounds (Rectangle rect) { if (rect == null) error (SWT.ERROR_NULL_ARGUMENT); - setBoundsInPixels(DPIUtil.autoScaleUp(rect, getZoom())); -} - -void setBoundsInPixels (Rectangle rect) { - setBoundsInPixels (rect.x, rect.y, rect.width, rect.height); + setBounds(rect.x, rect.y, rect.width, rect.height); } void setFocus () { long hwnd = parent.handle; long hBitmap = 0; if (image != null) hBitmap = Image.win32_getHandle(image, getZoom()); - int width = this.width; - if (image == null && width == 0) { + int widthInPixels = this.getWidthInPixels(); + if (image == null && widthInPixels == 0) { int [] buffer = new int [1]; if (OS.SystemParametersInfo (OS.SPI_GETCARETWIDTH, 0, buffer, 0)) { - width = buffer [0]; + widthInPixels = buffer [0]; } } - OS.CreateCaret (hwnd, hBitmap, width, height); + OS.CreateCaret (hwnd, hBitmap, widthInPixels, getHeightInPixels()); move (); setIMEFont (); if (isVisible) OS.ShowCaret (hwnd); @@ -539,11 +542,6 @@ void setIMEFont () { */ public void setLocation (int x, int y) { checkWidget(); - int zoom = getZoom(); - setLocationInPixels(DPIUtil.autoScaleUp(x, zoom), DPIUtil.autoScaleUp(y, zoom)); -} - -void setLocationInPixels (int x, int y) { if (this.x == x && this.y == y && isCurrentCaret()) return; this.x = x; this.y = y; moved = true; @@ -573,8 +571,7 @@ private void setCurrentCaret(Caret caret) { public void setLocation (Point location) { checkWidget(); if (location == null) error (SWT.ERROR_NULL_ARGUMENT); - location = DPIUtil.autoScaleUp(location, getZoom()); - setLocationInPixels(location.x, location.y); + setLocation(location.x, location.y); } /** @@ -590,12 +587,9 @@ public void setLocation (Point location) { */ public void setSize (int width, int height) { checkWidget(); - setSizeInPixels(DPIUtil.autoScaleUp(width, getZoom()), DPIUtil.autoScaleUp(height, getZoom())); -} - -void setSizeInPixels (int width, int height) { if (this.width == width && this.height == height && isCurrentCaret()) return; - this.width = width; this.height = height; + this.width = width; + this.height = height; resized = true; if (isVisible && hasFocus ()) resize (); } @@ -616,8 +610,7 @@ void setSizeInPixels (int width, int height) { public void setSize (Point size) { checkWidget(); if (size == null) error (SWT.ERROR_NULL_ARGUMENT); - size = DPIUtil.autoScaleUp(size, getZoom()); - setSizeInPixels(size.x, size.y); + setSize(size.x, size.y); } /** @@ -654,6 +647,28 @@ public void setVisible (boolean visible) { } } +/** + * IMPORTANT: This method is not part of the public + * API for Image. It is marked public only so that it + * can be shared within the packages provided by SWT. It is not + * available on all platforms, and should never be called from + * application code. + * + * Sets the height o the caret in points. + * + * @param caret the caret to set the height of + * @param height the height of caret to be set in points. + * + * @noreference This method is not intended to be referenced by clients. + */ +public static void win32_setHeight(Caret caret, int height) { + caret.checkWidget(); + if(caret.height == height && caret.isCurrentCaret()) return; + caret.height = height; + caret.resized = true; + if(caret.isVisible && caret.hasFocus()) caret.resize(); +} + private static void handleDPIChange(Widget widget, int newZoom, float scalingFactor) { if (!(widget instanceof Caret caret)) { return; @@ -669,3 +684,4 @@ private static void handleDPIChange(Widget widget, int newZoom, float scalingFac } } } +