Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Portlet resizing bugs when using with DrawPane

    Hi,

    SmartClient_v130p_2023-08-12_Pro

    Portlet members resized() function is not getting called if the height of the member is set via the setHeight() function or if the member was resized at least once by the user.

    The isolated test case is given below.
    Steps to reproduce:
    1. There, by default everything works correctly. If you resize the portlet, then both portletsResized() and DrawPane resized() functions are called.
    2. Resize the DrawPane by dragging its border (not the portlet's border). The DrawPane resized() is called.
    3. Then, resize the portlet containing the DrawPane. Notice that only the portletsResized() is getting called now.
    Alternatively:
    3. Uncomment this line : // member.setHeight(portlet.getHeight()-35); //this kills resizing call
    Or uncomment any of the lines that call setHeight() on the DrawPane.
    Notice that when resizing the portlet the DrawPane resized() function is never called.

    Additionally, on the initial draw there is 50% of blank space appears below the DrawPane if its setHeight() call is not invoked.


    Code:
    isc.defineClass("MyPortlet", "DrawPane");
    isc.MyPortlet.addMethods({
        redrawOnResize : true,
       // defaultWidth:830, defaultHeight:830,
       // defaultWidth:"100%", defaultHeight:"100%",
        canDragResize:true,
        //minWidth:150, minHeight:100,
        headerMargin:2, headerHeight:23,
        showEdges:true,
         mytext : "original",
        //width:"99%", height:"99%",
        //width:"400", height:"400",
        backgroundColor:"#F3FCA0",
    
        initWidget:function(){
            this.Super("initWidget", arguments);
            this.paneProps = {
                drawPane: this,
                canDrag: true,
                //paneSize: this.resetSize()
            };
        }
    
        ,resized:function(){
            this.Super('resized', arguments);
            console.log("DrawPane resized "+this.mytext);
            this.paneProps.paneSize = this.resetSize();
         // this.redraw(); //markForRedraw();
        }
        ,resetSize:function(){
            var offset=4,size,w = this.getInnerWidth(), h=this.getInnerHeight();
            size = w;
            if(w>h) size=h;
            size -=offset;
            return size;
        }
    });
    
    function createPortletToolStrip(actId){
        return isc.ToolStrip.create({
            height:15,
            members:[
                isc.Label.create({
                    contents:"label I am: toolbar for Id"+actId
                })
            ]
       });
    }
    
    function addPortlets2Layout(portal, portletsArr){
        for(let p=0; p<portletsArr.length; p++){
            let portProps=portletsArr[p];
            let portlet = isc.Portlet.create({
                title: portProps.rsltId,
                autoDraw:false
                ,height: portProps.height
            });
    
            portlet.addMember(createPortletToolStrip(portlet, portProps.rsltId));
            if(portProps.rsltId===1){
                portlet.addMember(
                    isc.MyPortlet.create({
                           ID:"myPortletID",
                            autoDraw:false,
                            mytext : "Portlet Resized Directly!"
                           // ,height:2*portlet.getHeight()-35 //this kills resizing call
                        })
                    );
                    //member.setHeight(portlet.getHeight()-35);
                let member=portlet.getMembers()[1];
               // member.setHeight(portlet.getHeight()-35); //this kills resizing call
            }
    
            portal.addPortlet(portlet, portProps.colNum, portProps.rowInCol);
    // let pr=portal.getPortlets()[p];
    // let member=pr.getMembers()[1];
    // if(member) member.setHeight(pr.getHeight()-55); //this kills resizing call
        }
    }
    
    var portal = isc.PortalLayout.create({
        ID: "portal",
        width: "80%",
        height: "90%",
        preventColumnUnderflow: true,
        canResizePortlets: true,
        showColumnMenus : false,
        autoDraw:false,
        portletsResized : function () {
            var message = "portlets resized from Layout\n";
            let portlets = this.getPortlets();
            for(let p=0; p<portlets.lentgh; p++){
                let member=portlets[p].getMembers()[2];
                member.setHeight(portlets[p].getHeight()-35);
            }
            console.log("PortletLayout: "+message);
        }
    });
    
    var portletsArr=[];
    portletsArr[0] = {rsltId:3, height:"100%", colNum:0,rowInCol:0};
    portletsArr[1] = {rsltId:1, height:400, colNum:1,rowInCol:0};
    portletsArr[2] = {rsltId:2, height:400, colNum:1,rowInCol:1};
    portletsArr[3] = {rsltId:4, height:400, colNum:1,rowInCol:2};
    
    addPortlets2Layout(portal, portletsArr);
    
    portal.show();
    //portal.resize();

    thank you.

    #2
    By design, resized() fires only when a portlet actually changes size, and does not fire when you make a programmatic change (as this would often require you to ignore notifications when you know you are going to trigger them).

    Further, by design, if you set a portlet to a specific size by either resizing it in the UI or explicitly setting its height with setHeight(), SmartClient layouts in general stop managing that dimension. This is required for good UX: you don't want the surrounding layout to just go ahead and undo an explicit size setting you applied. This is avoiding "fighting" the user.

    It's not clear what you're trying to achieve here, but if what you really wanted was to know when the portlets have been moved around, there's a separate "moved" notification for that.

    Comment


      #3
      I'm trying to make sure the DrawPane component fills the entire available portlet size whenever the portlet that contains it is resized for whatever reason (the entire portlet size minus the space occupied by the ToolStrip member of the same portlet). Since setHeight() is not available on the DrawItem, how would I go about that?
      Further, I want to make sure the DrawPane component is aware of it being resized so it can be redrawn based on the newly available dimensions.

      thank you.
      Last edited by genev; 11 Dec 2023, 13:28.

      Comment


        #4
        To achieve that, simply do nothing - filling space is the default. Just don't call setHeight() (because then we will respect what you set) and don't offer the user a resize control directly on this portlet - offer resizing on the overall layout instead.

        In this case, resized() will fire when you need it to.

        Comment


          #5
          I tried doing that but when initialized the DrawPane only fills 50% of the available space. So I tried forcing it to fill all available space by getting portlet dimensions and then using those to set height. So looks like there is a bug in the way the DrawPane is drawn initially.
          When I don't call setHeight() the resizing is happening correctly but the height of the DrawPane always stays at about 50% of the portlet size.

          Comment


            #6
            Setting a specific height in the properties on creation is the same as setHeight() - you're telling us what height you specifically want, instead of allowing the layout to handle things.

            Again, what you're looking for is the default behavior. Just stop trying to explicitly control height and you'll get what you're hoping for.

            Comment


              #7
              That's right but it doesn't work. Even when I don't set the height anywhere, the initially loaded DrawPane only occupies 50% of the available height. Please see the image attached. That's how it loads when I don't attempt to set the height. I commented out all setHeight calls and all height init properties. The resizing works but the initial vertical sizing is wrong.
              Click image for larger version

Name:	initHeightIssue.png
Views:	74
Size:	31.8 KB
ID:	271412

              Comment


                #8
                This screenshot seems to reflect code we don't have, so if you need more help, you should provide the code that has this effect.

                However, before doing that, there are some more troubleshooting steps to try:

                1) use the Watch tab to understand what elements have what size. Here, it looks as if you've created a Window or similar that has the right size, but something inside it does not have the right size

                2) resized() does not fire on init in general (overflow is the exception) so the typically technique is to run layout logic right before draw, and then on resized()

                3) different layout managers have different default behaviors - Portals and Layouts fill space by default, Stacks and simple Canvas containers do not. So you may have added an intervening layout manager that does not fill space

                4) some components have default sizes where appropriate. For example, buttons have a default height since it doesn't make sense to have a layout stretch a button. So check the default height of the components you're using, and if you want stretching where it's not the default, you set "*" or a percent size (just as with HTML / CSS).

                Comment


                  #9
                  1. I don't have a window.
                  2. I'm not relying on resize() to fire on init
                  3. I only have a PortalLayout and a Portlet with a ToolStrip (with a Label) and a DrawPane. Nothing else. Removing the ToolStrip (thus leaving only a Portlet with a single DrawPane member doesn't help either.

                  This is the complete standalone test case that generates the image attached:

                  Code:
                  isc.defineClass("MyPortlet", "DrawPane");
                  isc.MyPortlet.addMethods({
                      redrawOnResize : true,
                      canDragResize:true,
                  //    headerMargin:2, headerHeight:23,
                      showEdges:true,
                       mytext : "original",
                      backgroundColor:"#F3FCA0",
                  
                      initWidget:function(){
                          this.Super("initWidget", arguments);
                          this.paneProps = {
                              drawPane: this,
                              canDrag: true
                          };
                      }
                  
                      ,resized:function(){
                          this.Super('resized', arguments);
                          console.log("DrawPane resized "+this.mytext);
                          //this.paneProps.paneSize = this.resetSize();  //this is required to redraw but commenting out doesn't have any effect on initial sizing
                      }
                      ,resetSize:function(){
                          var offset=4,size,w = this.getInnerWidth(), h=this.getInnerHeight();
                          size = w;
                          if(w>h) size=h;
                          size -=offset;
                          return size;
                      }
                  });
                  
                  function createPortletToolStrip(actId){
                      return isc.ToolStrip.create({
                          height:15,
                          members:[
                              isc.Label.create({
                                  contents:"label I am: toolbar for Action "+actId
                              })
                          ]
                     });
                  }
                  
                  function addPortlets2Layout(portal, portletsArr){
                      for(let p=0; p<portletsArr.length; p++){
                          let portProps=portletsArr[p];
                          let portlet = isc.Portlet.create({
                              title: portProps.rsltId,
                              autoDraw:false
                          });
                  
                          portlet.addMember(createPortletToolStrip(portlet, portProps.rsltId));  //commenting out this line will remove the ToolStrip and its label. But it doesn't help.
                          if(portProps.rsltId===1){
                              portlet.addMember(
                                  isc.MyPortlet.create({
                                         ID:"myPortletID",
                                          autoDraw:false,
                                          mytext : "Portlet Resized Directly!"
                                      })
                                  );
                          }
                  
                          portal.addPortlet(portlet, portProps.colNum, portProps.rowInCol);
                      }
                  }
                  
                  var portal = isc.PortalLayout.create({
                      ID: "portal",
                      width: "80%",
                      height: "90%",
                      preventColumnUnderflow:true,
                      canResizePortlets: true,
                      showColumnMenus : false,
                      autoDraw:false,
                      portletsResized : function () {
                          var message = "portlets resized from Layout\n";
                          let portlets = this.getPortlets();
                          console.log("PortletLayout: "+message);
                      }
                  });
                  
                  var portletsArr=[];
                  portletsArr[0] = {rsltId:3, height:"100%", colNum:0,rowInCol:0};
                  portletsArr[1] = {rsltId:1, height:400, colNum:1,rowInCol:0};
                  portletsArr[2] = {rsltId:2, height:400, colNum:1,rowInCol:1};
                  portletsArr[3] = {rsltId:4, height:400, colNum:1,rowInCol:2};
                  
                  addPortlets2Layout(portal, portletsArr);
                  
                  portal.show();
                  Thank you.
                  Last edited by genev; 11 Dec 2023, 15:24.

                  Comment


                    #10
                    Hi - so, the Portlet is in fact the right size, as we said it was, and also, the troubleshooting instructions we gave lead quickly to the solution.

                    You've confused things a little because you made a subclass of DrawPane called MyPortlet. But your DrawPane is not a Portlet, it's just one of a few different widgets that you've put inside of a Portlet. To avoid confusion, we would recommend not naming your class MyPortlet, since your class is not a Portlet. We'll refer instead to this widget as the DrawPane.

                    Having cleared up terms, if you use the Watch Tab (#1 piece of advice listed above), you will see that the Portlet is in fact the right size. What's the wrong size is your DrawPane.

                    #2 piece of advice is to know your container. You are adding your DrawPane to a Portlet, which is a subclass of Window. Windows in general have a few built-in members, like the header, footer, resizer, and body area. The "body" area is where you put the contents. To put things in the body, you call addItem(). Doing this immediately fixes your problem, because the policy on the body is to fill space with any added items that don't have a height.

                    By instead using addMember() you're inserting yourself into the internal layout of the Window - basically adding something that is a peer to the header, footer, etc built-in components of Window. This becomes obvious in other skins which have a default border around the body area - you can see that your DrawPane isn't in the body. You can also see this in the Watch tab, of course.

                    Note that it is valid to call addMember() on a Window if you were trying to extend the core layout of the window, that is, you really meant to place something outside of the Window body area. That might make sense for a toolbar or similar where you want it to appear as if it's part of the window as such and not part of the body.

                    When you are adding something as a member rather than an item in the body, the policy for the Window as a whole is not to cause members to fill space. This is because, for the internal layout of the Window, the body area is supposed to fill space, and everything else is generally a fixed size. So, just for completeness, if you were adding your DrawPane as a direct member of the Window instead of adding it to the Window body, you could get it to fill by using height:"100%". Again, that's just for completeness - what you almost certainly want here is to put your DrawPane into the Window body via addItem().

                    Finally, just a note that all of these concepts in SmartClient are exactly the same as those in HTML/CSS and basically any other layout system ever created: there is a nested containment hierarchy and you have to put your widgets in the right place, and different kinds of containers have different policies for whatever is placed insider them. It's all straightforward and predictable if you just use advice #1 (use the Watch tab) and #2 (know your container).

                    Comment


                      #11
                      Great, thank you so much for all the details. This makes sense and the addItem works.

                      Comment

                      Working...
                      X