GTK3, Pango - rendering mixed case text as uppercase in TextView? - python

What would be the most efficient way to render text, which in the TextBuffer could be any case, as uppercase in a TextView?
It isn't for the entirety of the text, only specific styles within it - and the original capitalization of that section needs to be preserved in case the user changes the text style back to a non-capitalized style.
So if the relevant section of text could be tagged with a TextTag that would be ideal, but there isn't a tag to fully capitalize (there is a small_caps font variant, which for some reason doesn't seem to work in a textview) - can one create a custom TextTag property like "all_caps" and, if so, how would it be implemented?
Other thoughts would be overriding the textview draw function (sounds painful) or possibly creating a secondary TextBuffer and changing the text case on the fly?
UPDATE:
For this application, the best would likely be to intercept the string being passed to Pango from the TextBuffer (from TextView's do_draw, I think) and change it on the fly: for other text styles in this application, some additional text character additions would be needed (It's a screenwriting application, so there is a 'Parenthical' style which, unsurprisingly, is always contained in parentheses - these should be added as part of the style, not relying on the user to add them)
So the updated question would be: How would one subclass / monkey code / something Pango / PangoCairo / Gtk+ 3 to intercept the string being passed to Pango (along with its TextTags) so as to alter / add to it according to its TextTag styles?

Related

Pillow - draw a literal tag glyph?

