aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authororbitalquark <70453897+orbitalquark@users.noreply.github.com>2025-05-12 11:38:13 +1000
committerorbitalquark <70453897+orbitalquark@users.noreply.github.com>2025-05-12 11:38:13 +1000
commit140a921a133ee63337e8dfe1c7261b7eb86399e9 (patch)
tree219a6641ddd4fd117bc0b0fa2bb1876d39f4499e
parentda1240f14a3fda528e8776cc873d124b6c8703f4 (diff)
downloadscintilla-mirror-140a921a133ee63337e8dfe1c7261b7eb86399e9.tar.gz
Add SCI_AUTOC{G,S}ETIMAGESCALE and implement for Qt and GTK.
-rw-r--r--call/ScintillaCall.cxx8
-rw-r--r--doc/ScintillaDoc.html12
-rw-r--r--doc/ScintillaHistory.html4
-rwxr-xr-xgtk/PlatGTK.cxx34
-rw-r--r--include/Scintilla.h2
-rw-r--r--include/Scintilla.iface6
-rw-r--r--include/ScintillaCall.h2
-rw-r--r--include/ScintillaMessages.h2
-rw-r--r--qt/ScintillaEditBase/PlatQt.cpp24
-rw-r--r--scripts/HeaderOrder.txt1
-rw-r--r--src/AutoComplete.cxx1
-rw-r--r--src/AutoComplete.h1
-rw-r--r--src/Platform.h1
-rw-r--r--src/ScintillaBase.cxx8
-rw-r--r--test/simpleTests.py5
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 &rarr; int</a><br />
<a class="message" href="#SCI_AUTOCSETSTYLE">SCI_AUTOCSETSTYLE(int style)</a><br />
<a class="message" href="#SCI_AUTOCGETSTYLE">SCI_AUTOCGETSTYLE &rarr; int</a><br />
+ <a class="message" href="#SCI_AUTOCSETIMAGESCALE">SCI_AUTOCSETIMAGESCALE(int scale)</a><br />
+ <a class="message" href="#SCI_AUTOCGETIMAGESCALE">SCI_AUTOCGETIMAGESCALE &rarr; 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 &rarr; 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)