omz / Pythonista-Issues

Issue tracker for Pythonista (iOS)
169 stars 14 forks source link

Ui components frame default size - enhancement #494

Open Phuket2 opened 6 years ago

Phuket2 commented 6 years ago

@omz, the default sizes you have chosen for ui components in my opinion don't make sense. (I, know I have brought this up before) Below I have listed the objects with their frame sizes on creation and comment if I think it does not make sense.

I think a pivotal point is to choose a good ui.View default size. I am not sure what it should be, but to me it seems like the most popular iphone screen size would be a good starting point.
I think this is important, because other items defaults should be considered relative to the ui.View

Look I am not saying what I have written below is exact, but it seems like a step forward. A lot of the defaults just dont make sense, eg ui.Button. In the ui Designer if you create a button, its 80w, 32h. Seems like a good size instead of (0, 0, 0, 0) when created programmatically without a frame param.

oh, also applying size_to_fit on a ui.Button when its created seems very counter productive. I think most people would choose their titles to fit the button width. The exception would be to change the width of your button if you had longer text.

Below are the defaults of the frame attr when the object is created View - (0.00, 0.00, 100.00, 100.00) why not pick a default size like an iPhone 6 or the most popular as the default

Label - (0.00, 0.00, 100.00, 100.00) width of the ui.View, height 32

TextField - (0.00, 0.00, 100.00, 100.00) width of the ui.View, height 32

TextView - (0.00, 0.00, 100.00, 100.00) The bounds of the ui.View as default

Button - (0.00, 0.00, 0.00, 0.00) 80 wide , 32 high

ImageView - (0.00, 0.00, 100.00, 100.00) Width, height 32 (this would seem the most common)

WebView - (0.00, 0.00, 100.00, 100.00) The bounds of the ui.View as default

TableView - (0.00, 0.00, 100.00, 100.00) The bounds of the ui.View as default

ScrollView - (0.00, 0.00, 100.00, 100.00) The bounds of the ui.View as default

Phuket2 commented 6 years ago

I just want to clarify that my meaning when I say the bounds of the ui.View, I had in mind the static size of the default ui.View decided upon. Again, I know all this stuff is tricky. Can sound very simple, but many ways to look at this issue. I guess another issue is backward compatibility. Some ppl may have coded around knowledge of these default sizes (Although I doubt it). But if it believed that these defaults may cause problems to existing ui App, there could be possibly a ui method to say use the new defaults, and by default use the old defaults.

I guess going one step further would be the ability to override any of ui controls defaults for any attr. So say a method in ui where you pass the ui instance type and **kwargs. The kwargs just valid attrs with a default value. Because while I have talked about frame above, there really is more to it. Eg. I would like each time I created a ui.Button that the border_width =.5, corner_radius = 6, bg_color = 'white'. So at the begining of my code i could do something like: ui.set_default(ui.Button, width=80, height=32, border_width =.5, corner_radius = 6, bg_color ='white') ui.set_default(ui.TableView, corner_radius=6) There after any ui.TableView created would have a corner_radius of 6 by default. Then you could maybe have - ui.set_default(ui.TableView, None), which would remove your overrides defaults and ui.TableView would just use the defaults pre coded.
So basically the approach here, is you only override those default attrs of a ui object that is important for you given the App.

zrzka commented 6 years ago

You forced me to write a longer response :) Was thinking about this one for a long time, little bit lazy, but now it's the time :)

the default sizes you have chosen for ui components in my opinion don't make sense

But it's probably better than CGRectZero (0, 0, 0, 0). For example, when I create UILabel in this way:

UILabel *lbl = [[UILabel alloc] init];
lbl.text = @"Hallo";
[self.view addSubview:lbl];    
NSLog(@"%@", NSStringFromCGRect(lbl.frame));

The frame is CGRectZero (= 0, 0, 0, 0). There's no UILabel initialiser allowing me to specify frame and text. Basically almost all UIView subclasses have init (-> CGRectZero) or initWithFrame:.

I don't see a big problem with 100x100 and I suspect that it's because the ui.View is basically not just UIView, it's a combination of UIView and UIViewController. It's kind of convenience for Pythonista users, because you can call present() on ui.Label for example. Which is weird in the UIKit world :) I didn't inspect this part of Pythonista much, I'm just guessing and it probably has a reason.

Anyway, the point is that when you do these things in code, all these views / controls have some default size. It's CGRectZero in UIKit, 100x100 in Pythonista. And there's a reason for this - continue reading.

I think a pivotal point is to choose a good ui.View default size. I am not sure what it should be, but to me it seems like the most popular iphone screen size would be a good starting point.

There's no good ui.View default size, even when you base it on the most popular iPhone screen size. Okay, 100x100 can be changed to anything else, but I'm a big fan of iPhone SE for example (sold all these bigs 6, 7, Plus, ...) and here you have a first person which is against the most popular iPhone screen size :) What I'm trying to say, you can't simply satisfy everyone. There will always be unhappy people no matter what Ole is going to choose.

Also what behaviour is expected when you have default label size like 80x44 and text doesn't fit? Do you expect to call sizeToFit automagically? You can do this in the initialiser. And then another person will appear requesting magic sizeToFit call when the font property is modified. Where it will end? Magic everywhere?

Here you have two choices:

It's vicarious problem in my eyes and I don't see anything to be done here.

On the other side, if you want magic, support #402 (autolayout.py, Auto Layout Guide, ...).

also applying size_to_fit on a ui.Button when its created seems very counter productive

What is counter productive with this? Remember - you voluntarily left the UI Designer. You should be ready to cope with it.

ui.set_default(ui.Button, width=80, height=32, border_width =.5, corner_radius = 6, bg_color ='white')

In the UIKit world, there's a thing called UIAppearance allowing you to set default button colour for example. You can't do everything you'd like to do with, but it helps. I assume that this one is used for Pythonista look & feel and thus it can't be used from within Python scripts, because it's one runtime, one application, ... and whatever you do will interfere with Pythonista interface. Can imagine UIAppearance in scripts (appearanceWhenContainedIn:), but it's not worth the trouble (in case of bug, UI of Pythonista will be crippled, doesn't support everything, ...).

Why don't you use factory method for all these things? Just create simple module for yourself with functions like:

import ui

_DEFAULTS = {
    ui.Label: dict(
        border_width=.5,
        background_color='white',
        border_color='red',
        frame=(0, 0, 80, 32),
        corner_radius=3.0 
    )
}

def make(cls, *args, **kwargs):
    defaults = dict(_DEFAULTS.get(cls, {}))
    defaults.update(kwargs)
    return cls(*args, **defaults)

def label(*args, **kwargs):
    return make(ui.Label, *args, **kwargs)

lbl = make(ui.Label, border_width=2.0)  # or just label(border_width=2.0)
print(lbl.frame)  # -> (0, 0, 80, 32)
print(lbl.border_width)  # -> 2.0
print(lbl.corner_radius)  # -> 3.0
print(type(lbl))  # -> _ui.Label

Simple and easy enough to spare others from non standard stuff like ui.set_defaults, ...

Tempted to close this one, but will wait if Ole will step into this discussion or not.

P.S. Nice try with thumbs up to your own comment :)