omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Changing button shape using up.Path

    Pythonista
    4
    11
    6240
    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.
    • RoninSage
      RoninSage last edited by

      I want to have a button that has a different shape than a rectangle. I think ui.Path is the way to go but I am having trouble implementing it. I have code for a simple button press. Could I get some help changing it so the button changes to say a hexagon?

      
      import ui
      # Define variables
      btn_counter=-1 # button pressed count
      btn_color=['red','magenta','blue','green','yellow','cyan'] # button colours
      btn_txt=['click again','click one more time','have another go','go again please', 'one last press','finally'] # button text when pressed
      # Define functions
      # What button1 does when tapped
      def button1_tapped(sender):
        global btn_counter # count number of times the button is pressed
        btn_counter+=1
        if btn_counter<=5: # cycle through button colours
          sender.title = btn_txt[btn_counter] # change button text when pressed
          sender.size_to_fit() # adjust button size to fit new text exactly
          button1.width=1.5*button1.width # change button width
          button1.height=2*button1.height # change button height
          button1.bg_color = btn_color[btn_counter] # change button colour when tapped
        else:
          view.remove_subview(button1) # remove button
          some_box.title = 'thank you for your time' # change box text
          some_box.size_to_fit() # change box size to fit new text exactly
          some_box.frame=(view.width*0.38,view.height*0.45,1.1*some_box.width,2*some_box.height) # change box location and size
      
      # Create display, further details see theBackground.py
      view=ui.View()
      view.present('fullscreen', hide_title_bar=True)
      view.background_color = (214/255,12/255,140/255)
      
      # Create button
      button1 = ui.Button(title='Click me') # initial button text
      button1.center = (view.width*0.38, view.height*0.45) # Button initial position
      button1.border_width = 5 # give button a border
      #button1.size_to_fit() # fit button around text exactly
      button1.width = view.width*0.3 # button width
      button1.height = view.height*0.2 # button height
      button1.bg_color = (.3,.31,.32) # button colour (.3,.31,.32,0) fof transparent
      button1.font = ('Chalkduster', 30) # button font type and size
      button1.tint_color=(1,1,1) # button font colour
      button1.action = button1_tapped # needed for when button pressed
      view.add_subview(button1) # display button
      
      # Include non-interactive box
      some_box = ui.Label(
        text='This is not a button', # box text
        background_color=(95/255,96/255,98/255), # box colour
        text_color='white', # box text colour
        alignment=ui.ALIGN_CENTER, # text alignment in box
        number_of_lines=0, # number of lines used in box
        frame=(10, 10, view.width-20, 100)) # box position (10 in, 10 down, view.width-20 wide, 100 high)
      some_box.font=('HoeflerText-BlackItalic', 40) # box font type and size
      view.add_subview(some_box) # show box
      
      
      1 Reply Last reply Reply Quote 0
      • brumm
        brumm last edited by

        Try changing the draw method in this example.

        1 Reply Last reply Reply Quote 0
        • enceladus
          enceladus last edited by

          May be this
          https://github.com/encela95dus/ios_pythonista_examples/blob/master/imagecontext4.py

          1 Reply Last reply Reply Quote 0
          • enceladus
            enceladus last edited by

            
            import ui, math
            # Define variables
            btn_counter=-1 # button pressed count
            btn_color=['red','magenta','blue','green','yellow','cyan'] # button colours
            btn_txt=['click again','click one more time','have another go','go again please', 'one last press','finally'] # button text when pressed
            
            def make_polygon(num_sides, x=0, y=0, radius=100, phase=0, line_width=5): 
                path = ui.Path()
                path.move_to(x,y)
                path.line_width = line_width
                for i in range(num_sides):
                    t = 2*math.pi*i/num_sides
                    x1, y1 = radius+radius*math.cos(t+phase), radius+radius*math.sin(t+phase)
                    if i:
                        path.line_to(x+x1, y+y1)
                    else:
                        path.move_to(x+x1,y+y1)
                path.close() 
                return path 
                
            def create_image(w, h, bg, fg):
                img = None
                with ui.ImageContext(w, h) as ctx:  
                    ui.set_color(bg)
                    rect = ui.Path.rect(0,0,w,h)
                    rect.fill()        
                    ui.set_color(fg)
                    path = make_polygon(6, 0, 0, h/2, math.pi/2) 
                    path.fill() 
                    img = ctx.get_image()
                return img   
                
            # Define functions
            # What button1 does when tapped
            def button1_tapped(sender):
              global btn_counter # count number of times the button is pressed
              btn_counter+=1
              if btn_counter<=5: # cycle through button colours
                sender.title = btn_txt[btn_counter] # change button text when pressed
                sender.size_to_fit() # adjust button size to fit new text exactly
                button1.width=button1.width # change button width
                button1.height=button1.width # change button height
                main_bg = (214/255,12/255,140/255)
                button1.background_image = create_image(button1.width, button1.height,
                                                    main_bg, btn_color[btn_counter])
                #button1.bg_color = btn_color[btn_counter] # change button colour when tapped
              else:
                view.remove_subview(button1) # remove button
                some_box.title = 'thank you for your time' # change box text
                some_box.size_to_fit() # change box size to fit new text exactly
                some_box.frame=(view.width*0.38,view.height*0.45,1.1*some_box.width,2*some_box.height) # change box location and size
            
            # Create display, further details see theBackground.py
            view=ui.View()
            view.present('fullscreen')
            view.background_color = (214/255,12/255,140/255)
            
            # Create button
            button1 = ui.Button(title='Click me') # initial button text
            button1.center = (view.width*0.38, view.height*0.45) # Button initial position
            #button1.border_width = 5 # give button a border
            #button1.size_to_fit() # fit button around text exactly
            button1.width = view.width*0.3 # button width
            button1.height = view.height*0.2 # button height
            button1.bg_color = (.3,.31,.32) # button colour (.3,.31,.32,0) fof transparent
            button1.font = ('Chalkduster', 30) # button font type and size
            button1.tint_color=(1,1,1) # button font colour
            button1.action = button1_tapped # needed for when button pressed
            view.add_subview(button1) # display button
            
            # Include non-interactive box
            some_box = ui.Label(
              text='This is not a button', # box text
              background_color=(95/255,96/255,98/255), # box colour
              text_color='white', # box text colour
              alignment=ui.ALIGN_CENTER, # text alignment in box
              number_of_lines=0, # number of lines used in box
              frame=(10, 10, view.width-20, 100)) # box position (10 in, 10 down, view.width-20 wide, 100 high)
            some_box.font=('HoeflerText-BlackItalic', 40) # box font type and size
            view.add_subview(some_box) # show box
            
            1 Reply Last reply Reply Quote 0
            • RoninSage
              RoninSage last edited by

              @brumm thanks for the help but the code In the link did not work when I tried to run it.

              @enceladus this is a start but the button still exists as a rectangle around the hexagon picture. Any tips to make sure that only tapping the shape will activate the button?

              1 Reply Last reply Reply Quote 0
              • enceladus
                enceladus last edited by enceladus

                Need to write "inside" function.

                # coding: utf-8
                
                import ui, math
                
                class MyButtonClass(ui.View):
                    def __init__(self):
                        self.color = 'red'
                        #touch event are limited to this area (left=100,top=100,right=200,bottom=200)
                        self.x = 100
                        self.y = 100
                        self.height = 100
                        self.width = 100
                        self.main_bg = 'black'
                        self.fg = 'red'
                        
                    def make_polygon(self, num_sides, x=0, y=0, radius=100, phase=0, line_width=5): 
                        path = ui.Path()
                        path.move_to(x,y)
                        path.line_width = line_width
                        for i in range(num_sides):
                            t = 2*math.pi*i/num_sides
                            x1, y1 = radius+radius*math.cos(t+phase), radius+radius*math.sin(t+phase)
                            if i:
                                path.line_to(x+x1, y+y1)
                            else:
                                path.move_to(x+x1,y+y1)
                        path.close() 
                        return path 
                        
                
                    def draw(self):
                        w, h = self.width, self.height
                        ui.set_color(self.main_bg)
                        rect = ui.Path.rect(0,0,w,h)
                        rect.fill()        
                        ui.set_color(self.fg)
                        path = self.make_polygon(6, 0, 0, h/2, math.pi/2) 
                        path.fill() 
                        
                    def inside(self, touch):
                        return True
                
                    def touch_ended(self, touch):
                        if not self.inside(touch):
                            return
                        if self.fg == 'red':
                            self.fg = 'blue'
                        else:
                            self.fg = 'red'
                        self.set_needs_display()
                
                class SpecialButton(object):
                    def __init__(self):
                        self.view = ui.View()
                        self.view.present('fullscreen')
                        self.btn = MyButtonClass()
                        self.view.add_subview(self.btn)
                
                SpecialButton()
                
                
                1 Reply Last reply Reply Quote 0
                • cvp
                  cvp last edited by

                  Perhaps, inside(touch) could check the color of touch.location?

                  1 Reply Last reply Reply Quote 0
                  • enceladus
                    enceladus last edited by enceladus

                    Here is an implementation. Not tested well. (Used Brumm code)

                    # coding: utf-8
                    from matplotlib import path
                    
                    import ui, math
                    
                    class MyButtonClass(ui.View):
                        def __init__(self):
                            self.color = 'red'
                            #touch event are limited to this area (left=100,top=100,right=200,bottom=200)
                            self.x = 100
                            self.y = 100
                            self.height = 100
                            self.width = 100
                            self.main_bg = 'black'
                            self.fg = 'red'
                            self.points = []
                            
                        def make_polygon(self, num_sides, x=0, y=0, radius=100, phase=0, line_width=5): 
                            path1 = ui.Path()
                            path1.move_to(x,y)
                            path1.line_width = line_width
                            points = []
                            for i in range(num_sides):
                                t = 2*math.pi*i/num_sides
                                x1, y1 = radius+radius*math.cos(t+phase), radius+radius*math.sin(t+phase)
                                points.append((x+x1, y+y1))
                                if i:
                                    path1.line_to(x+x1, y+y1)
                                else:
                                    path1.move_to(x+x1,y+y1)
                            path1.close() 
                            return (path1, points)
                            
                    
                        def draw(self):
                            w, h = self.width, self.height
                            ui.set_color(self.main_bg)
                            rect = ui.Path.rect(0,0,w,h)
                            rect.fill()        
                            ui.set_color(self.fg)
                            path1, self.points = self.make_polygon(6, 0, 0, h/2, math.pi/2) 
                            path1.fill() 
                            
                        def inside(self, touch):
                            p = path.Path(self.points)
                            return p.contains_points([touch.location])[0]
                    
                        def touch_ended(self, touch):
                            if not self.inside(touch):
                                return
                            if self.fg == 'red':
                                self.fg = 'blue'
                            else:
                                self.fg = 'red'
                            self.set_needs_display()
                    
                    class SpecialButton(object):
                        def __init__(self):
                            self.view = ui.View()
                            self.view.present('fullscreen')
                            self.btn = MyButtonClass()
                            self.view.add_subview(self.btn)
                    
                    SpecialButton()
                    
                    
                    
                    1 Reply Last reply Reply Quote 0
                    • RoninSage
                      RoninSage last edited by

                      @enceladus That last code worked, just a quick question, if I wanted a second button, is there an easy way to do that?

                      1 Reply Last reply Reply Quote 0
                      • brumm
                        brumm last edited by brumm

                        class MyButtonClass(ui.View):
                            def __init__(self, x, y, height, width):
                                self.x = x
                                self.y = y
                                self.height = height
                                self.width = width
                        
                        class SpecialButton(object):
                            def __init__(self):
                                self.view = ui.View()
                                self.view.present('fullscreen')
                                self.btn = MyButtonClass(100, 100, 100, 100)
                                self.btn2 = MyButtonClass(200, 100, 100, 100)
                                self.view.add_subview(self.btn)
                                self.view.add_subview(self.btn2)
                        

                        python classes

                        1 Reply Last reply Reply Quote 0
                        • RoninSage
                          RoninSage last edited by

                          @brumm thanks, just enough info for me to figure it out.

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post
                          Powered by NodeBB Forums | Contributors