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.


    UI composites for the world

    Pythonista
    3
    7
    3606
    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 last edited by

      This recent thread by @cvp on how to right-align the label on a button prompted me to think about a more general solution to these kinds of requirements. Hence this utility view, available on GitHub.

      Sample image

      Composite is a custom Pythonista UI View that supports stacking several other views in the same area, while providing easy access to the features of the individual views.

      Example #1 - Basic use

      Let's stack a ui.Label on top of a ui.Button:

      lbl_btn = Composite(Button, Label)
      

      Composite members are listed in bottom-up order, and you can provide both classes and instances; classes are simply instantiated with no arguments.

      When you access or set an attribute on the composite, it is also applied in the order given to the constructor, above. Thus, if I set the alignment:

      lbl_btn.alignment = ALIGN_RIGHT
      

      This applies to the Label, as Button does not have that attribute. On the other hand, setting the background color:

      lbl_btn.background_color = 'lightgrey'
      

      Applies only to the first view, Button, even though the Label has that attribute as well.

      The underlying Composite view grabs all attributes that affect the sizing and positioning of the whole composited view. For example:

      lbl_btn.center = (100, 100)
      

      Likewise, setting the size of the Composite will lay out all the contained views so that they all fill the whole area of the Composite.

      If you need to explicitly manage a specific view, for example to manage which view gets touch events, you have two options:

      1. Instantiate it and retain the reference to it, in order to set values before or after giving it to the Composite constructor.
      2. Get the specific view by class name, and set specific values on it.

      An example of the second option:

      lbl_btn['Label'].border_color = 'black'
      

      Example #2 - Margins and corners

      Composite comes with a Margins view, which can be included to inset the following views by a set amount, by default 5 pixels from every edge:

      lbl = Composite(Margins, Label)
      

      You can set the margin values for every edge separately, with any of the following options:

      • single number - Same amount on all sides
      • 2-tuple - (top and bottom, sides)
      • 3-tuple - (top, sides, bottom)
      • 4-tuple - (top, right, bottom, left)

      For example:

      lbl.margin = (5, 10)
      

      Sets top and bottom margins to 5 pixels, and side margins to 10 pixels.

      Labels do not normally support rounded corners eithout some objc_util code, but luckily the containing View does, so this works as well:

      lbl.corner_radius = 10
      

      size_to_fit also works as expected, arranging the whole Composite view around the preferred size of the innermost/topmost view.

      Example #3 - Shadow

      Setting the shadow options for the whole Composite view is supported, either with the convenience function set_drop_shadow that only needs the color of the shadow as a parameter, or with the individual settings:

      • shadow_opacity
      • shadow_offset (tuple)
      • shadow_color
      • shadow_radius

      Example #4 - Blurred background

      iOS BlurEffect is available through a separate auxiliary view:

      blur_lbl = Composite(Blur, Button, Label)
      

      style option can be used to set the brightness of the blurred area in relation to the underlying layer to one of the following values:

      • LIGHTER
      • SAME (default)
      • DARKER

      Run the examples

      All of the above examples are demonstrated in the end of the composite.py file.

      To do

      Editable views like TextField do not work right.

      Should include the vibrancy effect as well.

      Other composable examples are highly welcome.

      Thanks to the following contributions on the Pythonista forum:

      • ObjC code for the shadow settings
      • BlurView code
      1 Reply Last reply Reply Quote 3
      • zipit
        zipit last edited by

        Hi,

        that does look quite nice. As already stated in the ui Thread, I am not a big ui user, so this could be considered to be of most irrelevance. But I think the documentation is despite all efforts a bit lacking. I won't touch anything that does not provide at least method signatures for its constructor functions. Sounds a bit rude, but I hope you do understand how it is meant 😉.

        cheers
        zipit

        1 Reply Last reply Reply Quote 0
        • ccc
          ccc last edited by ccc

          You can automatically generate function/method signature docs: https://docs.python.org/3.6/library/pydoc.html

          mikael 1 Reply Last reply Reply Quote 1
          • mikael
            mikael @ccc last edited by

            @ccc and all, I would sure appreciate any pointers to tools or tutorials that would help me generate a straight-forward GitHub-friendly markdown API doc out of my module, which is often just a single file.

            1 Reply Last reply Reply Quote 0
            • ccc
              ccc last edited by

              On the Pythonista console:

              >>> import composite
              >>> help(composite)
              

              See how your docstrings appear in the generated docs? This should encourage you to write more docstrings on functions/methods that are not obvious. Always ask yourself if there are ways to structure / name your code to make docstrings unnecessary.

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

                @ccc made a pull request which inspired me to think about how to make views even more easy to combine, customize and use.

                As a result, the version now on Github allows me to define new components like this:

                class FancyButton(Sized, Clickable, Rounded, Blurred, Shadowed, DefaultLabel): pass
                

                ... that can then be used wherever needed in the normal way of views:

                btn = FancyButton(text='Click me')
                

                ... to get a sized-to-fit button with multiline centred text, rounded corners, blurred background and a drop shadow.

                The above is of course a bit contrived example. In practice, I will first assemble my default look and feel (text color, rounded corners, background, maybe shadow, but probably not), and then apply it to labels and buttons and whatnot.

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

                  Couple of additional tweaks:

                  1. Explicit but optional control for which view in the stack gets touch events.
                  2. TextView tweak that lets you get out of editing mode by swiping down on the TextView (helps with the old problem of the keyboard on iPhone not having any option for getting out of the edit mode).

                  Could keep on building different kinds of components, but probably will not, unless someone has a specific thing in mind. Or until I get back to my UI-heavy project.

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