0

I made a text bubble which have 2 dynamic horizontal constraints with superview: left with 1000 priority and right with 100 priority. If bubble was created by user left constraint will have 100 priority and right will have 1000 priority.

Inside of Bubble there is StackView with labels. Stack view is constrained to have the same size as bubble. Both hugging and compression priorities of labels are higher than 100 and lower than 1000(but upper label have a priority over lower).

Idea is simple, constraint with priority 100 will be broken, and bubble will be as big as it needs to show the whole text.

However it doesn't work. Bubbles are much bigger than they should be. It seems that autolayout ignores hugging priorities.

enter image description here

Here are description of all constraints of the bubble with text "Hhbhj":

<NSLayoutConstraint:0x283341630 V:|-(10)-[UIStackView:0x113310d90]   (active, names: '|':UIView:0x113310c20 )>
    <NSLayoutConstraint:0x283341810 H:[UIView:0x113310c20]-(>=16)-|   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x2833414a0 UILabel:0x113311360.height >= 14 priority:999   (active)>
    <NSLayoutConstraint:0x2833416d0 V:|-(6)-[UIView:0x113310c20]   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x283341540 H:|-(10)-[UIStackView:0x113310d90]   (active, names: '|':UIView:0x113310c20 )>
    <NSLayoutConstraint:0x2833415e0 V:[UIStackView:0x113310d90]-(10)-|   (active, names: '|':UIView:0x113310c20 )>
    <NSLayoutConstraint:0x283340be0 UIImageView:0x113310f20.width == 0 priority:1   (active)>
    <NSLayoutConstraint:0x283341680 H:[UIView:0x113310c20]-(16)-|   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x283341360 UILabel:0x1133110f0.height >= 24 priority:999   (active)>
    <NSLayoutConstraint:0x2833417c0 H:|-(16@100)-[UIView:0x113310c20] priority:100   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x283341770 H:|-(>=16)-[UIView:0x113310c20]   (active, names: '|':UITableViewCellContentView:0x113310a90 )>
    <NSLayoutConstraint:0x283340c80 UIImageView:0x113310f20.height == 183 priority:999   (active)>
    <NSLayoutConstraint:0x283341590 H:[UIStackView:0x113310d90]-(10)-|   (active, names: '|':UIView:0x113310c20 )>
    <NSLayoutConstraint:0x283341720 V:[UIView:0x113310c20]-(6)-|   (active, names: '|':UITableViewCellContentView:0x113310a90 )>

P.S You can also see an imageView in bubble. Don't worry if there is no image in bubble imageView will be hidden and constraints will be deactivated.
P.S.S Two vertical greater than constraints, just ensure that bubble will not get bigger than they need to be.

2
  • Can you show the full list of activated constraints? Also, check the logs to see if there were any conflicting constraints that got subsequently broken.
    – Sweeper
    Commented Aug 17, 2021 at 9:41
  • There are no conflicts. I added constraints of the bubble with text "Hhbhj" Commented Aug 17, 2021 at 10:02

1 Answer 1

3

Here is one way to approach this...

For your labels, give the top (the message) label:

Content Hugging Priority
    Horizontal: 750
    Vertical: 1000

Content Compression Resistance Priority
    Horizontal: 1000
    Vertical: 750

and give the bottom (the time) label:

Content Hugging Priority
    Horizontal: 251
    Vertical: 1000

Content Compression Resistance Priority
    Horizontal: 1000
    Vertical: 750

There are two examples here... the top one will constrain the "bubble view" to the cell's Content View margins. The bottom one will constrain the width of the "bubble view" to 80% of the width of the cell.

Setup your constraints like this - ALL with Priority: 1000:

enter image description here

define @IBOutlet vars for the leading and trailing constraints:

@IBOutlet var sentConstraint: NSLayoutConstraint!
@IBOutlet var receivedConstraint: NSLayoutConstraint!

connect sentConstraint to the Bubble View.trailing = trailingMargin constraint, and connect receivedConstraint to the Bubble View.leading = leadingMargin constraint.

It will now look like this:

enter image description here

When you set the data for the cell, activate / deactivate the corresponding constraint, for example:

// activate / deactivate Trailing / Leading constraints
//  based on sent or received
sentConstraint.isActive = msg.type == .sent
receivedConstraint.isActive = msg.type == .received

