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.


    [Lab] Function to easily create a vertical view of views

    Pythonista
    lab ui.view
    1
    5
    4115
    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.
    • Phuket2
      Phuket2 last edited by

      Hmm, Sunday nights 😱 Ok, this is a function to create a vertical list of views. Granted, it's not difficult, but can be a pain. The below is pretty flexible if you want to get started quickly with a vertical layout. It's also orientation and size friendly. If you take out the comments and test code, it's pretty tiny I think. Anyway, I know I will be able to use something like this. I will tweak it a bit to be able to use a scrollview and clean it up.

      # Pythonista Forum - @Phuket2
      import ui, editor
      
      def simple_vert_view(parent, v_list, cv_margin=(0, 0),
      					v_margin=(0,0), *args, **kwargs):
      	'''
      	simple_h_view:
      	Description - creates a number of ui.Views vertically. A root ui.View
      	named 'cv' is created first. The vertical views are subviews of 'cv'
      	params -
      		1. parent = the parent view that this view will be a subview of
      		2. v_list = a list of numbers. each number represents the height
      		of the view. as follows
      			0  = fill the free space, if more than one, its divided
      			<1 = is a percentage if the overall height avail
      			>1 = is a abs points value
      		3. cv_margin, is used when creating the rect fir the 'cv' view.
      		the 'cv' is equal to the parent.bounds.inset(*cv_margin).
      		4. v_margin = is called on the ui.rect that is used to create
      		the view. The view is already sized as per the v_list.
      		so this will change the dimensions of the view. not trying to
      		go the other way, meaning adusting the abs values in the v_list,
      		would not be hard to do, but this way makes more sense i think.
      		5. **kwargs = kwargs are evaluated for every view, including the
      		'cv' view.  just a choice.
      		
      	returns:
      		a ui.View. The view returned is named 'cv', contains the views
      		created from v_list as subviews. each subview is named p0..pn
      	'''
      	r = ui.Rect(*parent.bounds).inset(*cv_margin)		
      	cv = ui.View(name='cv', frame=r)
      	cv.bg_color = 'pink'
      	cv.flex = 'wh'
      	
      	def translate_height(ph, h):
      		# i know can be done better... but thinking will expand this
      		if h == 0 or h > 1:
      			return h
      		elif h == -1:
      			return ph
      		elif h < 1.0:
      			return ph * h
      			
      	def apply_kwargs(kwargs, obj):
      		for k, v in kwargs.items():
      			if hasattr(obj, k):
      				setattr(obj, k, v)
      				
      	# translate the numbers in v_list to absolute numbers
      	v_list = [translate_height(r.height, x) if x else x for x in v_list]
      	
      	# var is the space left over in the view after the absolute heights
      	# have been subtracted divided by the number if items that are
      	# equal to 0
      	zero_count = v_list.count(0)
      	
      	# aviod divide by zero error
      	var = (r.height - sum(v_list)) / zero_count if zero_count else\
      			(r.height - sum(v_list))
      		
      	# replaces 0 in v_list with var.
      	v_list = [var if x == 0 else x for x in v_list]
      	
      	y = 0		# keep track of the height
      	# go through v_list, create the views as subviews of cv, and apply
      	# some attrs to the created views
      	for i, h in enumerate(v_list):
      		frame = ui.Rect(0, y, r.width, h).inset(*v_margin)
      		v = ui.View(name='p' + str(i), frame=frame)
      		v.flex = 'whlrtb'
      		apply_kwargs(kwargs, v)
      		cv.add_subview(v)
      		y += h
      	
      	# hmmm, to do or not do?
      	apply_kwargs(kwargs, cv)
      	return cv
      
      
      class MyClass(ui.View):
      	def __init__(self, *args, **kwargs):
      		super().__init__(*args, **kwargs)
      		self.make_view()
      		
      	def make_view(self):
      		v_list = [44, 0, 0, 0, 44, .5, 60]
      		#v_list = [44, 0, 60]
      		#v_list = [.5, .4, 0, 0]
      		#v_list = [44, .2, 0, 60]
      		#v_list = [.5, .5]
      		#v_list = [48, .4, 0, 64]
      		
      		v = simple_vert_view(self, v_list, cv_margin=(10, 10),
      		v_margin=(5, 5), corner_radius=5, border_width=.5)
      		self.add_subview(v)
      
      if __name__ == '__main__':
      	_use_theme = True
      	w, h = 600, 800
      	f = (0, 0, w, h)
      	style = 'sheet'
      	
      	mc = MyClass(frame=f, bg_color='white')
      	
      	if not _use_theme:
      		mc.present(style=style, animated=False)
      	else:
      		editor.present_themed(mc, theme_name='Oceanic', style=style, animated=False)
      		
      	# accessing a view, different ways
      	mc['cv']['p0'].bg_color = 'crimson'
      	cv = mc['cv']
      	cv.subviews[len(cv.subviews)-1].bg_color = 'cornflowerblue'
      
      1 Reply Last reply Reply Quote 0
      • Phuket2
        Phuket2 last edited by

        A small breakthrough in thinking. I created a split view horizontal function below. I have it working, but need to quite a bit more to clean it up and follow same API as the vertical. But almost 1am here now, time to go home eat some food and watch some series until,I pass out 😱💅🏽
        Will,finish this tomorrow, well actually it tomorrow already

        def split_view_hor(parent, v):
        
        	v.width = v.width / 2
        	r = ui.Rect(*v.frame)
        
        	r.x = r.max_x
        	
        	nv = ui.View(frame = r )
        	nv.flex = v.flex
        	nv.bg_color = 'yellow'
        	v.superview.add_subview(nv)
        
        1 Reply Last reply Reply Quote 0
        • Phuket2
          Phuket2 last edited by

          Ok, in my mind I have actually done something good now. I am guessing I have thought this before.
          I don't think it's finished yet. But it works very well in my opinion.

          So, it's just about creating a view of views. Which you basically always need. In this case, you call a function and pass a list of numbers to describe the vertical view, which returns a ui.View with the vertical views as subviews.
          Then if you need any of those vertical views to x number of views horizontally then you call another function that basically splits the view in place so to speak.

          Yes, I know some are thinking already, why 2 functions. I have struggled with this so many times in the past. Meaning how to do this in some sort of easy meaningful way. For me this so easy, to create the vertical view, then split the vertically views horizontally. The Params can be kept super simple. And the code doesn't get too twisted and complicated (maybe some will prove me wrong on this).

          But I do see that with a horizontal and vertical splitter function, you could make any view in a few mins. I will work on this next. Just wanted to get this far first.

          Also it's worth nothing that everything is orientation and size friendly, well what I have tested has been. Takes a long time to test all the variations. Also it's all running off flex , which simplifies again. The hard work is left to ui.

          Anyway the gist is below. I still see it as work in progress, improvements can and will be made. Again, I am really happy with this. It's not as the crow flys from a to b, but it's dead simple to use in my mind.

          gist

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

            Well life moves on. I think this gist Is a whole lot better. Now, I have 2 main functions that can easily build most common types of view layouts very easily. Amazing how simple it is. It's still work in progress. One big issue is finding a uniform way to access views. Using @JonB ViewWalker code I will find a way to do this. But now, the 2 main functions are insert_into_view and split_view_h. insert_into_view is nice as it can insert vertically or horizontally. split_view_h only splits a view horizontally, not sure it needs to split vertically. Vertically, you would use insert_into_view. It's still,a gist because more to do, but I am excited to share what I have anyway.

            The below view can be made with very little effort both in code and thought.

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

              Made more improvements today. The biggest dealing with the view names. I added a parameter to the 2 main functions to accept a list of names. I think I have done this in quite flexible way. I have commented the code. but this was a big thing missing, I think my approach is a pretty reasonable solution.

              I also added @JonB ViewWalker Class. it's very helpful. Most notably in MyClass (Example implementation ). You can easily access all your views with dot notation via one class attr. I have commented on this in the code.

              I did some other things such as a dynamic attr to the views created in the module called vid (View ID). Maybe not necessary, but it's still helpful for the sake of a few bytes per view.

              One thing I am conflicted about is the code similarities between the 2 main functions. is so tempting to try and merge them, but my gut feeling is this would be a mistake. Well for me it would be a mistake, lets say that. if I tried to combine them, I would be worried about really weird logic creeping in. I should be able to remove some of it into a different function that both funcs call. baby steps....

              I have a few things directly on my mind that I need to think about.

              1. when splitting a view, should the view being split be renamed. in a practical sense, it seems so. but this can make things a little ambiguous also.
              2. when splitting a view, should you inherit the visual aspects of the parent? Or maybe support kwargs, apply to the parent as well as the new views. The latter is starting to make more sense.
              3. Does split_view_h need to be able to split vertically as well.

              A few other smaller issues to consider also.

              Again, I know for a lot, this is not exciting. For me though, it is. it's only a wireframe so to speak. But getting wirefames in place to start populating them with tables/controls etc can be so frustrating and time consuming. and it's about the least exciting thing you have to do. if you can just knock out the wireframe quickly and start adding your functionality, to me that's great.

              Btw, the code looks long. it's not. it's just all the commentary.

              New gist Here.

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