Skip to content

Instantly share code, notes, and snippets.

@Phuket2
Created Dec 23, 2015
Embed
What would you like to do?
tmpPaYJ8A.py
import ui
'''
dict of dicts
key == x.__class.__name__
value = dict of the defaults for the object
'''
_std_defaults = \
{
'Button' : {
'tint_color': 'blue',
'width' : 80,
'height' : 32,
'background_color' : None,
'x' : 0,
'y' : 0,
'title' : 'fred',
'border_width' : .5,
'corner_radius' : 3,
'name' : 'ButtonTest',
},
}
_attr_ignore_attrs = \
{
'Button' : \
['frame','width','height','x','y','flex',
'hidden','transform', 'border_width, corner_radius, background_color'],
}
class ControlExt(ui.View):
def __init__(self , ui_object, *args, **kwargs):
self.obj = ui_object()
self.hidden = True
self.add_subview(self.obj)
self.obj.flex = 'WH'
if kwargs.get('parent', False):
print 'we have a parent'
if kwargs.get('add', False):
print 'we will add ourself to parent'
kwargs.get('parent').add_subview(self)
#self.ignore_attr_list = object.get_attr_ignore_list()
self.std_object_creation(self.obj)
self.set_obj_args(self.obj, *args, **kwargs)
def __setattr__(self, name,value):
# flex, frame taken out
if name not in ['width','height','x','y','hidden','transform'
'border_width, corner_radius, background_color']:
if hasattr(self,'obj'):
if name in dir(self.obj):
print name, value
object.__setattr__(self.obj,name,value)
object.__setattr__(self,name,value)
f = self.frame # limit the calls to set/get scary...
# i cant get flex to work... doing it with a hammer for now
object.__setattr__(self.obj, 'frame', (0,0,f[2], f[3]))
def __getattribute__(self,name):
try:
return object.__getattribute__(self,name)
except AttributeError:
if hasattr(self,'obj') and name in dir(self.obj):
return object.__getattribute__(self.obj,name)
else:
raise
# dont use the obj init to set the args, kwargs
def set_obj_args(self , obj, *args, **kwargs):
for k,v in kwargs.iteritems():
if hasattr(obj, k):
if k == 'image':
setattr(obj, k , self.get_named_ui_image(v))
else:
setattr(obj, k, v)
print '**object kwargs ', k,v
def get_named_ui_image(self, image_name):
return ui.Image.named(image_name)
def std_object_creation(self, obj):
#set the attrs of the object as created without passing attrs
class_str = obj.__class__.__name__
obj_defaults = _std_defaults.get(class_str, False)
if not obj_defaults: return
for k, v in obj_defaults.iteritems():
if hasattr(obj, k):
if k == 'image':
setattr(obj, k , self.get_named_ui_image(v))
else:
setattr(obj, k, v)
print '**creation ', k,v
def get_attr_ignore_list(self):
return _attr_ignore_attrs.get(self.obj.__class__.__name__, [])
#def layout(self):
#self.obj.frame = self.frame
def how_did_we_get_here(self):
object.__setattr__(self.obj, 'frame', (0,0,f[2], f[3]))
# we need to create one per ui. class type
class _uiButtonExt(ControlExt):
'''
Can do ui.Button specfic stuff here
'''
def __init__(self, *args, **kwargs):
# support adding to subview
ControlExt.__init__(self, ui.Button, *args, **kwargs)
# LOL, do it before the call to the super or not...
# i have tried both ways. i am sure i will learn the hard way
'''
if kwargs.get('parent', False):
print 'we have a parent'
if kwargs.get('add', False):
print 'we will add ourself to parent'
kwargs.get('parent').add_subview(self)
'''
self.hidden = False
# would be nice to offer some positional func..
def please_center(self):
self.center = (self.superview.bounds.center())
def pos_br(self):
l,t,h,w = self.superview.bounds
ow, oh = self.obj.frame[2],self.obj.frame[3]
self.frame = (w - ow, h - oh, h, w)
#self.how_did_we_get_here()
#f1 = ()
# we only want to deal with this class
class uiButtonExt(_uiButtonExt ):
def __init__(self, *args, **kwargs):
_uiButtonExt.__init__(self, *args, **kwargs)
def btn_action(sender):
print 'btn hit'
if __name__ == '__main__':
f = (0,0, 500, 500)
v = ui.View(frame = f )
#v.hidden = True
v.present('sheet')
btn = uiButtonExt(parent = v, add = True, bg_color = 'purple', tint_color = 'white', action = btn_action, width = 50, height = 32)
btn.please_center()
#btn.pos_br()
#v.hidden = False
@jsbain
Copy link

