Scroll area in UA



  • On 12/07/2018 at 07:46, xxxxxxxx wrote:

    I have a User Area with multiple (vertical) images in it.
    Now I want to add a vertical scroll bar to scroll through the images.
    But I do not understand fully, the relation between the ua size and the visible area size?

    What is the best place to define the visible area?
    How do I use SetVisibleArea() when the user area is resized?

    A little example would help me for certain!

    Here the code.

    import c4d
    from c4d import bitmaps, gui, plugins, utils, documents
    import collections, os, sys
      
    PLUGIN_ID = 10000010 #TestID only!!!!!!!!!!!!
    scrollGroup = 1001
      
    class Area(gui.GeUserArea) :
      
        def __init__(self) :
            self.bmp = c4d.bitmaps.BaseBitmap()
      
        def Sized(self, w, h) :
            print "Sized: ", w,h
            return     
      
        def DrawMsg(self, x1, y1, x2, y2, msg) :
        
            self.DrawRectangle(x1, y1, x2, y2)                                #Draws the UA rectangle area
            
            path = os.path.join(os.path.dirname(__file__), "Library", "Airbus_A380.jpg")
            result, ismovie = self.bmp.InitWith(path)
            
            x1 = 10
            if result == c4d.IMAGERESULT_OK:
                y1 = 10
                self.DrawBitmap(self.bmp, x1, y1, 200, 200, 0, 0, 200, 200, c4d.BMP_NORMAL)    #first        
                y1 = 220
                self.DrawBitmap(self.bmp, x1, y1, 200, 200, 0, 0, 200, 200, c4d.BMP_NORMAL)    #second     
                y1 = 430
                self.DrawBitmap(self.bmp, x1, y1, 200, 200, 0, 0, 200, 200, c4d.BMP_NORMAL)    #third
        
    class MyDialog(gui.GeDialog) :
      
        def __init__(self, area) :
            self.area = area
            
        def CreateLayout(self) :
            self.ScrollGroupBegin(scrollGroup, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_VERT)
            
            self.GroupBegin(1003, c4d.BFH_CENTER | c4d.BFV_CENTER, cols=1)
            self.GroupBorderNoTitle(c4d.BORDER_NONE)
            self.GroupBorderSpace(0, 0, 0, 20)
            self.AddUserArea(1, c4d.BFH_LEFT | c4d.BFV_TOP) 
            self.AttachUserArea(self.area, 1)
            self.GroupEnd() #end UA group
            
            self.GroupEnd() #end scrollgroup
      
            self.GroupBegin(0, flags=c4d.BFH_FIT, cols=1)
            self.AddButton(1027, flags=c4d.BFH_LEFT, initw=100, name="Test")  #Test button
            self.GroupEnd()
      
            return True
                    
        def Command(self, id, msg) :
      
            if (id == 1027) :
                print self.GetVisibleArea(scrollGroup)   
                self.SetVisibleArea(scrollGroup, 0,0,250,250)
      
                self.area.Redraw()
                return True
                
            return True
            
    class MBLibrary(plugins.CommandData) :
        
        area = Area()
        dialog = None
      
        def Execute(self, doc) :
            if self.dialog is None: self.dialog = MyDialog(self.area)
            return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=500, defaulth=120)
        def RestoreLayout(self, sec_ref) :
            if self.dialog is None: self.dialog = MyDialog(self.area)
            return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
      
    if __name__ == "__main__":
      
        pluginString = "MB Library V01"
       
        bmp = bitmaps.BaseBitmap()
        dir, f = os.path.split(__file__)
        fn = os.path.join(dir, "res", "icon.tif")
        bmp.InitWith(fn)
        okyn = plugins.RegisterCommandPlugin(id=PLUGIN_ID, str=pluginString, info=0, help=pluginString, dat=MBLibrary(), icon=bmp)
                                      
        if (okyn) : 
            print pluginString + " initialized."
        else: print "Error initializing " + pluginString
      
    
    


  • On 16/07/2018 at 07:48, xxxxxxxx wrote:

    Hi Pim,

    The ua size is the total size of the GeUserArea, without any scrolling, so it's the full GeUserArea size, which can be bigger than the screen of course.
    The visible area is the part which is currently visible in this GeUserArea.

    Let' take an example, I get a ua of a 2000 pixels height, but my dialog is only 500 pixels height. So the Visible area will only be 500 pixels, but from the 2000 pixels, displayed pixels can be from 0 to 500 or either 1000 to 1500.

    But looking at your code there is few adjustments to make. For example, you initialize the parent group to BFH/BFV_CENTER, so by default a GeUserArea it will be a square of 4,4 pixels since there is nothing inside, please use BFH/BFV_SCALEFIT instead, it will then automatically scale according to the size you define in GetMinSize function.

    On a side note since you are going to draw more than it's allowed (by that I mean you will draw from pixel 0 to 2000 and then crop it using a scrollGroup in order to allow custom display size) so make sure to call SetClippingRegion in the DrawMsg function.

    Here is your example fixed

    import c4d
    from c4d import bitmaps, gui, plugins, utils, documents
    import collections, os, sys
      
    PLUGIN_ID = 10000010 #TestID only!!!!!!!!!!!!
    scrollGroup = 1001
      
    class Area(gui.GeUserArea) :
      
        def __init__(self) :
            self.bmp = c4d.bitmaps.BaseBitmap()
      
        def Sized(self, w, h) :
            print "Sized: ", w,h
            return
      
        def GetMinSize(self) :
          #do a calculation here
          return 400, 430 + 200
      
        def DrawMsg(self, x1, y1, x2, y2, msg) :
            self.DrawSetPen(c4d.COLOR_BG_HIGHLIGHT)
            self.SetClippingRegion(x1, y1, x2, y2)
            self.DrawRectangle(x1, y1, x2, y2)                                #Draws the UA rectangle area
            
            path = os.path.join(os.path.dirname(__file__), "Library", "Airbus_A380.jpg")
            result, ismovie = self.bmp.InitWith(path)
            
            x1 = 10
            if result == c4d.IMAGERESULT_OK:
                y1 = 10
                self.DrawBitmap(self.bmp, x1, y1, 200, 200, 0, 0, 200, 200, c4d.BMP_NORMAL)    #first        
                y1 = 220
                self.DrawBitmap(self.bmp, x1, y1, 200, 200, 0, 0, 200, 200, c4d.BMP_NORMAL)    #second     
                y1 = 430
                self.DrawBitmap(self.bmp, x1, y1, 200, 200, 0, 0, 200, 200, c4d.BMP_NORMAL)    #third
        
    class MyDialog(gui.GeDialog) :
      
        def __init__(self, area) :
            self.area = area
            
        def CreateLayout(self) :
            self.ScrollGroupBegin(scrollGroup, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, c4d.SCROLLGROUP_VERT)
            
            self.GroupBegin(1003, c4d.BFH_SCALEFIT|c4d.BFH_SCALEFIT, cols=1)
            self.GroupBorderSpace(0, 0, 0, 20)
            self.AddUserArea(1005, c4d.BFH_SCALEFIT|c4d.BFH_SCALEFIT)
            self.AttachUserArea(self.area, 1005)
            self.GroupEnd() #end UA group
            
            self.GroupEnd() #end scrollgroup
      
            self.GroupBegin(0, flags=c4d.BFH_FIT, cols=1)
            self.AddButton(1027, flags=c4d.BFH_LEFT, initw=100, name="Test")  #Test button
            self.GroupEnd()
      
            return True
                    
        def Command(self, id, msg) :
      
            if (id == 1027) :
                sizes = self.GetVisibleArea(scrollGroup)
                ySize = sizes["y2"] - sizes["y1"] # Get the current size displayed
                #Jump to the 2nd picture
                print self.area.GetHeight()
                self.SetVisibleArea(scrollGroup, 0,220, 0, 220 + ySize)
      
                #self.area.Redraw()
                return True
                
            return True
      
            
    class MBLibrary(plugins.CommandData) :
        
        area = Area()
        dialog = None
      
        def Execute(self, doc) :
            if self.dialog is None: self.dialog = MyDialog(self.area)
            return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=500, defaulth=120)
        def RestoreLayout(self, sec_ref) :
            if self.dialog is None: self.dialog = MyDialog(self.area)
            return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
      
    if __name__ == "__main__":
      
        pluginString = "MB Library V01"
       
        bmp = bitmaps.BaseBitmap()
        dir, f = os.path.split(__file__)
        fn = os.path.join(dir, "res", "icon.tif")
        bmp.InitWith(fn)
        okyn = plugins.RegisterCommandPlugin(id=PLUGIN_ID, str=pluginString, info=0, help=pluginString, dat=MBLibrary(), icon=bmp)
                                      
        if (okyn) :
            print pluginString + " initialized."
        else: print "Error initializing " + pluginString
    

    If you have any questions please let me know,
    Cheers,
    Maxime



  • On 17/07/2018 at 03:30, xxxxxxxx wrote:

    Great explanation!
    Thanks, Pim



  • On 18/07/2018 at 08:38, xxxxxxxx wrote:

    Sorry, more questions on scrolling UA.

    Next step is to size the images / thumbnails to be displayed.

    For example, when I click the test button, the size of the thumbnail is decreased from 200 to 20.
    Displaying the sized thumbnails is no problem, but how to size the vertical scroll bar, thus that it indicates the new size?

    Do I use GetMinSize() or SetVisibleArea().
    If so, where and when do I call GetMinSize()?

            if (id == 1027) :
                newSize = 20
                self.area.GetMinSize()
                print "SetVisibleArea: ", self.SetVisibleArea(scrollGroup, 0, 0, 400, 3*(newSize+10))
                self.area.Redraw()
    


  • On 18/07/2018 at 09:39, xxxxxxxx wrote:

    Hi Scott,

    You don't have to call GetMinSize, it's called automatically when the parent(owner of the GeUserArea) is drawn/sized, in your case, group 1003 which is owned by your ScrollGroup.
    So in order to support what's, you want I've made few adjustments.

    class Area(gui.GeUserArea) :
        size = 300
        pictureCnt = 3
      
        def GetMinSize(self) :
            return 400, self.pictureCnt * self.size
      
        def DrawMsg(self, x1, y1, x2, y2, msg) :
            self.DrawSetPen(c4d.COLOR_BG_HIGHLIGHT)
            self.SetClippingRegion(x1, y1, x2, y2)
            self.DrawRectangle(x1, y1, x2, y2)  # Draws the UA rectangle area
      
            path = os.path.join(os.path.dirname(__file__), "Library", "Airbus_A380.jpg")
            result, ismovie = self.bmp.InitWith(path)
      
            x1 = 10
            if result == c4d.IMAGERESULT_OK:
                for i in xrange(0, self.pictureCnt) :
                    y1 = self.size * i
                    self.DrawBitmap(self.bmp, x1, y1, self.size, self.size, 0, 0, self.size, self.size, c4d.BMP_NORMAL)
    

    and in the GeDialog

    if (id == 1027) :
    	self.area.size = 400
    	self.LayoutChanged(scrollGroup)
    	sizes = self.GetVisibleArea(scrollGroup)
    	ySize = sizes["y2"] - sizes["y1"]  # Get the current size displayed
    	pictureId = 1 # ID start from 0
    	self.SetVisibleArea(scrollGroup, 0, self.area.size * pictureId, 0, self.area.size * pictureId + ySize)
    	return True
    

    So we define the new size of the picture then we call self.LayoutChanged(scrollGroup) which will call DrawMsg and also GetMinSize in order to know the size of the UserArea then finally our scrollGroup is drawn according to these data. Then after is up to us to scroll where we want.

    Maybe off topic, but I did a library with thumbnail on my personal time some time ago, it's available in here you may found some interesting stuff in it.

    Again if you have any question, let me know! :)
    Cheers,
    Maxime


Log in to reply