diff options
author | orbitalquark <70453897+orbitalquark@users.noreply.github.com> | 2025-05-12 11:38:13 +1000 |
---|---|---|
committer | orbitalquark <70453897+orbitalquark@users.noreply.github.com> | 2025-05-12 11:38:13 +1000 |
commit | 140a921a133ee63337e8dfe1c7261b7eb86399e9 (patch) | |
tree | 219a6641ddd4fd117bc0b0fa2bb1876d39f4499e | |
parent | da1240f14a3fda528e8776cc873d124b6c8703f4 (diff) | |
download | scintilla-mirror-140a921a133ee63337e8dfe1c7261b7eb86399e9.tar.gz |
Add SCI_AUTOC{G,S}ETIMAGESCALE and implement for Qt and GTK.
-rw-r--r-- | call/ScintillaCall.cxx | 8 | ||||
-rw-r--r-- | doc/ScintillaDoc.html | 12 | ||||
-rw-r--r-- | doc/ScintillaHistory.html | 4 | ||||
-rwxr-xr-x | gtk/PlatGTK.cxx | 34 | ||||
-rw-r--r-- | include/Scintilla.h | 2 | ||||
-rw-r--r-- | include/Scintilla.iface | 6 | ||||
-rw-r--r-- | include/ScintillaCall.h | 2 | ||||
-rw-r--r-- | include/ScintillaMessages.h | 2 | ||||
-rw-r--r-- | qt/ScintillaEditBase/PlatQt.cpp | 24 | ||||
-rw-r--r-- | scripts/HeaderOrder.txt | 1 | ||||
-rw-r--r-- | src/AutoComplete.cxx | 1 | ||||
-rw-r--r-- | src/AutoComplete.h | 1 | ||||
-rw-r--r-- | src/Platform.h | 1 | ||||
-rw-r--r-- | src/ScintillaBase.cxx | 8 | ||||
-rw-r--r-- | test/simpleTests.py | 5 |
15 files changed, 97 insertions, 14 deletions
diff --git a/call/ScintillaCall.cxx b/call/ScintillaCall.cxx index 662bb9406..11a1f1d52 100644 --- a/call/ScintillaCall.cxx +++ b/call/ScintillaCall.cxx @@ -1115,6 +1115,14 @@ int ScintillaCall::AutoCGetStyle() { return static_cast<int>(Call(Message::AutoCGetStyle)); } +void ScintillaCall::AutoCSetImageScale(int scalePercent) { + Call(Message::AutoCSetImageScale, scalePercent); +} + +int ScintillaCall::AutoCGetImageScale() { + return static_cast<int>(Call(Message::AutoCGetImageScale)); +} + void ScintillaCall::SetIndent(int indentSize) { Call(Message::SetIndent, indentSize); } diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 1ee1c2306..17ee1673c 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -6514,6 +6514,8 @@ struct Sci_TextToFindFull { <a class="message" href="#SCI_AUTOCGETMAXWIDTH">SCI_AUTOCGETMAXWIDTH → int</a><br /> <a class="message" href="#SCI_AUTOCSETSTYLE">SCI_AUTOCSETSTYLE(int style)</a><br /> <a class="message" href="#SCI_AUTOCGETSTYLE">SCI_AUTOCGETSTYLE → int</a><br /> + <a class="message" href="#SCI_AUTOCSETIMAGESCALE">SCI_AUTOCSETIMAGESCALE(int scale)</a><br /> + <a class="message" href="#SCI_AUTOCGETIMAGESCALE">SCI_AUTOCGETIMAGESCALE → int</a><br /> <a class="element" href="#SC_ELEMENT_LIST">SC_ELEMENT_LIST : colouralpha</a><br /> <a class="element" href="#SC_ELEMENT_LIST_BACK">SC_ELEMENT_LIST_BACK : colouralpha</a><br /> <a class="element" href="#SC_ELEMENT_LIST_SELECTED">SC_ELEMENT_LIST_SELECTED : colouralpha</a><br /> @@ -6746,6 +6748,16 @@ struct Sci_TextToFindFull { </p> <p> + <b id="SCI_AUTOCSETIMAGESCALE">SCI_AUTOCSETIMAGESCALE(int scalePercent)</b><br /> + <b id="SCI_AUTOCGETIMAGESCALE">SCI_AUTOCGETIMAGESCALE → int</b><br /> + + Get or set the scale factor in percent for <em>all</em> autocompletion list images. This is useful on macOS with + a retina display where each display unit is 2 pixels: use a factor of 200 so that each image pixel is displayed using a screen pixel. + The default scale, 100, will stretch each image pixel to cover 4 screen pixels on a retina display. + </p> + <p>This is currently only implemented for the Qt and GTK platforms.</p> + + <p> <b id="SC_ELEMENT_LIST">SC_ELEMENT_LIST : colouralpha</b><br /> <b id="SC_ELEMENT_LIST_BACK">SC_ELEMENT_LIST_BACK : colouralpha</b><br /> <b id="SC_ELEMENT_LIST_SELECTED">SC_ELEMENT_LIST_SELECTED : colouralpha</b><br /> diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 49b96aa2c..d1fdd16d7 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -608,6 +608,10 @@ Tweak SC_MARK_BAR to be slightly wider by using next higher whole pixel instead of next lower for margin width / 3. </li> <li> + Scale images in autocompletion lists with SCI_AUTOCSETIMAGESCALE to match high DPI screens. + Initially only on GTK and Qt. + </li> + <li> On GTK, reset vertical scroll bar synchronously in SCI_SETDOCPOINTER to fix bug where scroll position not restored in non-wrap mode. <a href="https://sourceforge.net/p/scintilla/bugs/2416/">Bug #2416</a>. diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx index 67b7f7052..c7bcbb772 100755 --- a/gtk/PlatGTK.cxx +++ b/gtk/PlatGTK.cxx @@ -27,6 +27,9 @@ #if defined(GDK_WINDOWING_WAYLAND) #include <gdk/gdkwayland.h> #endif +#if GTK_CHECK_VERSION(3, 10, 0) +#include <cairo/cairo-gobject.h> +#endif #include "ScintillaTypes.h" #include "ScintillaMessages.h" @@ -1432,6 +1435,7 @@ class ListBoxX : public ListBox { #if GTK_CHECK_VERSION(3,0,0) std::unique_ptr<GtkCssProvider, GObjectReleaser> cssProvider; #endif + float imageScale; public: IListBoxDelegate *delegate; @@ -1439,7 +1443,7 @@ public: pixhash(nullptr), pixbuf_renderer(nullptr), renderer(nullptr), desiredVisibleRows(5), maxItemCharacters(0), - aveCharWidth(1), + aveCharWidth(1), imageScale(1.0), delegate(nullptr) { } // Deleted so ListBoxX objects can not be copied. @@ -1673,7 +1677,13 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, Technology) { /* Tree and its model */ GtkListStore *store = - gtk_list_store_new(N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING); + gtk_list_store_new(N_COLUMNS, +#if GTK_CHECK_VERSION(3, 10, 0) + CAIRO_GOBJECT_TYPE_SURFACE, +#else + GDK_TYPE_PIXBUF, +#endif + G_TYPE_STRING); list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_signal_connect(G_OBJECT(list), "style-set", G_CALLBACK(StyleSet), nullptr); @@ -1701,7 +1711,13 @@ void ListBoxX::Create(Window &parent, int, Point, int, bool, Technology) { gtk_cell_renderer_set_fixed_size(pixbuf_renderer, 0, -1); gtk_tree_view_column_pack_start(column, pixbuf_renderer, FALSE); gtk_tree_view_column_add_attribute(column, pixbuf_renderer, - "pixbuf", PIXBUF_COLUMN); +#if GTK_CHECK_VERSION(3, 10, 0) + "surface", +#else + "pixbuf", +#endif + PIXBUF_COLUMN); + renderer = gtk_cell_renderer_text_new(); gtk_cell_renderer_text_set_fixed_height_from_font(GTK_CELL_RENDERER_TEXT(renderer), 1); @@ -1915,11 +1931,20 @@ void ListBoxX::Append(char *s, int type) { if (nullptr == list_image->pixbuf) init_pixmap(list_image); if (list_image->pixbuf) { +#if GTK_CHECK_VERSION(3, 10, 0) + cairo_surface_t *surface = gdk_cairo_surface_create_from_pixbuf(list_image->pixbuf, imageScale, nullptr); + gtk_list_store_set(GTK_LIST_STORE(store), &iter, + PIXBUF_COLUMN, surface, + TEXT_COLUMN, s, -1); + + const gint pixbuf_width = gdk_pixbuf_get_width(list_image->pixbuf) / imageScale; +#else gtk_list_store_set(GTK_LIST_STORE(store), &iter, PIXBUF_COLUMN, list_image->pixbuf, TEXT_COLUMN, s, -1); const gint pixbuf_width = gdk_pixbuf_get_width(list_image->pixbuf); +#endif gint renderer_height, renderer_width; gtk_cell_renderer_get_fixed_size(pixbuf_renderer, &renderer_width, &renderer_height); @@ -2125,7 +2150,8 @@ void ListBoxX::SetList(const char *listText, char separator, char typesep) { } } -void ListBoxX::SetOptions(ListOptions) { +void ListBoxX::SetOptions(ListOptions options_) { + imageScale = options_.imageScale; } Menu::Menu() noexcept : mid(nullptr) {} diff --git a/include/Scintilla.h b/include/Scintilla.h index a90dd3571..e2555b862 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -475,6 +475,8 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP #define SCI_AUTOCGETMAXHEIGHT 2211 #define SCI_AUTOCSETSTYLE 2109 #define SCI_AUTOCGETSTYLE 2120 +#define SCI_AUTOCSETIMAGESCALE 2815 +#define SCI_AUTOCGETIMAGESCALE 2816 #define SCI_SETINDENT 2122 #define SCI_GETINDENT 2123 #define SCI_SETUSETABS 2124 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index ef0a9a384..af34b71db 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -1174,6 +1174,12 @@ set void AutoCSetStyle=2109(int style,) # Get the style number used for auto-completion and user lists fonts. get int AutoCGetStyle=2120(,) +# Set the scale factor in percent for auto-completion list images. +set void AutoCSetImageScale=2815(int scalePercent,) + +# Get the scale factor in percent for auto-completion list images. +get int AutoCGetImageScale=2816(,) + # Set the number of spaces used for one level of indentation. set void SetIndent=2122(int indentSize,) diff --git a/include/ScintillaCall.h b/include/ScintillaCall.h index b31978725..a2387f876 100644 --- a/include/ScintillaCall.h +++ b/include/ScintillaCall.h @@ -324,6 +324,8 @@ public: int AutoCGetMaxHeight(); void AutoCSetStyle(int style); int AutoCGetStyle(); + void AutoCSetImageScale(int scalePercent); + int AutoCGetImageScale(); void SetIndent(int indentSize); int Indent(); void SetUseTabs(bool useTabs); diff --git a/include/ScintillaMessages.h b/include/ScintillaMessages.h index d7ec27c39..67b4f69c6 100644 --- a/include/ScintillaMessages.h +++ b/include/ScintillaMessages.h @@ -249,6 +249,8 @@ enum class Message { AutoCGetMaxHeight = 2211, AutoCSetStyle = 2109, AutoCGetStyle = 2120, + AutoCSetImageScale = 2815, + AutoCGetImageScale = 2816, SetIndent = 2122, GetIndent = 2123, SetUseTabs = 2124, diff --git a/qt/ScintillaEditBase/PlatQt.cpp b/qt/ScintillaEditBase/PlatQt.cpp index 91edf0754..38aec01a0 100644 --- a/qt/ScintillaEditBase/PlatQt.cpp +++ b/qt/ScintillaEditBase/PlatQt.cpp @@ -40,6 +40,7 @@ #include <QTextLayout> #include <QTextLine> #include <QLibrary> +#include <QtMath> using namespace Scintilla; @@ -994,6 +995,7 @@ private: bool unicodeMode{false}; int visibleRows{5}; QMap<int,QPixmap> images; + float imageScale{1.0}; }; ListBoxImpl::ListBoxImpl() noexcept = default; @@ -1034,10 +1036,11 @@ void ListBoxImpl::Create(Window &parent, int maxIconWidth = 0; int maxIconHeight = 0; foreach (QPixmap im, images) { - if (maxIconWidth < im.width()) - maxIconWidth = im.width(); - if (maxIconHeight < im.height()) - maxIconHeight = im.height(); + im.setDevicePixelRatio(imageScale); + if (maxIconWidth < im.width() / im.devicePixelRatio()) + maxIconWidth = im.width() / im.devicePixelRatio(); + if (maxIconHeight < im.height() / im.devicePixelRatio()) + maxIconHeight = im.height() / im.devicePixelRatio(); } list->setIconSize(QSize(maxIconWidth, maxIconHeight)); @@ -1085,8 +1088,8 @@ int ListBoxImpl::CaretFromEdge() ListWidget *list = GetWidget(); int maxIconWidth = 0; foreach (QPixmap im, images) { - if (maxIconWidth < im.width()) - maxIconWidth = im.width(); + if (maxIconWidth < im.width() / im.devicePixelRatio()) + maxIconWidth = im.width() / im.devicePixelRatio(); } int extra; @@ -1165,9 +1168,9 @@ void ListBoxImpl::RegisterQPixmapImage(int type, const QPixmap& pm) ListWidget *list = GetWidget(); if (list) { QSize iconSize = list->iconSize(); - if (pm.width() > iconSize.width() || pm.height() > iconSize.height()) - list->setIconSize(QSize(qMax(pm.width(), iconSize.width()), - qMax(pm.height(), iconSize.height()))); + if (pm.width() / pm.devicePixelRatio() > iconSize.width() || pm.height() / pm.devicePixelRatio() > iconSize.height()) + list->setIconSize(QSize(qMax(qFloor(pm.width() / pm.devicePixelRatio()), iconSize.width()), + qMax(qFloor(pm.height() / pm.devicePixelRatio()), iconSize.height()))); } } @@ -1226,8 +1229,9 @@ void ListBoxImpl::SetList(const char *list, char separator, char typesep) Append(startword, numword?atoi(numword + 1):-1); } } -void ListBoxImpl::SetOptions(ListOptions) +void ListBoxImpl::SetOptions(ListOptions options_) { + imageScale = options_.imageScale; } ListWidget *ListBoxImpl::GetWidget() const noexcept { diff --git a/scripts/HeaderOrder.txt b/scripts/HeaderOrder.txt index a75693a66..cd1322ac1 100644 --- a/scripts/HeaderOrder.txt +++ b/scripts/HeaderOrder.txt @@ -71,6 +71,7 @@ #include <gdk/gdkkeysyms.h> #include <gdk/gdkwayland.h> #include <gtk/gtk-a11y.h> +#include <cairo/cairo-gobject.h> // Windows headers #include <windows.h> diff --git a/src/AutoComplete.cxx b/src/AutoComplete.cxx index 2487d3042..058550d62 100644 --- a/src/AutoComplete.cxx +++ b/src/AutoComplete.cxx @@ -41,6 +41,7 @@ AutoComplete::AutoComplete() : ignoreCase(false), chooseSingle(false), options(AutoCompleteOption::Normal), + imageScale(1.0), posStart(0), startLen(0), cancelAtStartPos(true), diff --git a/src/AutoComplete.h b/src/AutoComplete.h index 378232a84..b1233332c 100644 --- a/src/AutoComplete.h +++ b/src/AutoComplete.h @@ -25,6 +25,7 @@ public: bool ignoreCase; bool chooseSingle; AutoCompleteOption options; + float imageScale; std::unique_ptr<ListBox> lb; Sci::Position posStart; Sci::Position startLen; diff --git a/src/Platform.h b/src/Platform.h index 77464945e..119b4ef3f 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -317,6 +317,7 @@ struct ListOptions { std::optional<ColourRGBA> foreSelected; std::optional<ColourRGBA> backSelected; AutoCompleteOption options=AutoCompleteOption::Normal; + float imageScale=1.0f; }; class ListBox : public Window { diff --git a/src/ScintillaBase.cxx b/src/ScintillaBase.cxx index a49cfab32..1f4c360da 100644 --- a/src/ScintillaBase.cxx +++ b/src/ScintillaBase.cxx @@ -296,6 +296,7 @@ void ScintillaBase::AutoCompleteStart(Sci::Position lenEntered, const char *list vs.ElementColour(Element::ListSelected), vs.ElementColour(Element::ListSelectedBack), ac.options, + ac.imageScale, }; int lineHeight; @@ -972,6 +973,13 @@ sptr_t ScintillaBase::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { case Message::AutoCGetStyle: return vs.autocStyle; + case Message::AutoCSetImageScale: + ac.imageScale = static_cast<float>(wParam) / 100.0f; + break; + + case Message::AutoCGetImageScale: + return static_cast<int>(ac.imageScale * 100); + case Message::RegisterImage: ac.lb->RegisterImage(static_cast<int>(wParam), ConstCharPtrFromSPtr(lParam)); break; diff --git a/test/simpleTests.py b/test/simpleTests.py index 867c0ebbc..0389d6dbc 100644 --- a/test/simpleTests.py +++ b/test/simpleTests.py @@ -3188,6 +3188,7 @@ class TestAutoComplete(unittest.TestCase): self.assertEqual(self.ed.AutoCGetIgnoreCase(), 0) self.assertEqual(self.ed.AutoCGetAutoHide(), 1) self.assertEqual(self.ed.AutoCGetDropRestOfWord(), 0) + self.assertEqual(self.ed.AutoCGetImageScale(), 100) def testChangeDefaults(self): self.ed.AutoCSetSeparator(ord('-')) @@ -3222,6 +3223,10 @@ class TestAutoComplete(unittest.TestCase): self.assertEqual(self.ed.AutoCGetStyle(), 13) self.ed.AutoCSetStyle(self.ed.STYLE_DEFAULT) + self.ed.AutoCSetImageScale(200) + self.assertEqual(self.ed.AutoCGetImageScale(), 200) + self.ed.AutoCSetImageScale(100) + def testAutoShow(self): self.assertEqual(self.ed.AutoCActive(), 0) self.ed.SetSel(0, 0) |