Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

UI tool: dynamicRects—just like normal rects, but dynamic!

edited May 19 in Code Sharing Posts: 1,278

Working off of the resizing code in @dave1707’s excellent scrolling-textboxes project, these are draggable and resizable rects that are as easy to use as the existing rect(x,y,w,h) command—and in some ways easier.

I think there are a couple-three cool enhancements to dave’s rect-dragging code, too.

  • When you tap or drag a dynamicRect, the draw order changes on the fly, so that whatever rect is currently selected draws itself on top of all the others.
  • When you’re resizing a rect, it will stay visible even if you drag one corner past the opposite corner.
  • The hotspots for dragging the corners extend a little outside the bounds of the rect itself, making them a lot easier to manipulate.
  • The corners are reserved for resizing, but the whole rect can be dragged by putting your finger down anywhere else on its insides.
  • Since dynamicRects are created with names, you can set them to show their names during runtime so you never get confused which is which.
  • You can get a dynamicRect’s exact size and position at any time by tapping it.

When you find the right position and size, you can note down those coordinates and add them directly into the dynamicRect command, which locks it down so that it acts just like a normal rect().

Tagged:

Comments

  • dave1707dave1707 Mod
    Posts: 9,421

    @UberGoober Heres something simple I threw together, don’t know how useful it would be. This is similar to what you say above. You can move a rect around and resize it. Drag a corner to resize, drag from center to move. But instead of writing down the coordinates when you get the size and position you want, you just tap on the center of the rect 5 times to lock it. After that you use it as normal. Tap 5 times again to unlock it if you what to change it.

    viewer.mode=STANDARD
    
    function setup()
        boxTab={}
        rectMode(CENTER)
        table.insert(boxTab,box(200,200,100,200,"box1",1))
        table.insert(boxTab,box(200,400,200,100,"box2",2))
        table.insert(boxTab,box(500,500,200,100,"box3",3))
    end
    
    function draw()
        background(0)
        for a,b in pairs(boxTab) do
            b:draw()
        end  
    end
    
    function touched(t)
        for a,b in pairs(boxTab) do
            b:touched(t)
        end  
    end
    
    box=class()
    
    function box:init(x,y,w,h,n,v)    
        self.x=x
        self.y=y
        self.w=w
        self.h=h
        self.sel=0
        self.lock=false
        self.dir=""
        self.name=n
        self.dist=20
    end
    
    function box:draw()  
        fill(188, 176, 175)  
        rect(self.x,self.y,self.w,self.h)
        fill(255)
        if self.lock then
            fill(255,0,0)
        end
        text(self.name,self.x,self.y)
    
    end
    
    function box:touched(t)
        if t.state==BEGAN then
            if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
                    t.y>self.y-self.h/2 and t.y<self.y+self.h/2 and self.lock then
                print(self.name.."  selected")
            end
            if math.abs(t.x-self.x)<self.dist and math.abs(t.y-self.y)<self.dist then
                self.sel=1
                if self.lock then print(self.name.." selected") end
                if t.tapCount==5 then self.lock= not self.lock end
            end
            if math.abs(t.x-(self.x+self.w/2))<self.dist and 
                    math.abs(t.y-self.y+self.h/2)<self.dist then self.dir="ur" end
            if math.abs(t.x-self.x-self.w/2)<self.dist and 
                    math.abs(t.y-self.y+self.h/2)<self.dist then self.dir="lr" end
            if math.abs(t.x-self.x+self.w/2)<self.dist and 
                    math.abs(t.y-self.y+self.h/2)<self.dist then self.dir="ll" end
            if math.abs(t.x-self.x+self.w/2)<self.dist and 
                    math.abs(t.y-self.y-self.h/2)<self.dist then self.dir="ul" end
        end
        if t.state==CHANGED and not self.lock then
            if self.sel==1 then
                self.x,self.y=t.x,t.y 
            elseif self.dir=="ur" then  
                self.w,self.h=self.w+t.deltaX*2,self.h+t.deltaY*2
            elseif self.dir=="ul" then  
                self.w,self.h=self.w-t.deltaX*2,self.h+t.deltaY*2
            elseif self.dir=="lr" then  
                self.w,self.h=self.w+t.deltaX*2,self.h-t.deltaY*2
            elseif self.dir=="ll" then  
                self.w,self.h=self.w-t.deltaX*2,self.h-t.deltaY*2
            end
            if self.w<50 then self.w=50 end
            if self.h<50 then self.h=50 end
        end
        if t.state==ENDED then
            self.sel,self.dir=0,""
        end
    end
    
  • Posts: 1,278

    @dave1707 I think there’s something off about how touches work in this project, for me, because often the rects don’t respond at all.

    In any case you do still have to write the coordinates down with this approach, if you want them to stay in a consistent place, because the sizes and positions of locked rects don’t persist between launches of the project—which would take some additional coding because the project doesn’t expose that information during runtime.

    I intend to have dynamicRects remember their own positions eventually but right now you can get the coordinates of a dynamicRect at any time by tapping it.

  • dave1707dave1707 Mod
    Posts: 9,421

    @UberGoober I don’t have any problems with the touch. There’s the variable self.dist that can be increased to make the touch areas larger. The center of the corner touch areas are the corners themselves. This was just a simple demo. The box info can be saved and read back in when the program starts. I’m not sure if I would use something like this anyways, but then I haven’t written anything lately that has a lot of buttons placed around the screen.

    Maybe it needs an option to create or destroy buttons on the fly.

  • Posts: 1,278

    @dave1707 I don’t know what to tell you, I’d say at least 1 out of 5 times, when I try to drag a rect to reposition it, it doesn’t respond at all.

  • dave1707dave1707 Mod
    edited May 19 Posts: 9,421

    @UberGoober I don’t know what to tell you, I don’t have any trouble with the touch areas. Did you try increasing the value in self.dist. Anyways, here’s another version. This one allows you to create or destroy a button on the fly. Put a name in the name box and slide one of the parameters.

    viewer.mode=STANDARD
    
    function setup()
        parameter.text("name",name)
        parameter.boolean("create",false,create)
        parameter.boolean("destroy",false,destroy)
        boxTab={}
        rectMode(CENTER)
        table.insert(boxTab,box(200,200,100,200,"box1",1))
        table.insert(boxTab,box(200,400,200,100,"box2",2))
        table.insert(boxTab,box(500,500,200,100,"box3",3))
    end
    
    function draw()
        background(0)
        for a,b in pairs(boxTab) do
            b:draw()
        end  
    end
    
    function touched(t)
        for a,b in pairs(boxTab) do
            b:touched(t)
        end  
    end
    
    function create()
        if name~="" then
            table.insert(boxTab,box(WIDTH/2,HEIGHT/2,200,100,name,3))
        end
        create=false
    end
    
    function destroy()
        if name~="" then
            for a,b in pairs(boxTab) do
                if b.name==name then
                    table.remove(boxTab,a)
                end
            end
        end
        destroy=false
    end
    
    box=class()
    
    function box:init(x,y,w,h,n,v)    
        self.x=x
        self.y=y
        self.w=w
        self.h=h
        self.sel=0
        self.lock=false
        self.dir=""
        self.name=n
        self.dist=20
    end
    
    function box:draw()  
        fill(188, 176, 175)  
        rect(self.x,self.y,self.w,self.h)
        fill(255)
        if self.lock then
            fill(255,0,0)
        end
        text(self.name,self.x,self.y)
    
    end
    
    function box:touched(t)
        if t.state==BEGAN then
            if t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
            t.y>self.y-self.h/2 and t.y<self.y+self.h/2 and self.lock then
                print(self.name.."  selected")
            end
            if math.abs(t.x-self.x)<self.dist and math.abs(t.y-self.y)<self.dist then
                self.sel=1
                if self.lock then print(self.name.." selected") end
                if t.tapCount==5 then self.lock= not self.lock end
            end
            if math.abs(t.x-(self.x+self.w/2))<self.dist and 
            math.abs(t.y-(self.y+self.h/2))<self.dist then self.dir="ur" end        
            if math.abs(t.x-(self.x+self.w/2))<self.dist and 
            math.abs(t.y-(self.y-self.h/2))<self.dist then self.dir="lr" end        
            if math.abs(t.x-(self.x-self.w/2))<self.dist and 
            math.abs(t.y-(self.y-self.h/2))<self.dist then self.dir="ll" end       
            if math.abs(t.x-(self.x-self.w/2))<self.dist and 
            math.abs(t.y-(self.y+self.h/2))<self.dist then self.dir="ul" end
        end
        if t.state==CHANGED and not self.lock then
            if self.sel==1 then
                self.x,self.y=t.x,t.y 
            elseif self.dir=="ur" then  
                self.w,self.h=self.w+t.deltaX*2,self.h+t.deltaY*2
            elseif self.dir=="ul" then  
                self.w,self.h=self.w-t.deltaX*2,self.h+t.deltaY*2
            elseif self.dir=="lr" then  
                self.w,self.h=self.w+t.deltaX*2,self.h-t.deltaY*2
            elseif self.dir=="ll" then  
                self.w,self.h=self.w-t.deltaX*2,self.h-t.deltaY*2
            end
            if self.w<50 then self.w=50 end
            if self.h<50 then self.h=50 end
        end
        if t.state==ENDED then
            self.sel,self.dir=0,""
        end
    end
    
  • dave1707dave1707 Mod
    Posts: 9,421

    @UberGoober It looks like the upper right corner doesn’t work right.

  • dave1707dave1707 Mod
    Posts: 9,421

    @UberGoober I think I have the four corners fixed in the code above.

  • Posts: 1,278

    @dave1707 It’s fun! I added this at line 88:


    if self.dir ~= "" or self.sel ~= 0 then print(self.name.." "..self.dir) name = self.name end

    ...it makes destroying boxes easier.

    If you wouldn’t mind a small idea offered, I’d recommend testing for any inner touches at all to make a rect be selected, instead of just near the center.

  • dave1707dave1707 Mod
    Posts: 9,421

    @UberGoober Theres a lot more that can be done with this, but it was something I thought I’d try. Adding code to save the boxTab table to a tab should be easy. That way this program could be used to layout a button screen and the table saved to a tab. That tab could then be copied to a new project and coded from there without having to manually place the buttons in the new code.

  • Posts: 1,278

    @dave1707 that’s exactly how my SimpleButtons work ;)

Sign In or Register to comment.