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.
[Share] Position a ui.control in a view
-
@cook , if you pass a single char like 't' or 'b' , the x value is not changed for example. So the object will be positioned at this location without changes it x value. So I am pretty sure you can do as you suggest now.
Each char in the pos_code is evaluated as a single operation. Center 'c' in the stream of chars is treated differently. If c exists in the stream, it's deleted and append to the front of the stream.
This is just because of the way I handle c. The way I handle it, c effects both the x and y in a single operation. Without me patching this , the order would become important. Like 'bc' would just result with the object centred instead of it being centred on the bottom.Did I understand you correctly? If not please say. I am eager to improve this
-
elif code is 'r':
appears twice in the code above.I like @cook approach:
| tl | tc | tr | | ml | mc | mr | | bl | bc | br |
The code should first center the control in the view and then:
pos_code = (pos_code or '').lower() if 't' in pos_code: move control to top of view elif 'b' in pos_code: move control to bottom of view if 'l' in pos_code: move control to left of view elif 'r' in pos_code: move control to right of view
This means that:
- pos_code of 'mc', 'c', 'm', 'junk', or even the empty string on None will center the control in X and Y.
- pos_code of 'R' or 'r" will right justify the control in the view.
- pos_code of 'BR', 'RB', 'rb', 'r...B', 'rabid' will place the control at the bottom right of the view.
- 't' takes presidence over 'm' or 'b' if there are multiple in pos_code.
- 'l' takes presidence over 'c' or 'r' if there are multiple in pos_code.
-
Of course, a pos_code of
Black Label
will put the control at the bottom left of the view where it belongs. -
@ccc , lol, I am going to have at least 3 or 4 more whiskeys before trying to digest your comments 😱😬
But really -
Is the following in line with achieving your suggestions?
import ui def _make_button(title): btn = ui.Button() btn.width = 80 btn.height = 32 btn.border_width = .5 btn.title = title return btn def do_position(obj, pos_code='', pad = 0): if not obj.superview: return (False, ui.Rect()) # we only reference superview.bounds. hopefully this is correct! r = ui.Rect(*obj.superview.bounds) #obj.center = r.center() if 'c' in pos_code: pos_code = 'c' + pos_code.replace('c', '') pos_code = (pos_code or '').lower() for i in range(len(pos_code)): code = pos_code[i] if code is 'c': obj.center = r.center() elif code is 'l': obj.x = r.min_x + pad elif code is 'r': obj.x = r.max_x - (obj.width+pad) elif code is 't': obj.y = r.min_y + pad elif code is 'b': obj.y = r.max_y - (obj.height + pad) elif code is 'm': obj.y = (r.height / 2) - (obj.height / 2) return (True, ui.Rect(*obj.frame)) hide_title_bar = False style = '' w = 800 h = 600 f = (0, 0, w, h) pos_list=['tl', 'tc', 'tr', 'ml', 'mc', 'rm', 'bl', 'bc', 'br' ] v = ui.View(frame = f, bg_color = 'lightyellow') v.present(style = style, hide_title_bar = hide_title_bar ) for pos_code in pos_list: btn = _make_button(pos_code) v.add_subview(btn) # do_position, can only be called after its been added to a view. # does need to be like this, but it makes sense to do it this way. do_position(btn, pos_code, 30)
-
def do_position(obj, pos_code='', pad=0): if not obj.superview: return (False, ui.Rect()) # we only reference superview.bounds. hopefully this is correct! r = obj.superview.bounds obj.center = r.center() pos_code = (pos_code or '').lower() if 'l' in pos_code: obj.x = r.min_x + pad elif 'r' in pos_code: obj.x = r.max_x - (obj.width+pad) if 't' in pos_code: obj.y = r.min_y + pad elif 'b' in pos_code: obj.y = r.max_y - (obj.height + pad) return (True, obj.frame)
-
@ccc , ok. I see what you mean now. I my function with your version and it worked as expected. Shorter code also. But same in functionality (basically).
But wouldn't my approach be better suited to exapanding the functionality? I am not making a statement, I am asking. This function is just sort of ok. Mainly good for testing.
Maybe this function can't be expanded to be really functional in real world. And I know the problem, sizing is not considered.
I have often thought about the grid system used in the old battleship game before for both positioning and sizing objects. Ok, it's just a grid. But maybe it's a better route? Not sure.
-
Oh yeah man... The code I gave you was merely focused on the gracefully dealing with garbage input for nine boxes that your question was about.
Laying out components in a UI is a massive topic and (like almost all UI-related issues) not a topic that I have any expertise in.
You might check out different layout mangers that Java uses to get some ideas: https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html The GridBag might be of special interest.
I think that Pythonista approach does a nice job of letting you lay things out well without going cross-eyed trying to understand the complexities of layout managers.
Build the battleship game and I will kick your butt... You on the beach and me in the mountains.
-
One last item...
for i in range(len(pos_code)): code = pos_code[i] # becomes... for code in pos_code:
-
@ccc , I agree. Pythonista gives you a big head start. But it's wanting. But I am sure not because of anything else other than time.
But imagine if the wrench menu was available in the designer and there was a Designer Module.
Example you want to evenly distribute 3 objects in a view or a subview. At the moment it's a pain (manual job). But if we could run some code from the wrench menu for example with a designer module exposing, selected items, superview etc...making views in the designer could be so easy. That's only one example, but you could do a lot.
I do understand, this would be a fairly large under taking for omz. Well, I think. Maybe he is in good shape for this. One thing that gives me a hint is that you can copy , and then paste attrs to another object. Also copying between different UIFiles seems to work properly, to the root or a subview or a subview of a subview.Many battleship games still out there. I am not saying I am great. I just know I loved it as a kid. For our generation it was a lot of fun. It will probably come back into fashion at some point the way the marvel comics have. Who would have thought 😱😬
-
@ccc @phuket2 you had a lot going on here with this and I didn't see. Sorry! Ian's original post got me thinking about layout a lot, and I started on something as well. I really like how you can do a lot of auto layout in html with css or javascript and it's really useful. I think the same is possible for
UI
. So far I have:- distribute horizontally (equal distribution) with padding is possible
- distribute vertically (equal distribution) with padding is possible
- adjust width/height/x/y by percent (rather than by points or pixels)
Working on a grid distribution.
None of this is too hard or rocket science. Just a bunch of numbers. I'm sure anyone could do it...
It's really different than what @phuket2 has above though...!!I don't know why I didn't think to do this before... I seem to use a kind of distribution for doing buttons at times, but having it in a module would be much easier. Will share once I've got kinks worked out...
With what I have already I could do @phuket2 's battleship grid without the headache! But I want to improve the functions to make it even more straightforward.
-
another approach might be a more pythonic implementation of ios layout constraints. These are incredibly powerful, though a bit of a pain to use.
Another approach:
Years ago, I tried my hand at implementing layout controllers sort of similar to the java equivalents. One difficulty was that there was no way at the time to specify a "preferred size" or minimum size.. though now with custom attributes it is possible.
The idea was to override add_subview to properly handle layout of the elements, then different container types would layout the subviews appropriately.
I implemented a flowcontainer, and a box layout before I lost interest....
https://github.com/jsbain/uicomponents.git
see uicontainer.py and BoxLayout.py -
@Phuket2 As I mentioned in other forum post I have added the example file position_img_shape_in_custom_view.py in textlayout repository.
https://github.com/balachandrana/textlayout.
You can do a git pull if you have already got this.It is not just limited to pyui. We could use it in custom views for placement of various shapes and images. May be I will post an example later.
This example illustrates using placement of images and shapes in custom view using textlayout module. The textlayout module is generic enough to use in other types of applications. Here is the portion of code illustrating the layout of images and shapes.
Only one image or shape (element) is shown at a time and you can do a tap to change the current element.
layout_text = ''' ******** i--***** |--***** **s--*** ******** ****s--* ******** ******** ''' ui_element_map = { 'i': ('image', Img), 's': ('shape', Shape) }