• shinyformica

    @mikael yeah, we won't be expecting anything specific from Pythonista development. We'll probably go with something like RabbitMQ which doesn't require any compiled library extensions.

    Unfortunately I can't really say anything about what I'm working on here...suffice it to say that we have to rapidly respond to client requests in an environment where development isn't macOS-based, is almost entirely python and c++, but still needed to be able to build interfaces for iOS. Pythonista checked those boxes very nicely.

    If @olemoritz is listening, he should know just how good this app is.

    posted in Pythonista read more
  • shinyformica

    @mikael thanks, haven't had much time recently. Rest assured, the pythonista-based stuff I've been building is still going strong. In fact, its inherent stability has impressed everyone.

    I did google it, and saw that library...but I'm very very wary of using an old, unsupported thing like that. Was hoping someone here might have a better solution. Perhaps I should ping @olemoritz himself? See if we can get zmq included in the next pythonista release.

    posted in Pythonista read more
  • shinyformica

    I guess what I'm really asking is: is there a pure python client for ZeroMQ so that a pythonista-based app can send and receive messages in a ZeroMQ messaging system?

    Since pythonista doesn't come with the zmq library installed, it means there would have to be a pure-python zmq substitute out there? Right? Unless I'm missing something.

    Has anyone played around with ZeroMQ via pythonista before?

    posted in Pythonista read more
  • shinyformica

    @mcriley821 yeah, that's what I felt as well...just unfortunate that we don't have a way to access the font descriptors they want us to use instead of names. Well, no way via normal Pythonista python APIs, I'm sure we could do it via objc.

    posted in Pythonista read more
  • shinyformica

    Yeah, that makes sense. I just read a stackoverflow post about something similar to this. This isn't a big deal, overall...I can do something other than setting the widget font to the font of the associated widget.

    Does this qualify as a "bug" really? Should the value of the widget.font property be returning something which can't be assigned as a valid value to another widget's font property?

    posted in Pythonista read more
  • shinyformica

    Could someone verify my sanity here...I was noticing some widgets in my UI were getting a different non-system font under Pythonista3.3 on iOS13. And when I investigated, it was only widgets who were setting their font to match another widget.

    What I'm seeing is that code like this:

    label = ui.Label()
    print label.font()
    button = ui.Button()
    print button.font()
    label.font = button.font
    print label.font()
    

    will end up with label.font being set to something other than the button's font. It will instead be set to ('TimesNewRomanPSMT', 15.0). In fact, the output is:

    ('.SFUI-Regular', 17.0)
    ('.SFUI-Regular', 15.0)
    ('TimesNewRomanPSMT', 15.0)

    Which is decidedly strange. It seems like it actually boils down to that '.SFUI-Regular' font name...it's being turned into 'TimesNewRomanPSMT', and the size comes across appropriately. If I directly assign a specific font, or the special '<system>' value for the font, it works as expected.

    Is this some new iOS13 font name that Pythonista doesn't handle properly? Admittedly this is a rare thing to do, setting one widget's font to equal another's...but I was expecting it to work, and it did under Pythonista3.2 and iOS12, and I think it was still working under Pyhtonista3.3 and iOS12.

    posted in Pythonista read more
  • shinyformica

    Sorry for the typos and things...I didn't really test what I posted, just copy pasted stuff from my own project and test code, and modified it to remove extra utilities and things that I wrote which are in other modules.

    Thanks to those who fixed those issues, glad it's working.

    The ViewHierarchy thing is a utility class I have which holds a bunch of tricks and things for helping with navigating the views in my projects. The actual definition of getUIViewController is:

    def getUIViewController(cls, view):
            import objc_util
            UIViewController = objc_util.ObjCClass('UIViewController')
            UIView = objc_util.ObjCClass('UIView')
            if isinstance(view,ui.View):
                viewobj = view.objc_instance
            elif isinstance(view,objc_util.ObjCInstance) and \
                    view.isKindOfClass_(UIView):
                viewobj = view
            elif isinstance(view,objc_util.ObjCInstance) and \
                    view.isKindOfClass_(UIViewController):
                viewobj = view
            viewResponder = viewobj.nextResponder()
            try:
                while not viewResponder.isKindOfClass_(UIViewController):
                    viewResponder = viewResponder.nextResponder()
            except AttributeError:
                    return None
            return viewResponder
    

    which crawls the responder chain to find the view controller living above the one controlling the passed-in view, or the view controller if one was given. Anyway...looking at what @stephen posted...I think I should actually just be doing that instead.

    posted in Pythonista read more
  • shinyformica

    First, here's a newer version with some improvements which make it work better on iOS 13, and adds a callback which is called when the popover is presented:

    def adaptivePresentationStyleForPresentationController_(_self, _cmd,
                                                                    controller):
        #### force the popover presentation style to stay as-is
        return -1 # UIModalPresentationNone
    
    def popoverDelegateCompletion(delegate):
        if delegate._popview is not None and delegate._bgcolor is not None:
            delegate._popview.background_color = delegate._bgcolor
        if delegate._completion is not None:
            delegate._completion()
        delegate._popview = None
        delegate._presented_block = None
    
    def popoverPresentationControllerDidDismissPopover_(_self, _cmd, controller):
        import objc_util
        delegate = objc_util.ObjCInstance(_self)
        popoverDelegateCompletion(delegate)
    
    PopoverPresentationDelegate = objc_util.create_objc_class(
                    "PopoverPresentationDelegate",
                    methods=[adaptivePresentationStyleForPresentationController_,
                                popoverPresentationControllerDidDismissPopover_],
                    protocols=["UIPopoverPresentationControllerDelegate"])
    
    def popover(sourceview, popview, presented=None, dismissed=None):
        """Create and display a popover modal view containing the given
        content view, with a little arrow pointing at the given source view.
        'presented' is called when the popover is first presented.
        'dismissed' will be called when the popover is dismissed."""
    
        def _closer(vc, delegate):
            #### return a function object which will dismiss the popover
            #### and restore the popview bg color, as well as call
            #### any completion function
            def _f():
                vc.dismissViewControllerAnimated_completion_(True,None)
                popoverDelegateCompletion(delegate)
            return _f
    
        #### find the view controller which is presenting the source view
        #### this is what the popover arrow will point at
        sourcevc = ViewHierarchy.getUIViewController(sourceview)
        #### create a new modal view controller and set its presentation
        #### style to the popover style, and size it to the content
        UIViewController = objc_util.ObjCClass("UIViewController")
        vc = UIViewController.new().autorelease()
        vc.modalPresentationStyle = 7 # UIModalPresentationPopover
        vc.preferredContentSize = objc_util.CGSize(popview.width, popview.height)
    
        #### As of iOS 13+ popover presentation bounds include the little arrow
        #### as part of the content area.
        #### Since our popup content is designed to be displayed only in the
        #### rectangular portion of the popover view, we constrain it to
        #### the "safe area", which excludes the arrow.
        safeView = objc_util.UIView.new().autorelease()
        safeView.addSubview_(popview.objc_instance)
        safeView.backgroundColor = objc_util.UIColor.clearColor()
        vc.view = safeView
        popview.objc_instance.translatesAutoresizingMaskIntoConstraints = False
        guide = safeView.safeAreaLayoutGuide()
        anchor = popview.objc_instance.leadingAnchor()
        anchor.constraintEqualToAnchor_(guide.leadingAnchor()).active = True
        anchor = popview.objc_instance.trailingAnchor()
        anchor.constraintEqualToAnchor_(guide.trailingAnchor()).active = True
        anchor = popview.objc_instance.topAnchor()
        anchor.constraintEqualToAnchor_(guide.topAnchor()).active = True
        anchor = popview.objc_instance.bottomAnchor()
        anchor.constraintEqualToAnchor_(guide.bottomAnchor()).active = True
    
        #### retrieve the popover presentation controller for the new modal
        #### view controller, bail if that fails for some reason
        popover = vc.popoverPresentationController()
        if popover is None: return None
    
        #### create and assign the popover presentation delegate
        delegate = PopoverPresentationDelegate.new().autorelease()
        delegate._completion = dismissed
        delegate._popview = popview
        delegate._bgcolor = None
        popover.delegate = delegate
    
        #### if the popview has a translucent background, make the
        #### presenting view translucent instead, and the popview transparent,
        #### save the original color to restore on dismissal.
        color = popview.background_color
        if color[3] < 1.0:
            popview.background_color = "clear"
            delegate._bgcolor = color
        popover.backgroundColor = objc_util.UIColor.colorWithRed_green_blue_alpha_(*color)
        popover.sourceView = sourceview.objc_instance
        popover.sourceRect = objc_util.CGRect(objc_util.CGPoint(0,0),objc_util.CGSize(
                                                sourceview.width, sourceview.height))
        #### if a presentation function is provided, it is converted to an
        #### objective-c block to be called when the popover is displayed
        objc_f = None
        if presented is not None:
            objc_f = objc_util.ObjCBlock(presented, None, [objc_util.c_void_p])
            delegate._presented_block = objc_f
        #### present the view controller containing the popover content
        #### via the popover presentation controller, using the
        #### popover delegate we created, and return the close
        #### function to allow caller to close the popover from code
        sourcevc.presentViewController_animated_completion_(vc, True, objc_f)
        return _closer(vc, delegate)
    

    it's simple enough to use. When you wish to display a view as a popover, just call like so:

    def popover(sender):
        popview = ui.View()
        popview.width = 200
        popview.height = 100
        popview.add_subview(ui.Label(text="Hello popover!", flex="WH")
        popover(sender, popview)
    
    v = ui.View()
    v.width = 300
    v.height = 300
    b = ui.Button()
    b.title = "Show Popover"
    b.action = showPopover
    b.frame = (0,0,100,40)
    b.center = v.center
    v.add_subview(b)
    v.present("sheet")
    

    posted in Pythonista read more
  • shinyformica

    @JonB I try very hard not to swizzle anything...it sounds and feels dirty. I did do it once, I admit, in order to make the tableview have the tableView_willDisplayHeaderView_forSection_ method, so I could customize header display.

    I suspect you are right about why it isn't working. Using the string comparison is working well enough.

    posted in Pythonista read more
  • shinyformica

    @BapeHiks thanks! I didn't know how to do that.

    posted in Pythonista read more

Internal error.

Oops! Looks like something went wrong!