HISE Logo Forum
    • Categories
    • Register
    • Login

    Delayed broadcaster fires twice

    Scheduled Pinned Locked Moved Solved Scripting
    11 Posts 6 Posters 417 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • d.healeyD
      d.healey @Oli Ullmann
      last edited by

      @Oli-Ullmann It fires once a second for me

      Libre Wave - Freedom respecting instruments and effects
      My Patreon - HISE tutorials
      YouTube Channel - Public HISE tutorials

      Oli UllmannO 1 Reply Last reply Reply Quote 1
      • Oli UllmannO
        Oli Ullmann @d.healey
        last edited by Oli Ullmann

        @d-healey
        Strange. Here he fires several times. I set the position of the panel in the broadcaster. This then jumps, as can be seen in the video. In the console you can also see that the broadcaster fires several times.
        If I use “showControl” instead of “fadeComponent”, the panel does not jump. Maybe this has something to do with it... However, I am not using the latest HISE version. Maybe that's also the reason.

        Tooltip.mov

        d.healeyD 1 Reply Last reply Reply Quote 1
        • d.healeyD
          d.healey @Oli Ullmann
          last edited by

          @Oli-Ullmann Here's my floating tooltip script, maybe you can get something useful from it.

          /*
              Copyright 2024, 2025 David Healey
          
              This file is free software: you can redistribute it and/or modify
              it under the terms of the GNU General Public License as published by
              the Free Software Foundation, either version 3 of the License, or
              (at your option) any later version.
          
              This file is distributed in the hope that it will be useful,
              but WITHOUT ANY WARRANTY; without even the implied warranty of
              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
              GNU General Public License for more details.
          
              You should have received a copy of the GNU General Public License
              along with This file. If not, see <http://www.gnu.org/licenses/>.
          */
          
          namespace Tooltips
          {
          	const tooltipComponents = getComponents();
          	
          	//! pnlTooltip
          	const pnlTooltip = Content.getComponent("pnlTooltip");
          	pnlTooltip.showControl(false);
          	pnlTooltip.set("enabled", false);
          
          	pnlTooltip.setPaintRoutine(function(g)
          	{
          		var a = this.getLocalBounds(20);
          		var radius = this.get("borderRadius");
          
          		g.drawDropShadow(a, Colours.withAlpha(Colours.black, 0.6), 20);
          
          		g.setColour(this.get("bgColour"));
          		g.fillRoundedRectangle(a, radius);
          
          		g.setColour(Colours.withAlpha(this.get("itemColour"), 0.5));
          		g.drawRoundedRectangle([a[0] + radius / 4, a[1] + radius / 4, a[2] - radius / 2, a[3] - radius / 2], radius, 1);
          
          		g.setFontWithSpacing("medium", 16, 0.0);
          		g.setColour(this.get("textColour"));
          		g.drawAlignedText(this.get("tooltip"), a, "centred");
          	});
          	
          	//! Functions
          	inline function: Array getComponents()
          	{
          		local result = [];
          		local allComponents = Content.getAllComponents("");
          		local types = ["ScriptButton", "ScriptSlider", "ScriptTable", "ScriptComboBox", "ScriptPanel"];
          		
          		for (x in allComponents)
          		{
          			if (!x.get("enabled"))
          				continue;
          
          			if (x.get("tooltip") == "")
          				continue;
          
          			if (!types.contains(x.get("type")))
          				continue;
          
          			result.push(x);			
          		}
          	
          		return result;
          	}
          	
          	//! Broadcaster	
          	const bcTooltipPanel = Engine.createBroadcaster({"id": "tooltip", "args": ["component", "event"]});
          	bcTooltipPanel.attachToComponentMouseEvents(tooltipComponents, "All Callbacks", "");
          
          	inline function addRemoveListeners(state: number)
          	{
          		if (!state)
          		{
          			bcTooltipPanel.removeListener("Update panel position");
          			bcTooltipPanel.removeListener("Show Tooltip");
          			return;
          		}
          		
          		bcTooltipPanel.addListener(pnlTooltip, "Update panel position", function(component, event)
          		{
          			var interfaceSize = Content.getInterfaceSize();
          
          			this.set("tooltip", component.get("tooltip"));
          			this.set("width", Engine.getStringWidth(this.get("tooltip"), "medium", 16, 0.0) + 75);
          			this.set("x", component.getGlobalPositionX() + component.getWidth() / 2 - this.getWidth() / 2);
          			this.set("y", component.getGlobalPositionY() + 10);
          
          			if (this.get("x") + this.getWidth() > interfaceSize[0])
          				this.set("x", interfaceSize[0] - this.getWidth() - 5);
          			else if (this.get("x") < 0)
          				this.set("x", 0);
          
          			if (this.get("y") + this.getHeight() > interfaceSize[1])
          				this.set("y", interfaceSize[1] - this.getHeight() - 5);
          
          			this.repaint();
          		
          			if (!event.hover || (component.get("tooltip") == ""))
          				this.showControl(false);
          		});
          			
          		bcTooltipPanel.addDelayedListener(500, pnlTooltip, "Show Tooltip", function(component, event)
          		{
          			if (!event.hover || this.get("tooltip") == "")
          				return;
          
          			this.showControl(true);
          		});
          	}
          
          	const bcTooltipButton = Engine.createBroadcaster({id: "valueChanged", args: ["component", "value"]});
          	bcTooltipButton.attachToComponentValue("btnTooltips", "Tooltips button toggled");
          	
          	bcTooltipButton.addListener({}, "Enable - disable tooltips", function(component, value)
          	{			
          		addRemoveListeners(value);
          	});
          }
          

          Libre Wave - Freedom respecting instruments and effects
          My Patreon - HISE tutorials
          YouTube Channel - Public HISE tutorials

          Oli UllmannO orangeO 2 Replies Last reply Reply Quote 3
          • Oli UllmannO
            Oli Ullmann @d.healey
            last edited by

            @d-healey
            Thank you very much, David! :-)

            My HISE Version does not have getInterfaceSize so I guess I have to update. ;-)

            1 Reply Last reply Reply Quote 0
            • Oli UllmannO Oli Ullmann has marked this topic as solved on
            • clevername27C
              clevername27 @Oli Ullmann
              last edited by

              @Oli-Ullmann I've experienced similar things—I think that whole system in HISE has serious issues, though I don' know what may or may not be happening in your case.

              1 Reply Last reply Reply Quote 1
              • orangeO
                orange @d.healey
                last edited by orange

                @d-healey said in Delayed broadcaster fires twice:

                Here's my floating tooltip script, maybe you can get something useful from it.

                Have you ever tried this method with ZoomPanel Dragger? It works normally without this tooltip code. But with this tooltip code, it crashes.

                If you try to resize the GUI from the Zoom Panel you will see a crash. I think there is a conflict with Broadcaster. Is there a solution for this? Or any other tooltip method?

                HiseSnippet 3316.3ocsZstbabaEdosYZHaSaRm7i1+gvejgxglZIotZGmnKVxlSrj4HREaGMd7.tKHIFubA6tXkDShmNSeR5iRdjZeBZOGf8BVxkxNtMxVW.v4.7cN3bC.rWfvgEFJBrJUcv7YLqR+gx8m6Kmb3DJ22p6irJ8okOxmNziQFHDdR9LqClOiFFxbsJU51OFopTk6Xo95e8sGP8n9Nrrtrr9dA2g8T9TtLq2d68cbOuiotrA7oFTuwdccD9GJ7DQ.htcYaqYTm2PGyNkhjcqxVOgFNwpzcK6Lb3PV6QNtTa5nVc1gsQ6M1bC6N6ZObms2XSmc1xAGdCqRezQtboHnujJYgVktyAB248mHtxWu.eOOjCRG1nkUeXk0cervyEEQrWqCmv8b6knpBsfYoWlh61ZE2mW9DtKOseSEHN.IiCSEXoakGd2NG7ZYBOaC3U.jJY.o6ngzmUtuS.elLaDDO+9xc8krfQTXexDJZZst0m+WKen.nvW1bJ8MriCfFobTeKa6FD3Gq8fpUqBaVgRxkz.h1FI1Dg7PRxLLlIOTLclvGZTuVNppASQ1DD24q646sR1MnIOyGHjRwzePHl1i5yV8Dr.c0TBw52sJA95Pwr4A7wSjj11s2nA9yMIOhdI2k7DF0iMuphrAS3gjQbve.+c.iQBEijWQCX2mLWDQbn9j.lKOTFvGFIAxjDpu65h.xTgKezb0r.cF46xBHxILBnZmFRDiTMd7omSdLymEP8H8hF5wcHOEbf7CYDZHYF1S3DlKYndhPVNFQQ+XTPNV.yLUxE9MHLNLd.4RVPHzlzIYQhmwFDQfZVpSkH3CHhYHiqAHdNwCrHS4sYARelP5R39pIdhXFHOSfoCjvq.ebxPFIJjMJxqgZB.pIOu6fm7ryGP1+zWRd99mc19mN3kO.nVNQ.ixtjomK9zYdbXpAoJf5KmCfWMEmbzYG9Dfm8On6S6N3kfLPNt6fSOpeexwO6Lx9jd6e1ftGd9S2+LRuyOq2y5eTSReFhKlZBtAU7H01DnEcYRJ2KLVreIrwFBnyykLgdIC1fcX7KArQINfYy6duSMKTOg+XkbloGaR5Nh3KjMHg.B+5IR4r6u95Wc0UMG6G0TDLdcO8LDt92zr5cWuZUeHTXHDVLMfbX0epZEsufT2SpEeH3IX5ADVGr3qTsx5qa5ukv8GfKXEi1MAMzUHWABu5indgrkHfAy.SECvsVCRBMKQTOHzo7LvXf6ypOJx2AMJqOdspU.IsB5vSA.JAcHhtmJbndGfV8g0asItlJRBnt7nPC5pWanH.74NSMfx2uBnIF2zMfd0iBDy5Og5JtpNsAQmAJrItWsu2rIz5I8LzCRH0fX2bm0ZP1TOGiQLqIn9xbZr7i0iVCXsUSHDpBqiaB1Admg3m4dFyQR8G6wPTnkfecqAWxllsJ1M6jrHnPtzhbA8B6WQ9pDc05DHtG8hVK2U6WQtWVWswt5juqWkfWP1Lf7wf8vyAb1GrX49iqWaJDaLZJr62pMhO6X3kIcYxhjcsLQVLjh883i8YtCfQMINIoBfsFjZfOiDBCqrQeapQ+ww1RgUqv88.qKRh008I6CQYlun2h1hyCsv.m9vHOIXPcwqdPZmTOubdaFdM6aNT8ZJnDykDROiTeQMcR2Chf7R9fRItceONXnl0d.5xj0Dl1ghCDWm0iNclBWv+wnX0uFiImCdfznDmJ7Qj5ew0Z8Vh63Z3nUvHAfWWDSsCpH75EzujG9PBHLqf5uPIZMwA.m3vTtgdgknHtzp0lyhBmT+50dPEkD7VbCCFRFE3Gq3wMx3swCBDTWGZHjepRRvqgNwAQRp.3H+wvFbSm.FjGyfi5+TMtas6SRkHPIRCFGBccQMmDkE1KlIRV6UJym7SeSpTRclLPjpbOQ.Y4N5R0V8RQgg4BLFHGB6FCgvGg3jqi+rfUHg5BdmSEWBELCXExjDVODqL79D+noCYAwFjJMsZfz8zE.XPtYodsymA0DvHyTJmYhPNtbZSx2EqX0nDiZ1pjrw7.8FEtSsn5w0MkeiX6fXWLNZjpApmtCzPUIfLU.wX57jxP6y+QVdustlCUWGAphJ7Pno4aCR5BrfcsVxx33JtqbBPercDPbenZG+wOG6u3.OFA21RGbCBjt8lKNyWuHJdrmXH0qWr13E0Q1xQfdMWCiyBAcSVaidWbIleyKwKUKQK60xbbyDnqqgCt3h7M4U9PdCsybdwZQZJ.s2iDqPXP1exxK8WSrKZlKFqyyg0mvv52K.rsVBryWBrsLAa5Lcujj7ZdCXyvZSTkQUIMlmxPs4DvqIf7y+Lo9pLwhCcZhkhJYRmvZE9UOh4Qmyxbu5fmGKuOVNG12GWqhDhBLvMi7mDAnZQRhLHxPPda0khQqy2ciAo4tPH5KodQL3jz9iUELhgoWJJshlEiRqWfkCS+8HwKdNTXRRJkFOeBhLoX7Xu3xGJXZMBu8SuEXO9FRtGdjH0eEqyBWg5WgYLVtdWtfn9ZJPc3ppvNkBTxAcb1WYmP.Oo6SfSe5wBxNj.FH8jtm95e3YO6DXKvt411OH2X6+hjwZ2L+PX2ut+fi5o3qkMt+aNNTd13wrfGQkXA5WPZ0xtQK6cazZiNMZ0wtQ6V6zXqsglaC+4Vvu2rwVvur2YotVfAfB63+UvPKzUJkKOzBKyt6VH75fcY2X2sRWf78rLBPHuEzSmjwqV4lwXdFJ.n4VwUfS61MZ2tQqcxVj78rRb1ZyVqffhgYB8EfybqnBms.gGT+jWosNJv9nGENBbV1as2O1Y7wSqVwfvldPTgiCDSQqp5FVXZZW3Jcd2Ge7lOIUZOSfSR0HNUCTxBMNx3W9kjrtf54DvIGoiWi7sf+vtj6idEaZdtNkTYHMMHWzBJO.9+132ux37IKUKHN6nfUWUsTChvOVDTsW.Bf9TnpHaVhZPUR5gfvHBpCS22Fe6WmgY1NTD.gYNiEBY9zjTC.esSEASodwcXbLXsx3BHSisBwwKhY1PUs4YPdgskFjjbBEtiogZb4wYaYIYoPYdwMhGRLRXEmMlORyRSGOtyaXtoI3xX9GgksujFfmiqOSBlHiUo4P37TfYOcp82ZNaSQzc9rzYKW0ulDh6yFIUgCCUfoRtzmURpr0kSGK7o3AWNAM5C+aAR7tVuK7MTgS7eoqK.o2IJH.VRD12rjTIwuqG+Z04hrSpsHOteATzTVqWpgoIe4n8tl..q.E.WZQc2Dqub0rl7MB3ozq6CGTlcL0QJBxWoObhWFyO9BezEMgWFQ1DYpOicMJx.3qxTKoqeN19J.4YY7RqxdI5h2xlx8qa1eiEjhUv88hYezTg6B7mt3ZVKZQCvZiVfsjj6MRSkmszntAUACDmGhmfxjyXyQvrvz55KdXFCJqBk0ckTStPSStLJUq3ayNg3RkOuTYK3WoA+D9mJjrm4WeMrvEfPxhCMZTgiEWdDTwSgCiu2TvMwXc8AsSqQKlPqR2I+C0Td0OTi46H4nsaMHT320mKe1Ll+pdcIqXicKffXTA+kT8jN+wxl2PjE20pzuq724KF1xRAXyWdy58l41+uvbmBX97tXFZ7UohkEP9lwBjbT0U5QrK4NL8aTUo7iXguQJlYU5iRKSGTuuSw85rEju27zF+xv8hK91pTuxOUDvlRfBwilRbgMk.RH9dLSYR77w9gLGIFIlPc4y3g3MTRXdb0sw6BLPX7nPvujHY.xBPkx6MBaafv8hLQXPFB+5x6KwmXAVIQHgAPywIJjNMR0.VbofHb4BvOcrOOLjOEHyMxgCT7qBMcLPyu7yFnYu+dFZ1srXJrJjKEdQyjzPBMDTbLeWJgEBJE8nZ8H3Jy.uLe2nvljbPoRdnnOyjBJ+ox4N30p1Bs9x8vq9sfmdVcmLYzQ2ah5b5Y8bPlv.quw4fsBoWx552KfAwqRdC0LL+G0X9SJabcpJH+IkMN+kAf+zIl.di8huFUXinD1gIP+m+4+8vEA5ub1dIuF.9j6azd6c6Xuyla0xJ6B70CryV1s1ciM11J61v0CramNsauw11V5W0.uCCSWPy25vr+UoetLI9UoaapX93UoX9rxKTGmgx4u7OLTNPiE111bossMy11Vu7iOuKdku7eD8F0OHIbdZviTpeVvjasgfEuZoJrJ8lUQarbW0pk0xOK9mV9DgajGUl+U5wOKCwC.KYtmFGubQeHxwbyOqC+e6o6eeg3mUtGW5LoXLdqBvHD+82BLF+Ad3SJeznQP.zL.dmxG+hea9zMXoON2Xnlm.NXnU9zno8AWAG0sCAVeXF4R2BSaoaam3I1GBQoZ7efuhGrE1tT7fsRFzZJ0IP7ZGcdO7iTwGq5Avju5ieRkxmfsIEjpcJ2k+ZGm7S0RL19CkwNenLtwGJia9gx3VenLt8GJi67tYD+.3reDDsR61XYcRuiTEnTpzQIAtg3d+W.ahf3OB
                

                develop Branch / XCode 13.1
                macOS Monterey / M1 Max

                d.healeyD 1 Reply Last reply Reply Quote 0
                • d.healeyD
                  d.healey @orange
                  last edited by

                  @orange said in Delayed broadcaster fires twice:

                  Have you ever tried this method with ZoomPanel Dragger?

                  I use a zoom panel dragger and haven't noticed an issue.

                  Here's my zoom handler script

                  /*
                      Copyright 2024, 2025 David Healey
                  
                      This file is free software: you can redistribute it and/or modify
                      it under the terms of the GNU General Public License as published by
                      the Free Software Foundation, either version 3 of the License, or
                      (at your option) any later version.
                  
                      This file is distributed in the hope that it will be useful,
                      but WITHOUT ANY WARRANTY; without even the implied warranty of
                      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
                      GNU General Public License for more details.
                  
                      You should have received a copy of the GNU General Public License
                      along with This file. If not, see <http://www.gnu.org/licenses/>.
                  */
                  
                  namespace ZoomHandler
                  {
                  	const zoomLevels = [0.5, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0];
                  	const MIN_ZOOM = 0.75;
                  	const MAX_ZOOM = 4.0;
                  	const ZOOM_STEP = 0.10;
                  	const interfaceSize = Content.getInterfaceSize();
                  
                  	//! pnlZoom
                  	const pnlZoom = Content.addPanel("pnlZoom", 0, 0);
                  	pnlZoom.set("parentComponent", "pnlMain");
                  	pnlZoom.setPosition(interfaceSize[0] - 12, interfaceSize[1] - 12, 12, 12);
                  	pnlZoom.set("allowCallbacks", "All Callbacks");
                  	pnlZoom.setControlCallback(onpnlZoomControl);	
                  	
                  	inline function onpnlZoomControl(component, value)
                  	{
                  		Settings.setZoomLevel(value);
                  	}
                  	
                  	pnlZoom.setPaintRoutine(function(g)
                  	{
                  		g.setFont("phosphor", 12);
                  		g.setColour(this.get("textColour"));
                  		g.drawAlignedText("\ued3a", this.getLocalBounds(0), "centred");
                  	});
                  		
                  	pnlZoom.setMouseCallback(function(event)
                  	{
                  		this.data.hover = event.hover;
                  		
                  		if (event.mouseUp)
                  			return;
                  		
                  		if (event.clicked)
                  			this.data.zoomStart = Settings.getZoomLevel();
                  	
                  		if (!event.drag)
                  			return this.repaint();
                  	
                  		if (!this.data.allowDrag)
                  			return;
                  
                  		var diagonal = Math.sqrt(interfaceSize[0] * interfaceSize[0] + interfaceSize[1] * interfaceSize[1]);
                  		var currentZoom = Settings.getZoomLevel();
                  		var dragPixel = 0;
                  		
                  		if (event.dragX > event.dragY)
                  			dragPixel = (event.dragX * currentZoom) / interfaceSize[0];
                  		else
                  			dragPixel = (event.dragY * currentZoom) / interfaceSize[1];
                  		
                  		var maxScaleFactor = Content.getScreenBounds(false)[3] / interfaceSize[1];
                  		var diagonalDrag = this.data.zoomStart + dragPixel;
                  		
                  		diagonalDrag += (ZOOM_STEP / 2);
                  		
                  		diagonalDrag = Math.min(diagonalDrag, maxScaleFactor);
                  		
                  		diagonalDrag -= Math.fmod(diagonalDrag, ZOOM_STEP);
                  		diagonalDrag = Math.range(diagonalDrag, MIN_ZOOM, MAX_ZOOM);
                  		
                  		var zoomToUse = diagonalDrag;
                  
                  		if (currentZoom != zoomToUse)
                  		{
                  			this.setValue(zoomToUse);
                  			this.changed();
                  		}			
                  	});
                  	
                  	//! Functions
                  	inline function allowZoom(panel: ScriptObject, on: number)
                  	{
                  		panel.data.allowDrag = on;
                  		panel.setMouseCursor(on ? "BottomRightCornerResizeCursor" : "NormalCursor", Colours.white, [0, 0]);
                  		panel.repaint();
                  	}
                  
                  	//! Broadcasters
                  	const bcZoomPanelValue = Engine.createBroadcaster({"id": "bcZoomPanelValue", "args": ["component", "value"]});
                  	bcZoomPanelValue.attachToComponentValue("pnlZoom", "");
                  
                  	bcZoomPanelValue.addComponentValueListener("cmbZoom", "If the zoom panel is used, set the zoom combo box to custom", function(index, component, value)
                  	{
                  		if (zoomLevels.contains(value))
                  			return zoomLevels.indexOf(value) + 1;
                  
                  		return zoomLevels.length + 1;
                  	});
                  	
                  	//! bccmbZoomValue
                  	const var bccmbZoomValue = Engine.createBroadcaster({"id": "bccmbZoomValue", "args": ["component", "value"]});
                  	bccmbZoomValue.attachToComponentValue("cmbZoom", "");
                  
                  	bccmbZoomValue.addComponentValueListener("pnlZoom", "pnlZoom will follow changes to cmbZoom", function(index, component, value)
                  	{
                  		return value - 1 < zoomLevels.length ? zoomLevels[value - 1] : this.getValue();
                  	});	
                  
                  	//! Calls
                  	allowZoom(pnlZoom, true);
                  	pnlZoom.setValue(Settings.getZoomLevel());
                  	pnlZoom.changed();
                  }
                  

                  Libre Wave - Freedom respecting instruments and effects
                  My Patreon - HISE tutorials
                  YouTube Channel - Public HISE tutorials

                  orangeO ustkU 2 Replies Last reply Reply Quote 2
                  • orangeO
                    orange @d.healey
                    last edited by

                    @d-healey This method doesn't crash. Thank you!
                    The interesting thing is that the other zoom panel dragger method does not have Broadcaster but also crashes with the tooltip.

                    develop Branch / XCode 13.1
                    macOS Monterey / M1 Max

                    1 Reply Last reply Reply Quote 1
                    • HISEnbergH
                      HISEnberg @Oli Ullmann
                      last edited by HISEnberg

                      @Oli-Ullmann I have this working without firing issues, and it worked well with the fadeComponent. I think I am having general issues with the fadeComponent on other systems so I am actively removing, but it did work on the compiled plugin (at least on my systems)

                      const var lbl_Tooltip = Content.getComponent("lbl_Tooltip");
                      
                      
                      // Broadcaster definition
                      const var Bc_Tooltip = Engine.createBroadcaster({
                        "id": "Bc_Tooltip",
                        "args": ["component", "event"],
                        "tags": [],
                        "colour": 2432630784
                      });
                      
                      // attach to event Type
                      Bc_Tooltip.attachToComponentMouseEvents(Components, "Clicks & Hover", "");
                      
                      
                      // add listeners
                      var lastTooltipText = "";
                      Bc_Tooltip.addListener("Tooltip Listenet", "Set tooltip", function(component, event)
                      {
                          if (event.hover)
                          {
                              var tooltipText = component.get("tooltip");
                      
                              lbl_Tooltip.set("text", tooltipText);
                              lbl_Tooltip.fadeComponent(true, 200);
                              lastTooltipText = tooltipText;
                          }
                          else
                          {
                              lbl_Tooltip.fadeComponent(false, 200);
                          }
                      });
                      
                      
                      1 Reply Last reply Reply Quote 0
                      • ustkU
                        ustk @d.healey
                        last edited by

                        @d-healey @orange Interesting, the zoom handle I was using is crashing a lot too so I removed it... I'll study and try that implementation, thanks, Dave! ☺

                        Can't help pressing F5 in the forum...

                        1 Reply Last reply Reply Quote 1
                        • First post
                          Last post

                        33

                        Online

                        1.8k

                        Users

                        12.0k

                        Topics

                        104.1k

                        Posts