• mikael

    @cvp, no worries! If you said something nasty, I would know someone had hijacked your user account.

    posted in Pythonista read more
  • mikael

    @pipe:

    import dialogs
    
    value = dialogs.input_alert('Input')
    
    print(value)
    

    posted in Pythonista read more
  • mikael

    @OkieWolf, you hit one of known quirks. You can set bordered to False, after which background_color works. Or if that appearance does not work for you, @cvp’s solution can be turned into a helper function that you can call with just 'red':

    def textfield_background(tf, color):
        import objc_util
        tfo = tf.objc_instance.textField()
        tfo.backgroundColor = objc_util.UIColor.colorWithRed_green_blue_alpha_(
            *ui.parse_color(color))
    

    posted in Pythonista read more
  • mikael

    @Bumbo-Cactoni, tiny example below, using ui because scene does not really have an ”input bar”, and mixing the two is not really the best way to start learning about them.

    import ui
    
    
    class MyApp(ui.View):
    
        def __init__(self, **kwargs):
            self.background_color = 'black'
            super().__init__(**kwargs)
    
            self.tf = ui.TextField(
                frame = (0, 0, 200, 40),
            )
    
            self.b_red = ui.Button(
                title='red',
                tint_color='black',
                background_color='lightgrey',
                action=self.action,
            )
            self.b_red.frame = (0, 0, 100, 30)
            
            self.add_subview(self.tf)
            self.add_subview(self.b_red)
    
        def action(self, sender):
            self.tf.text += sender.title
    
        def layout(self):
            self.tf.center = self.bounds.center()
            self.b_red.center = self.bounds.center()
            self.b_red.y = self.tf.y + 70
    
    
    MyApp().present('fullscreen')
    

    posted in Pythonista read more
  • mikael

    @Anxietier, the content rules, which might help or not, require at least two completion blocks, doable but unfortunately I do not have the kind of time I had earlier to spend on these projects.

    I would be happy to provide background support if you want to give it a go. I would expect it to be mostly versions of code already used in this component.

    posted in Pythonista read more
  • 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)
    

    posted in Pythonista read more
  • mikael

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

    posted in Pythonista read more
  • 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.

    posted in Pythonista read more
  • mikael

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

    posted in Pythonista read more
  • 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')
            ...
    

    posted in Pythonista read more
  • mikael

    @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)
            ...
    

    posted in Pythonista read more
  • mikael

    @mcriley821, instead of:

    btn.center = (btn.center.x + touchVec.x / 10,
                          btn.center.y + touchVec.y / 10)
    

    ... you should be able to just say:

    btn.center += touchVec / 10
    

    ... but for some reason it does not seem to exactly work.

    posted in Pythonista read more
  • mikael

    @Anxietier, hey, there’s something called content rules that can be configured to just stop loading images, see here. I will give it a try a bit later.

    posted in Pythonista read more
  • mikael

    @Anxietier, if web scraping is your thing, then the SafariViewController will not help you. WKWebView is the best tool around for Pythonista, as far as I know.

    posted in Pythonista read more
  • mikael

    @JonB, no it does not. Would be good to understand the need a bit more before trying to bend WKWebView to it. For the most part, just fetching the page with requests, then filtering imgs and javascript before giving it to WKwebView might work just as well.

    posted in Pythonista read more
  • mikael

    @mcriley821, also no need to navigate to btn and label in moveButton, the variables are already available (in the function’s closure).

    posted in Pythonista read more
  • mikael

    @mcriley821, no need to spend effort trying to make sure the coordinates are integers:

    j.frame = (x // 2 - 50, y // 2 - 150, 100, 100)
    

    Coordinates are floats, and the decimals are even somewhat meaningful on Retina displays.

    posted in Pythonista read more
  • mikael

    @mcriley821, no need to manually calculate vector magnitude:

    vecMagn = (touchVec.x**2 + touchVec.y**2)**.5
    

    ... Vector2 has you covered:

    vecMagn = abs(touchVec)

    posted in Pythonista read more
  • mikael

    @mcriley821, style is one part of being elegant. Elegant code is understandable and readable, i.e. not wasting the reader’s time.

    No need to use __call__, just call it:

    self.action(self, touchVec)

    posted in Pythonista read more
  • mikael

    @mcriley821, shorter way to format floats:

    label_text = f'{btn.center.x:.4f}, {btn.center.y:.4f}'

    posted in Pythonista read more
Internal error.

Oops! Looks like something went wrong!