The Unifont contains glyphs for Tags, Variation Selectors, and other non-printable characters.
For example at the end of https://unifoundry.com/pub/unifont/unifont-14.0.04/font-builds/unifont_upper-14.0.04.ttf are these tags (as shown in FontForge):
Each one has a glyph which should be printable:
I want to draw that glyph, using the Unifont, on an image with Pillow.
from PIL import Image, ImageDraw, ImageFont
text = chr(0x2A6B2) + " " + chr(0x0E0026)
font = ImageFont.truetype("unifont_upper-14.0.04.ttf", size=64)
image1 = Image.new("RGB", (256, 64), "white")
draw1 = ImageDraw.Draw(image1)
draw1.text( (0 , 0), text, font=font, fill="black")
image1.save("test aa.png")
The first character (a CJK ideograph) draws correctly. But the tag character is invisible.
Is there any way to get Pillow to draw the shape that I can see in FontForge?
It seems the short answer is, unfortunately, "no you can't".
Pillow generally uses libraqm to lay out text (i.e. do stuff like map the Unicode string to the glyphs in the font, specifically the raqm_layout function.
That library in turn has uses a library called harfbuzz to do the text shaping.
The tag characters you want, including U+E0026, have the Unicode default ignorable property. By default harfbuzz doesn't display characters with this property, replacing them with a blank glyph. But it is possible, with the use of flags, to modify this behaviour: specifically, calling hb_buffer_set_flags with HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES seems like it will achieve what you want, displaying these characters rather than blanking them out.
The trouble is, libraqm has no way of setting this flag when it calls harfbuzz - it does let you set some of the other flags, but not this one :(
To achieve what you want I guess you'd have to use a lower level library - there are apparently Python bindings for both FreeType and harfbuzz, though I've not used either so I can't comment on how much pain that might involve.
From Section 23.9, Tag Characters in The Unicode Standard, Chapter 23, Special Areas and Format Characters:
Tag Characters: U+E0000–U+E007F
This block encodes a set of 95 special-use tag characters to enable
the spelling out of ASCII-based string tags using characters that can
be strictly separated from ordinary text content characters in
Unicode…
Display. Characters in the tag character block have no visible rendering in normal text and the language tags themselves are not
displayed.
And from the Unicode Frequently Asked Questions (with my own emphasizing):
Q: Which characters should be displayed as invisible, if not supported?
All default-ignorable characters should be rendered as completely invisible (and non advancing, i.e. "zero width"), if not explicitly
supported in rendering.
Q: Does that mean that a font can never display one of these characters?
No. Rendering systems may also support special modes such as “Display
Hidden”, which are intended to reveal characters that would not
otherwise display. Fonts can contain glyphs intended for visible
display of default ignorable code points that would otherwise be
rendered invisibly when not supported.
More resources (required reading, incomplete):
Default_Ignorable_Code_Point character property
Section 5.21, Ignoring Characters in Processing in Implementation Guidelines
🏴 Emoji Tag Sequence

Stylesheet does not work with special characters pyqt

Could not parse stylesheet of object 0x2d956381ba0
def change_btn_image(self, btn):
imagem = self.atv_imagens_bd[self.atividades.get_contador()]
nome_imagem = imagem[:-4]
print(nome_imagem)
btn.setStyleSheet(f"border-image: url(src/main/resources/base/{imagem});")
return nome_imagem
As explained in a slightly related answer, HTML (and, therefore, stylesheet) parsing capabilities of Qt are a bit limited if compared to web browser parsers.
While those syntax are somehow pretty "liberal", one shouldn't push the boundaries of their freedom too much: it's always good practice to use quotes for string based values (besides keywords, obviously), most importantly for URLs.
In this case, the problem is the utf character, which creates a problem as the parser is unable to correctly identify where the url ends.
Just add quotes around the url path:
btn.setStyleSheet(f"border-image: url('src/main/resources/base/{imagem}');")

PyQt5 incorrect label formatting with links

I have two issues with how PyQt is formatting my QLabels
Issue 1:
When hyperlinks are added it displays as if there were no newlines in the string.
For the input text:
https://www.google.co.uk/
https://www.google.co.uk/
https://www.google.co.uk/
It's shown like this without newlines
Issue 2: Sometimes PyQt just doesn't even detect the 'a' tag this happens when the start of string is not a hyperlink but it is then followed by newlines with hyperlinks e.g. this input:
test
https://www.google.co.uk/
https://www.google.co.uk/
https://www.google.co.uk/
As you can see the newlines are properly shown but PyQt has no longer detected the hyperlinks
From the text property documentation of QLabel:
The text will be interpreted either as plain text or as rich text, depending on the text format setting; see setTextFormat(). The default setting is Qt::AutoText; i.e. QLabel will try to auto-detect the format of the text set.
The AutoText flag can only make a guess using simple tag syntax checks (basic tags without arguments, such as <b>, or document type declaration headers, like <html>).
This is obviously done for performance reasons.
If you are sure that you're always setting rich text content, use the appropriate Qt.TextFormat enum:
label.setTextFormat(QtCore.Qt.RichText)
Using the HTML-like syntax of rich text will obviously use the same basic concept HTML had since its birth, almost 30 years ago: line breaks between any word in the document (text or tag) are ignored, as much as multiple spaces are always considered as one.
So, if you want to add line breaks, you have to use the appropriate <br> (or <br/> for xhtml) tag.
Also remember that Qt rich text engine has a limited support, as described in the documentation about the Supported HTML Subset.

How to auto wrap the VSCode python intelliSence provided by Pylance?

PyLance response:
Not converting to markdown wouldn't be a good idea (as it prevents us from using markdown at all in the tooltips). VS Code's plaintext support is broken until 1.52, but maybe then we could add a toggle to say "use plaintext only".
I'm using VSCode to write python, and using Pylance to provide intelliSence. I wonder if it can provide auto wrapped information in a neat way? The intellisense information currently provided mixed all things in a single line which makes it hard to see.
More specifically, the figure below shows the intellisense without auto wrap. I would like the Args: and the following information shows exactly as the green comment writes (each line is one parameter with its explanation). How can I achieve it?
figure 1: intellisense of a user defined class FDNN without auto wrap
figure 2: intellisense of a pytorch class nn.Linear without auto wrap
EDIT 1:
removing the r before comment doesn't work
EDIT 2:
adding - renders better than plain text, but face with _ escape problem.
The solution is simple: Remove the r in front of your docstring
Edit
I have tried the r with a doc string for a function but I can't reproduce the behavior.
If you format the doc string as a kind of Markdown it will display better only it has problems with _ in variable names.
Underline header lines with - (minus) and the text is rendered reasonable.
class FDNN:
"""
Applies a fused fuzzy .....
Args
----
input_size: size of input vector
memfcn: type of membership functions
memparalist: list of tuples of membership functions
"""
def __init__(self):
pass
For functions the rendering of the doc string after you type the opening ( is different, it is used as literal text in the arguments tooltip.
This might be a reason to create an issue for VSC. The descriptions in the different Providers are interpreted differently and should be possible to mark them as plain text or "Markdown"

Why use an ampersand character (&) in PyQt Strings for GUI elements?

I've read several tutorials for PyQt and they use an ampersand character (&) in Strings which are used to label buttons. For example:
self.submitButton = QPushButton("&Submit")
I searched for some explanation, but one problem is, that common search engines think they're so smart and ignore the & character, which is annoying. When I add quotes around it, it only makes me find less results and none, which explains anything about strange '&' characters.
Is it something very basic and that's why no one is explaining it?
Or is it PyQt specific?
And why would I add an unnecessary character like that?
Doesn't it only clutter the String unnecessarily?
What kind of effect does it have on the handling of that String?
I also tried in the python console:
a = "&abc"
b = "abc"
a == b
which returns false.
Then I tried giving it as an argument to the print function:
print(a)
print(b)
which simple prints:
&abc
abc
So I still don't know what to make of this.
From msdn.microsoft.com: (not related to python itself, but the concept is the same)
Gets or sets a value indicating whether the control interprets an
ampersand character (&) in the control's Text property to be an access
key prefix character.
If the UseMnemonic property is set to true and a mnemonic character (a
character preceded by the ampersand) is defined in the Text property
of the Label, pressing ALT+ the mnemonic character sets the focus to
the control that follows the Label in the tab order. You can use this
property to provide proper keyboard navigation to the controls on your
form.
And from pyqt.sourceforge.net:
A QLabel is often used as a label for an interactive widget. For this
use QLabel provides a useful mechanism for adding an mnemonic (see
QKeySequence) that will set the keyboard focus to the other widget.
E.g.:
QLineEdit* phoneEdit = new QLineEdit(this);
QLabel* phoneLabel = new QLabel("&Phone:", this);
phoneLabel->setBuddy(phoneEdit);

Categories