omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular
    1. Home
    2. shinyformica

    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.


    • Profile
    • Following 0
    • Followers 2
    • Topics 61
    • Posts 230
    • Best 21
    • Controversial 0
    • Groups 0

    shinyformica

    @shinyformica

    28
    Reputation
    3333
    Profile views
    230
    Posts
    2
    Followers
    0
    Following
    Joined Last Online

    shinyformica Unfollow Follow

    Best posts made by shinyformica

    • RE: Help finding the value of an objc string constant...

      @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
      shinyformica
      shinyformica
    • RE: 330018: popover view now contains arrow in its frame

      I did a little digging on this, to figure out how it is being solved by other developers.

      First, though this would appear to many to be a bug, it actually puts the popover presentation view controller in line with how view controllers work in general. Since iOS 11+ Apple has provided a "safe area" concept which is supposed to be used by the view hierarchy to indicate what part of their content area is obscured. In the case of the popover view controller, the arrow is still part of the content area, but it obscures content.

      @cvp, @mikael you are both the dudes!

      I'm providing a somewhat more complex but general way below, which doesn't suffer from the delay between presentation of the popover and content. The trouble is that the safeAreaInsets() is always 0 before a view is displayed, so it can't be used to set the proper location of a view before it is visible. However, using the safeAreaLayoutGuide() and the constraint/anchor system, the content view can be made to size itself automatically to the safe area:

      import ui
      
      
      def present_popup(content_view, position):
          popup = ui.View(
              width=content_view.width,
              height=content_view.height,
          )
          popup.add_subview(content_view)
          
          content_view.objc_instance.translatesAutoresizingMaskIntoConstraints = False
          guide = popup.objc_instance.safeAreaLayoutGuide()
          anchor = content_view.objc_instance.leadingAnchor()
          anchor.constraintEqualToAnchor_(guide.leadingAnchor()).active = True
          anchor = content_view.objc_instance.trailingAnchor()
          anchor.constraintEqualToAnchor_(guide.trailingAnchor()).active = True
          anchor = content_view.objc_instance.topAnchor()
          anchor.constraintEqualToAnchor_(guide.topAnchor()).active = True
          anchor = content_view.objc_instance.bottomAnchor()
          anchor.constraintEqualToAnchor_(guide.bottomAnchor()).active = True
      
          popup.present(style="popover",
              popover_location=position,
              hide_title_bar=True)
      
          return popup
          
          
      if __name__ == '__main__':
          
          popup_content = ui.Label(
              text="Hello!",
              border_width=3,
              frame=(0,0,150,100),
          )
      
          popup = present_popup(popup_content, (100, 100))
      
      posted in Pythonista
      shinyformica
      shinyformica
    • RE: Access TableViewCells

      @Drizzel the important bit here is that you aren't really supposed to directly access tableview cells by index, since in all likelihood, they don't exist.

      This is because the way the underlying control is implemented is designed to only create cells when they need to be displayed, and it keeps only the ones it absolutely needs to keep (with some caching), it even reuses existing cells that have gone out of the visible area, instead of creating new ones.

      That source.tableview_cell_for_row() is called to generate a cell for a particular index at the moment the view requires it, and it will be destroyed or reused, so you can't really depend on it being "kept" somewhere as a subview you can always access.

      Now, you can actually use objc_util magic to get a cell at an index path, but the cell will be None if that index is invalid or not visible.

      So the best thing to do if you want to somehow modify a cell (I'm guessing that's what you want here) is to implement tableview_cell_for_row() and make any modifications there for cells being created. If you need to update a visible cell, just call table.reload() and it will cause all visible cells to be re-created.

      posted in Pythonista
      shinyformica
      shinyformica
    • RE: Is there an equivalent to objc_util, but for Swift?

      @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
      shinyformica
      shinyformica
    • RE: New Beta for Pythonista 3.3

      @omz thanks for the update!

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

      posted in Pythonista
      shinyformica
      shinyformica
    • RE: Override ui.View "attributes" in subclass?

      Ah, was tired last night...this just required some googling.
      The getset_descriptor is the CPython property object, and I can directly get and set the value from it with:

      @property
      def background_color(self):
          return ui.View.background_color.__get__(self) 
          
      @background_color.setter
      def background_color(self, color):
          ui.View.background_color.__set__(self, color)
      
      posted in Pythonista
      shinyformica
      shinyformica
    • RE: What what what!! New version in TestFlight!!!

      It really is so great to know you're still developing Pythonista @omz !

      Truly wonderful work, can't wait for the next release!
      (and if there's any chance of more open TestFlight slots, let us know).

      posted in Pythonista
      shinyformica
      shinyformica
    • RE: Is it possible to use ZeroMQ (0MQ) in pythonista?

      @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
      shinyformica
      shinyformica
    • RE: Popover on iPhone?

      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
      shinyformica
      shinyformica
    • RE: Pythonista 3.3 and theme access

      Well look at me, being all fancy and figuring this one out myself!

      Ok, so first step was looking at all the NSUserDefaults key/value pairs to see what held the theme:

      import objc_util
      nsd = objc_util.ObjCClass("NSUserDefaults")
      standard = nsd.standardUserDefaults()
      defaults = standard.dictionaryRepresentation()
      print(defaults)
      

      Then, just scanning through the output, I see:

      ThemeName = ...
      ThemeNameDarkMode = ...
      ThemeNameLightMode = ...

      so, obviously in retrospect, we've got new keys for the theme settings for light and dark modes. Et, voila.

      Now then...anyone know how we find out which mode we are in from a script?

      posted in Pythonista
      shinyformica
      shinyformica

    Latest posts made by shinyformica

    • RE: What what what!! New version in TestFlight!!!

      It really is so great to know you're still developing Pythonista @omz !

      Truly wonderful work, can't wait for the next release!
      (and if there's any chance of more open TestFlight slots, let us know).

      posted in Pythonista
      shinyformica
      shinyformica
    • RE: Trying to move to Pyto but….

      We have all been hoping that Ole returns to the community at some point and lets us know what the future of Pythonista might be. Unfortunately that hasn't happened so far, but the app continues to function as-is, so we can be thankful for that.

      I also prefer Pythonista overall to Pyto, though Pyto continues to improve. The developer of of Pyto, it should be noted, is an 18 year old student, and probably doesn't have a lot of time to interact with the community. I'm not even sure she's aware of the Discord server, but there is a community there, and on GitHub where the source code for Pyto is stored:
      https://github.com/ColdGrub1384/Pyto

      posted in Pythonista
      shinyformica
      shinyformica
    • RE: Contact with the developer of Pythonista?

      @JonB @cvp, I have tried a few attempts to contact the couple of support email addresses we have for Pythonista, but there's no response. My guess is it is @omz alone handling anything that comes in there.

      Anyway, I think we should continue to work on finding a way to get in contact, though in no way do I wish to put undue pressure on Ole, or come across as pushy or rude. I just want to get a conversation started.

      posted in Pythonista
      shinyformica
      shinyformica
    • Contact with the developer of Pythonista?

      Has anyone tried, or been able to make contact with Mr. Zorn (I think his name is Ole Zorn), the developer of Pythonista?

      I wish to respect his right to privacy, and his right not to be bothered by pestering. But I truly wish we had some way of starting a conversation about what the future of Pythonista might be, if any.

      It would be such a shame if the app and its community simply died out when either it disappears from the app store, or it ceases to be compatible with a future iOS version (we have continued to be lucky on both fronts so far).

      I'm not at all sure how to approach this in a way that is respectful of the developer's situation and needs. Any suggestions welcome, of course.

      posted in Pythonista
      shinyformica
      shinyformica
    • RE: Is it possible to use ZeroMQ (0MQ) in pythonista?

      @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
      shinyformica
      shinyformica
    • RE: Is it possible to use ZeroMQ (0MQ) in pythonista?

      @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
      shinyformica
      shinyformica
    • Is it possible to use ZeroMQ (0MQ) in pythonista?

      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
      shinyformica
      shinyformica
    • RE: Setting widget font a little wonky in Pythonista3.3/iOS13

      @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
      shinyformica
      shinyformica
    • RE: Setting widget font a little wonky in Pythonista3.3/iOS13

      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
      shinyformica
      shinyformica
    • Setting widget font a little wonky in Pythonista3.3/iOS13

      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
      shinyformica
      shinyformica