The >= Leading and Trailing constraints will prevent the bubble view from extending outside the content view frame.

Here's how it could look:

enter image description here

enter image description here

It's common in messaging apps to leave a bit of "padding" on the side. By limiting the width of the bubble view to 80%, it could look like this:

enter image description here

enter image description here

Here's the code I used to produce this layout:

enum MessageType {
    case sent, received
}

struct MessageStruct {
    var imageName: String = ""
    var message: String = ""
    var time: String = ""
    var type: MessageType = .sent
}

class BubbleCell: UITableViewCell {
    
    @IBOutlet var bubbleView: UIView!
    @IBOutlet var myImageView: UIImageView!
    @IBOutlet var messageLabel: UILabel!
    @IBOutlet var timeLabel: UILabel!
    
    @IBOutlet var sentConstraint: NSLayoutConstraint!
    @IBOutlet var receivedConstraint: NSLayoutConstraint!

    func fillData(_ msg: MessageStruct) -> Void {

        // I don't know how you're getting / setting your possible image,
        //  so I'll just set it to hidden for now
        myImageView.isHidden = true

        // set message label text
        messageLabel.text = msg.message
        
        // set time label text, append either sent or rec'd
        //  and set alignment
        timeLabel.text = msg.time + (msg.type == .sent ? " - sent" : " - rec'd")
        timeLabel.textAlignment = msg.type == .sent ? .right : .left
        
        // set colors based on sent or received
        bubbleView.backgroundColor = msg.type == .sent ? .systemGreen : .white
        messageLabel.textColor = msg.type == .sent ? .white : .black
        timeLabel.textColor = msg.type == .sent ? .white : .black
        
        // activate / deactivate Trailing / Leading constraints
        //  based on sent or received
        sentConstraint.isActive = msg.type == .sent
        receivedConstraint.isActive = msg.type == .received
        
        // set corner radii based on sent or received
        bubbleView.layer.cornerRadius = 16
        bubbleView.layer.maskedCorners = msg.type == .sent
            ? [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMinXMaxYCorner]
            : [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMinYCorner]
        
    }
    
}

class MessageTableViewController: UITableViewController {
    
    var myData: [MessageStruct] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        var msg: MessageStruct!
        
        msg = MessageStruct(imageName: "",
                            message: "Short message.",
                            time: "09:15",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "Short message.",
                            time: "09:15",
                            type: .received)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "This is a longer message.",
                            time: "09:20",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "This is a longer message.",
                            time: "09:20",
                            type: .received)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "This message should be long enough that it needs to wrap in the cell.",
                            time: "09:25",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "Another Short message.",
                            time: "09:30",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "Another message, long enough that it will need to wrap in the cell.",
                            time: "09:35",
                            type: .sent)
        myData.append(msg)
        
        msg = MessageStruct(imageName: "",
                            message: "Another message, long enough that it will need to wrap in the cell.",
                            time: "09:35",
                            type: .received)
        myData.append(msg)
        
        tableView.separatorStyle = .none
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myData.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // use "bubbleCell" identifier for margin-width limit
        // use "bubble80Cell" identifier for 80% width limit
        let c = tableView.dequeueReusableCell(withIdentifier: "bubbleCell", for: indexPath) as! BubbleCell
        let d = myData[indexPath.row]
        c.fillData(d)
        return c
    }
    
}