jsbain commented Dec 24, 2015

in the obj creation, set self.obj.frame=self.bounds, and set self.obj.flex='wh' right after. Then get rid of lines 64/66, and add flex and frame back to line 55. The reason flex didnt work for you was because a button defaults to a different size as a View, plus you directly set the obj attributes in the func on line 80... big no no! So, get rid of that function and just use self instead of obj in lines 99-104. The getattribute magic of line 74 will make it appear that hasattr(self,'image'), for example, will return true, even though a View does not have an image attribute!

The key to this approach is that you should not set self.obj parameters directly, do it through self after the obj is created, sized to self.bounds and flexxed. You want self to be linked to obj, such that you don't make a change to obj size on its own. Anything that needs special handling needs to be in getattribute/setattr, otherwise when the user tries to change something, they don't interact directly with obj. Most

It would be a good idea to have a dedicated size_to_fit, which calls obj.size_to_fit, then sets self.bounds=obj.frame, then sets obj.frame=self.bounds (or, turn off obj.flex before size to fit, and reenable after modifying self.bounds). So in that case, obj decides the size, and self follows, rather than the usual other way around.

Loading

@jsbain
Copy link

jsbain commented Dec 24, 2015

here is a more complete list of special attributes. the ones that say self, or special ones, should be in the list in line 55. The ones that say obj do not need any special mention.

# coding: utf-8
# here is a more complete list of which attribs not to pass on to obj.
# comment indicate which attribute to use: self, or obj
# 
 '_objc_ptr',  # not sure... 
 'add_subview', # pass to obj, though careful because used in init
 'alpha',       #need to test, but i think set self.alpha=self.obj.alpha=alpha/2 .  not sure if alpha works through multiple layers 
 'autoresizing',  # self
 'background_color', #obj
 'bg_color',#obj
 'border_color',#self
 'border_width',#self
 'bounds',#self
 'bring_to_front',#self
 'center',#self
 'close',#self
 'content_mode',#obj
 'corner_radius',#both self and obj, i think
 'draw_snapshot',#self
 'flex',#self
 'frame',#self
 'height',#self
 'hidden',#self
 'left_button_items',#self
 'multitouch_enabled',#hmmm
 'name',#self
 'navigation_view',#self
 'on_screen',#self
 'present',#self
 'remove_subview',#obj
 'right_button_items',#self
 'send_to_back',#self
 'set_needs_display',#hmmm self i think
 'size_to_fit',#special: call obj's then size self.bounds=self.obj.frame
 'subviews',#obj
 'superview',#self
 'tint_color',#obj
 'touch_enabled',#obj
 'transform',#self
 'wait_modal',#self
 'width',#self
 'x',#self
 'y']#self
 'action' #reauires special handling
 'delegate'# requires special handling

Loading

@Phuket2
Copy link
Author

Phuket2 commented Dec 24, 2015

@JonB, thanks for the great feedback. I am working on it. From your comments i am pretty sure I can why I was going wrong. But I knew it was wrong. But it's complicated for me. But slowly and surely I am getting there :)
It's one of those things, you know it or you don't and you will struggle with it. I am at the struggle stage. The fun will come when I try to work out the attrs that you are not sure about :) well I am a little confused already. You say action needs special attention. I am sure it does if you say it. In my mind it doesn't. Just means I am not thinking deep enough about side effects. But no need to tell me, I will try and work it out myself.

Loading

@cclauss
Copy link

cclauss commented Dec 25, 2015

I created a new version in your repo to facilitate collaboration: https://github.com/Phuket2/Pythonista/tree/master

One issue that I fixed in that version is that the code above has 'border_width, corner_radius, background_color' written twice where I believe you intended 'border_width', 'corner_radius', 'background_color'.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment