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.


    Joystick UIControl ui wrapper?

    Pythonista
    ui module objcutil
    3
    22
    8463
    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.
    • mikael
      mikael @mcriley821 last edited by

      @mcriley821, ui.View conveniently sets all its kwargs, so we can just call super() with them, no need to iterate manually. Also, defaults can be set before. tint_color we handle separately, as it is a custom property. (In general I would advice against overriding the ui.View properties, it will come back to haunt you.)

          def __init__(self, tint_color='grey', **kwargs):
              kwargs.setdefault('background_color', 'black')
              super().__init__(**kwargs)
              ...
      
      mcriley821 1 Reply Last reply Reply Quote 0
      • mcriley821
        mcriley821 @mikael last edited by mcriley821

        @mikael I iterate manually to catch a non-square frame. Is there a different way to make sure this happens? I feel like I also need to override the frame setter to catch it after init

        mikael 3 Replies Last reply Reply Quote 0
        • mikael
          mikael @mcriley821 last edited by mikael

          @mcriley821, sorry, forgot to include that bit. Seems enough to check it after super(). If you want to enforce it continuously, layout() is a good option since, in addition frame, size can change via bounds, width and height.

              def __init__(self, tint_color='grey', **kwargs):
                  kwargs.setdefault('background_color', 'black')
                  super().__init__(**kwargs)
                  if self.frame.width != self.frame.height:
                      raise ValueError('Joystick must be square')
                  ...
          
          1 Reply Last reply Reply Quote 0
          • mikael
            mikael @mcriley821 last edited by

            @mcriley821, also makes sense to set self.stick.flex = 'WH', so that it will resize with its superview.

            1 Reply Last reply Reply Quote 0
            • mikael
              mikael @mcriley821 last edited by mikael

              @mcriley821, taking the arithmetic capabilities of ui.Point/Vector2, the calculations can collapse to:

              
                  def touch_moved(self, touch):
                      touch = touch.location
                      radius_vector = [self.radius]*2
                      touch_vector = touch - radius_vector
                      magnitude = abs(touch_vector)
                      
                      if magnitude < self.radius:
                          self.stick.center = touch
                      else:
                          self.stick.center = (
                              touch_vector / magnitude *  self.radius + 
                              radius_vector
                          )
                      if self.action:
                          self.action(self, touch_vector)
                      return
              

              Thank you for your patience, I think I am done.

              1 Reply Last reply Reply Quote 1
              • mcriley821
                mcriley821 last edited by

                @mikael I really appreciate you taking the time to help me and the improvements! I’ve already updated a bunch of stuff from your suggestions and I’m currently working on using the ‘iob:pinpoint' ionicon to add a type of texture to the ‘joystick’!

                mikael 2 Replies Last reply Reply Quote 0
                • mikael
                  mikael @mcriley821 last edited by

                  @mcriley821, interesting! Careful placement to get just the head of the pin?

                  1 Reply Last reply Reply Quote 0
                  • mikael
                    mikael @mcriley821 last edited by mikael

                    @mcriley821, if you need a bit more flexibility, here’s an objc CAGradientLayer version, credits for an original axial version to @cvp:

                    import ui
                    import objc_util
                    
                    
                    CAGradientLayer = objc_util.ObjCClass('CAGradientLayer')
                    
                    
                    class ShadedCircle(ui.View):
                        
                        def __init__(self, color1='#ff8484', color2='red', **kwargs):
                            super().__init__(**kwargs)
                    
                            o_color1 = objc_util.UIColor.colorWithRed_green_blue_alpha_(
                                *ui.parse_color(color1)).CGColor()
                            o_color2 = objc_util.UIColor.colorWithRed_green_blue_alpha_(
                                *ui.parse_color(color2)).CGColor()
                            
                            layer = self.objc_instance.layer()
                            grlayer = CAGradientLayer.layer()
                            grlayer.setType('radial')
                            grlayer.frame = layer.bounds()
                            grlayer.setColors_([o_color1, o_color2])
                            layer.insertSublayer_atIndex_(grlayer, 0)
                            grlayer.setStartPoint(objc_util.CGPoint(0.25, 0.25))
                            grlayer.setEndPoint(objc_util.CGPoint(1.0, 1.0))
                            grlayer.locations = [0.0, 1.0]
                        
                        def layout(self):
                            self.height = self.width
                            self.corner_radius = self.width / 2
                            
                        
                    if __name__ == '__main__':
                        v = ui.View()
                        
                        c = ShadedCircle(
                            center=v.bounds.center(),
                            flex='RTBL',
                        )
                        
                        v.add_subview(c)
                        v.present('fullscreen', animated=False)
                    
                    1 Reply Last reply Reply Quote 1
                    • mcriley821
                      mcriley821 last edited by

                      @mikael
                      I just subclassed a ui.View object again and did some more stuff to check for changing the frame later with layout. Had to use layout or it wasn’t resizing correctly, or changing some of the attributes to make the stick/texture of the joystick not resize.

                      I decided to start a github repo for Pythonista and posted it in there.

                      https://github.com/mcriley821/Pythonista/blob/master/UIJoystick.py

                      1 Reply Last reply Reply Quote 1
                      • DoinStuffMobile
                        DoinStuffMobile @mcriley821 last edited by

                        @mcriley821 Wow, I clearly did not look hard enough initially! That's amazing!

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