and here's the Storyboard source so you can inspect it:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="t48-nh-14V">
    <device id="retina4_7" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Message Table View Controller-->
        <scene sceneID="mMr-vR-h6X">
            <objects>
                <tableViewController id="t48-nh-14V" customClass="MessageTableViewController" customModule="QuickTest" customModuleProvider="target" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="BrW-mC-6e6">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <prototypes>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="bubbleCell" rowHeight="260" id="Oi2-T7-oyW" customClass="BubbleCell" customModule="QuickTest" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="28" width="375" height="260"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Oi2-T7-oyW" id="gQY-hx-B2I">
                                    <rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="h2Z-Bt-MGu">
                                            <rect key="frame" x="16" y="11" width="343" height="238"/>
                                            <subviews>
                                                <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="wrN-dr-6PW">
                                                    <rect key="frame" x="8" y="12" width="327" height="214"/>
                                                    <subviews>
                                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Aio-Ve-8b1">
                                                            <rect key="frame" x="0.0" y="0.0" width="327" height="165.5"/>
                                                        </imageView>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="83w-nH-MFV">
                                                            <rect key="frame" x="0.0" y="171.5" width="327" height="20.5"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" text="13:50 - sent" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3MO-It-xQw">
                                                            <rect key="frame" x="0.0" y="198" width="327" height="16"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                    </subviews>
                                                </stackView>
                                            </subviews>
                                            <color key="backgroundColor" systemColor="systemGreenColor"/>
                                            <constraints>
                                                <constraint firstItem="wrN-dr-6PW" firstAttribute="top" secondItem="h2Z-Bt-MGu" secondAttribute="top" constant="12" id="61F-T7-VXd"/>
                                                <constraint firstAttribute="trailing" secondItem="wrN-dr-6PW" secondAttribute="trailing" constant="8" id="Aso-zu-ZPc"/>
                                                <constraint firstItem="wrN-dr-6PW" firstAttribute="leading" secondItem="h2Z-Bt-MGu" secondAttribute="leading" constant="8" id="bsG-sY-260"/>
                                                <constraint firstAttribute="bottom" secondItem="wrN-dr-6PW" secondAttribute="bottom" constant="12" id="oAO-Jt-UX3"/>
                                            </constraints>
                                        </view>
                                    </subviews>
                                    <color key="backgroundColor" red="0.897361517" green="0.8974906802" blue="0.89733326440000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <constraints>
                                        <constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="h2Z-Bt-MGu" secondAttribute="trailing" id="6hf-N2-14b"/>
                                        <constraint firstAttribute="bottomMargin" secondItem="h2Z-Bt-MGu" secondAttribute="bottom" id="FxF-PE-6iW"/>
                                        <constraint firstItem="h2Z-Bt-MGu" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gQY-hx-B2I" secondAttribute="leadingMargin" id="Wsa-eO-InO"/>
                                        <constraint firstItem="h2Z-Bt-MGu" firstAttribute="top" secondItem="gQY-hx-B2I" secondAttribute="topMargin" id="ZYU-hS-2Pl"/>
                                        <constraint firstItem="h2Z-Bt-MGu" firstAttribute="trailing" secondItem="gQY-hx-B2I" secondAttribute="trailingMargin" id="edX-9l-Ye2"/>
                                        <constraint firstItem="h2Z-Bt-MGu" firstAttribute="leading" secondItem="gQY-hx-B2I" secondAttribute="leadingMargin" id="s0J-rx-Rzx"/>
                                    </constraints>
                                </tableViewCellContentView>
                                <connections>
                                    <outlet property="bubbleView" destination="h2Z-Bt-MGu" id="uJ0-t9-ZQ9"/>
                                    <outlet property="messageLabel" destination="83w-nH-MFV" id="pEd-Gg-49x"/>
                                    <outlet property="myImageView" destination="Aio-Ve-8b1" id="qJQ-G9-Qc6"/>
                                    <outlet property="receivedConstraint" destination="s0J-rx-Rzx" id="fCI-9h-2V1"/>
                                    <outlet property="sentConstraint" destination="edX-9l-Ye2" id="KKm-FT-Zcq"/>
                                    <outlet property="timeLabel" destination="3MO-It-xQw" id="bxt-vZ-c2v"/>
                                </connections>
                            </tableViewCell>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="bubble80Cell" rowHeight="260" id="DAc-Zm-a8s" customClass="BubbleCell" customModule="QuickTest" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="288" width="375" height="260"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="DAc-Zm-a8s" id="te5-Rn-aLa">
                                    <rect key="frame" x="0.0" y="0.0" width="375" height="260"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lFi-s6-a3X">
                                            <rect key="frame" x="16" y="11" width="300" height="238"/>
                                            <subviews>
                                                <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="6" translatesAutoresizingMaskIntoConstraints="NO" id="HX0-dn-sRz">
                                                    <rect key="frame" x="8" y="12" width="284" height="214"/>
                                                    <subviews>
                                                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Xsw-i1-9mU">
                                                            <rect key="frame" x="0.0" y="0.0" width="284" height="165.5"/>
                                                        </imageView>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="750" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" text="Label" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6Zs-Af-RNQ">
                                                            <rect key="frame" x="0.0" y="171.5" width="284" height="20.5"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="1000" horizontalCompressionResistancePriority="1000" text="13:50 - sent" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7nV-rU-i4W">
                                                            <rect key="frame" x="0.0" y="198" width="284" height="16"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="13"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                    </subviews>
                                                </stackView>
                                            </subviews>
                                            <color key="backgroundColor" systemColor="systemGreenColor"/>
                                            <constraints>
                                                <constraint firstItem="HX0-dn-sRz" firstAttribute="leading" secondItem="lFi-s6-a3X" secondAttribute="leading" constant="8" id="6Kk-f4-tiB"/>
                                                <constraint firstItem="HX0-dn-sRz" firstAttribute="top" secondItem="lFi-s6-a3X" secondAttribute="top" constant="12" id="7H5-6V-Ag0"/>
                                                <constraint firstAttribute="trailing" secondItem="HX0-dn-sRz" secondAttribute="trailing" constant="8" id="Czf-wx-QBQ"/>
                                                <constraint firstAttribute="bottom" secondItem="HX0-dn-sRz" secondAttribute="bottom" constant="12" id="edZ-aP-M1N"/>
                                            </constraints>
                                        </view>
                                    </subviews>
                                    <color key="backgroundColor" red="0.897361517" green="0.8974906802" blue="0.89733326440000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <constraints>
                                        <constraint firstItem="lFi-s6-a3X" firstAttribute="trailing" secondItem="te5-Rn-aLa" secondAttribute="trailingMargin" id="Ua5-F4-YR5"/>
                                        <constraint firstAttribute="bottomMargin" secondItem="lFi-s6-a3X" secondAttribute="bottom" id="WKr-87-LJK"/>
                                        <constraint firstItem="lFi-s6-a3X" firstAttribute="leading" secondItem="te5-Rn-aLa" secondAttribute="leadingMargin" id="h4U-ie-xYq"/>
                                        <constraint firstItem="lFi-s6-a3X" firstAttribute="width" relation="lessThanOrEqual" secondItem="te5-Rn-aLa" secondAttribute="width" multiplier="0.8" id="sKr-Xc-5bn"/>
                                        <constraint firstItem="lFi-s6-a3X" firstAttribute="top" secondItem="te5-Rn-aLa" secondAttribute="topMargin" id="ueL-NI-qoX"/>
                                    </constraints>
                                </tableViewCellContentView>
                                <connections>
                                    <outlet property="bubbleView" destination="lFi-s6-a3X" id="5qj-C0-Uf3"/>
                                    <outlet property="messageLabel" destination="6Zs-Af-RNQ" id="YTU-M9-s7P"/>
                                    <outlet property="myImageView" destination="Xsw-i1-9mU" id="Unr-HS-Iv1"/>
                                    <outlet property="receivedConstraint" destination="h4U-ie-xYq" id="tCy-cc-uHa"/>
                                    <outlet property="sentConstraint" destination="Ua5-F4-YR5" id="Kgg-gY-JCv"/>
                                    <outlet property="timeLabel" destination="7nV-rU-i4W" id="GUX-T1-4Nc"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="t48-nh-14V" id="3oa-OS-rO8"/>
                            <outlet property="delegate" destination="t48-nh-14V" id="7Ua-sV-mwS"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" id="fpm-tv-1pb"/>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="2On-8d-2Kp" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-1447.2" y="-749.7751124437782"/>
        </scene>
    </scenes>
    <resources>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
        <systemColor name="systemGreenColor">
            <color red="0.20392156862745098" green="0.7803921568627451" blue="0.34901960784313724" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </systemColor>
    </resources>
</document>

Edit

Worth noting -- if we replace these two lines in fillData():

    sentConstraint.isActive = msg.type == .sent
    receivedConstraint.isActive = msg.type == .received
    

with these:

    sentConstraint.priority = msg.type == .sent ? .defaultHigh : .defaultLow
    receivedConstraint.priority = msg.type == .received ? .defaultHigh : .defaultLow

we'll accomplish the same goal.

Without seeing your actual layout (difficult to decipher the "description of all constraints" you posted), and without seeing the code you are using, it's tough to say why that wasn't working for you.

2
  • It works. Thanks. Do you have any idea why you should deactivate constraint instead of lowering it priority. Shouldn't both of these approach work? Commented Aug 18, 2021 at 10:41
  • @ShynggysSaparbek - see the Edit at the end of my answer.
    – DonMag
    Commented Aug 18, 2021 at 12:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.