• shinyformica

    @stephen not sure what SBridge is, exactly? Doesn't seem python related?

    @mikael it just came up at work in recent discussions about the future of using pythonista to do rapid development. People were wondering if there was any route to swift that was as simple as it is for objective-c.

    Not that Apple is planning to stop supporting objective-c in the near future, but more people are comfortable swift or with learning swift, than with picking up objective-c.

    Most of what I see when googling is about calling/embedding python from swift, not the other way around (calling swift from python). There's this:

    https://gist.github.com/jiaaro/e111f0f64d0cdb8aca38

    But that is not something which can be integrated with pythonista.

    posted in Pythonista read more
  • shinyformica

    Just curious, since I don't fully understand the details beyond using some kind of CFFI to do this kind of magic: is there any possibility of creating a Swift bridge for pythonista, similar to how we currently use objc_util or rubicon to call out to objective-c?

    Or does such a thing already exist that we can use? I see some projects for python which talk about swift/python interoperability, but it isn't clear to me whether they are things we could use in pythonista.

    Or...is such a thing completely impossible given how Swift differs from objective-c?

    posted in Pythonista read more
  • shinyformica

    Done and done. Thanks OMZ, for such a great piece of software.

    (and boy-oh-boy are there some ridiculously entitled people out there...)

    posted in Pythonista read more
  • shinyformica

    @omz thanks for the update!

    Pythonista has been unbelievably helpful at my work, and continues to impress every day.

    posted in Pythonista read more
  • shinyformica

    Good stuff, nice and simple.

    I'll take the opportunity to also point to the brilliant bit of python magic that @JonB came up with to make it possible to instantiate a pyui file directly as a ui.View subclass without deviating from standard class instantiation syntax.

    Here's the derivation of it which I use regularly:

    class PyUiView(ui.View):
        """
        Wrapper class for a custom ui.View
    
        If a pyui file is specified when instantiated then this view
        loads the pyui view and makes itself the root view. Otherwise
        acts as a normal custom ui.View subclass.
    
        If you subclass this for your custom view, the custom_class
        of your pyui root view needs to be set to the custom view's class.
        """
    
        def _WrapInstance(self):
            #### Wrap this view instance in an object which will
            #### return itself when "instantiated". This allows
            #### this same object to be produced when loaded via
            #### pythonista's pyui loading process.
            class _Wrapper(self.__class__):
                def __new__(cls):
                    return self
            return _Wrapper
    
        def __init__(self, *args, **kws):
            """Custom pyui views may be created with no options, in which
            case they are identical to regular ui.View objects, or they
            may be created with the following keyword options:
                pyui: a path to a .pyui file to load into the view.
                custom: the name of the custom_class of the root view in the pyui file.
                bindings: bindings to place in the local namespace
                            when the pyui file is loaded into the view.
                            Use this to make available modules and custom view classes
                            which are referenced by the pyui.
            """
            pyuifile = kws.pop("pyui",None)
            custom = kws.pop("custom", self.__class__.__name__)
            bindings = kws.pop("bindings",{})
            
            super(PyUiView, self).__init__(*args, **kws)
    
            if pyuifile:
                #### bindings include the current global namespace,
                #### and also two items needed to make sure this view
                #### instance is used as the root of the view hierarchy:
                ####    - either the name of this view class, or the given
                ####        custom class name, mapped to the
                ####        wrapper object that returns this instance on
                ####        instantiation.
                ####    - the name "self" mapped to this instance
                #### the bindings ensure that when the pyui custom classname
                #### matching this class is instanced, this same object
                #### is returned
                bindings.update(globals())
                bindings[custom] = self._WrapInstance()
                bindings["self"] = self
                ui.load_view(pyuifile, bindings)
    

    this allows for dynamic instantiation either by subclassing the base PyUiView class and naming the new subclass for the custom_class of the pyui root view:

    class MyView(PyUiView): pass
    v = MyView(pyui="test_customview.pyui")
    v.present("sheet")
    

    or by instantiating a PyUiView class with the 'custom' parameter set to the pyui root view custom_class:

    v = PyUiView(pyui="test_customview.pyui", custom="MyView")
    v.present("sheet")
    

    posted in Pythonista read more
  • shinyformica

    ListDataSource is a simple pure-python table data source and delegate object, and while the selected_row attribute is writable (it probably should be a read-only property), it does nothing if set manually. It will contain the correct selected row index as long as you don't manually fiddle with it. It is really only provided as a convenience because the data source action() callback will receive the ListDataSource as its argument when a selection is made, so you can look at the selected_row to see which row was selected.

    TableView.selected_row is the property to use if you want to modify the current selected row in code. Since TableViews actually support a more sophisticated sections-and-rows way of displaying data, the selected_row is a tuple of (section, row), but section should always be 0 for tables using the ListDataSource as their data source delegate.

    So: read from LastDataSource.selected_row to see what row index is selected in action() callbacks, but use TableView.selected_row = (0, row) to set the actual selected row directly.

    posted in Pythonista read more
  • shinyformica

    @mikael it works...it isn't feature-complete, and I was unable to figure out how to consistently get the proper animation of items when they are moved to a new location (it doesn't always animate the properties of the moved cell in the right way, or the cell in the new location is displayed before the move animation happens).

    Let me try to extricate the code which is unrelated to the implementation of the UICollectionView from the custom code for my specific purposes. Maybe someone can figure out why my end-move animation is wonky.

    posted in Pythonista read more
  • shinyformica

    @mikael sweet! Didn't realize the magnificent Gestures module already had exactly what I needed.

    posted in Pythonista read more
  • shinyformica

    Presenting a view with style = "full_screen" and hide_title_bar = True will enable that special two-finger-swipe "emergency exit" gesture, which will force the view to close.

    Is there a way to disable that gesture? For my script, I actually may have situations where two fingers will swipe down fast enough to cause that emergency exit to close the presented view. It would be a rare event, thankfully, but it is possible, so I'd like to turn it off altogether.

    posted in Pythonista read more
  • shinyformica

    @dgelessus thanks so much for the deep knowledge!

    So now this whole thing is working! As it turns out a lot of this was a red herring.

    In summary:

    • It is perfectly legal to use the python string value "UICollectionElementKindSectionHeader" directly in the registerClass_forSupplementaryViewOfKind_withReuseIdentifier_() objc method, since it is converted to an NSString object implicitly.
    • The value returned by ctypes.c_void_p.in_dll(objc_util.c, "UICollectionElementKindSectionHeader") works as well, I assume since that c_void_p ends up being interpreted as an NSString object.
    • Of course, objc_util.ObjCInstance(ctypes.c_void_p.in_dll(objc_util.c, "UICollectionElementKindSectionHeader")) works, and is probably "safest" since you get the actual value without having to guess, and it is turned into a correct type.
    • You cannot directly use the _FuncPtr value returned by objc_util.c.UICollectionElementKindSectionHeader but there might be some way to convert that _FuncPtr value (just doing a ctypes.cast(funcptr, ctypes.c_void_p) does not work).

    Now, the reason the whole thing was a red herring: collection views won't even bother to call the collectionView_viewForSupplementaryElementOfKind_atIndexPath_() method unless the flow layout object being used to layout the items has had its headerReferenceSize property set to something other than the default CGSize(0,0)...so even when I was successfully registering the class with the method to create section headers, it wasn't being called.

    posted in Pythonista read more

Internal error.

Oops! Looks like something went wrong!