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.


    Drop Shadow behind ui.view()

    Pythonista
    5
    24
    17877
    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.
    • blmacbeth
      blmacbeth last edited by blmacbeth

      I have been playing around with objc_util again and came up with this piece of code you might find applicable to your code above:

      # coding: utf-8
      from objc_util import *
      import ui
      
      UIColor = ObjCClass('UIColor')
      
      view = ui.View(frame=(0,0,500,500))
      box  = ui.View(frame=(0,0,100,100))
      
      view.background_color = 'white'
      box.background_color = 'red'
      box.center = view.center
      
      view.add_subview(box)
      
      box_pntr = ObjCInstance(box)
      ## Note: this allows for shadows to be drawn
      box_pntr.layer().setMasksToBounds_(False)
      box_pntr.layer().setCornerRadius_(6)
      ## Note: CGColor is needed in order for this to work
      box_pntr.layer().setBorderColor_(UIColor.cyanColor().CGColor())
      box_pntr.layer().setBorderWidth_(3)
      box_pntr.layer().setShadowRadius_(10)
      box_pntr.layer().setShadowOffset_(CGSize(0,0))
      box_pntr.layer().setShadowOpacity_(1.0)
      
      view.present('sheet')
      

      Hope you find this useful.

      Phuket2 2 Replies Last reply Reply Quote 3
      • Phuket2
        Phuket2 @blmacbeth last edited by

        @blmacbeth , thanks for sharing. Even though I wasn't the one asking for it, I have saved it for use later 😜

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

          @blmacbeth, I am just playing around with ui.TableView.datat_source at the moment. But I just remembered your code for shadowing a view. I wanted to try it. I did, I cut it up just to return a ui.View. But the full script below (nothing complete about the script, still working on it. Just excited and wanted to share) . But It looks nice.
          But it would be so much more useful if you created a custom class based on ui.View, and tweak the settings etc... This could be a very cool class to submit to the pythonistia_tools repo.
          But thanks again. I don't play with objc stuff for now... Still trying to learn python.

          # coding: utf-8
          
          import ui
          from objc_util import *
          
          def shadow_box(parent):
          	# using chopped up code from @blmacbeth
          	UIColor = ObjCClass('UIColor')
          
          	f = ui.Rect(*parent.bounds).inset(10,10)
          	box  = ui.View(frame=f)
          
          	box.background_color = 'white'
          
          	box_pntr = ObjCInstance(box)
          	## Note: this allows for shadows to be drawn
          	box_pntr.layer().setMasksToBounds_(False)
          	box_pntr.layer().setCornerRadius_(6)
          	## Note: CGColor is needed in order for this to work
          	box_pntr.layer().setBorderColor_(UIColor.grayColor().CGColor())
          	box_pntr.layer().setBorderWidth_(.5)
          	box_pntr.layer().setShadowRadius_(10)
          	box_pntr.layer().setShadowOffset_(CGSize(0,0))
          	box_pntr.layer().setShadowOpacity_(1.0)
          
          	return box
          
          class AbstractDataSource(object):
          	def __init__(self, tbl, items, **kwargs):
          		# assign positional args
          		tbl.data_source = self
          		tbl.data_source.items = items
          
          		self.sections = None
          		self.can_move = False
          		self.can_delete = False
          		self.can_edit = False
          		self.make_cell_func = None
          
          		self.cell_type = ''
          
          		self.sec_title = None
          
          		for k,v in kwargs.iteritems():
          			if hasattr(self, k):
          				setattr(self, k, v)
          
          	def tableview_number_of_rows(self, tv, sec):
          		# Return the number of rows in the section
          		return len(tbl.data_source.items)
          
          	def tableview_cell_for_row(self, tv, sec, row):
          		# Create and return a cell for the given section/row
          		if self.make_cell_func:
          			return self.make_cell_func(tv, sec, row)
          
          		cell = ui.TableViewCell(self.cell_type)
          		cell.text_label.text = 'Foo Bar'
          		return cell
          
          	def tableview_title_for_header(self, tv, sec):
          		# Return a title for the given section.
          		# If this is not implemented, no section headers will be shown.
          		if self.sec_title:
          			return self.sec_title
          		elif not self.sections:
          			return None
          		else:
          			return 'Some Section'
          
          	def tableview_can_delete(self, tv, sec, row):
          		# Return True if the user should be able to delete the given row.
          		return True
          
          	def tableview_can_move(self, tv, sec, row):
          		# Return True if a reordering control should be shown for the given row (in editing mode).
          		return True
          
          	def tableview_delete(self, tv, sec, row):
          		# Called when the user confirms deletion of the given row.
          		pass
          
          	def tableview_move_row(self, tv, from_sec, from_row, to_sec, to_row):
          		# Called when the user moves a row with the reordering control (in editing mode).
          		pass
          
          
          class MyListDataSource(AbstractDataSource):
          	def __init__(self, tbl, items, **kwargs):
          		AbstractDataSource.__init__(self, tbl,  items , **kwargs)
          		# we do this instead of overriding, to get extended functionality..
          		self.make_cell_func = self.make_cell
          
          	def make_cell(self, tv, sec, row):
          		cell = ui.TableViewCell(self.cell_type)
          		cell.text_label.text = 'make_cell - row' + str(row)
          		return cell
          
          if __name__ == '__main__':
          	f = (0,0,500, 500)
          	v = ui.View(frame = f, bg_color = 'white')
          	tbl = ui.TableView()
          	box = shadow_box(v)
          	v.add_subview(box)
          	ds = MyListDataSource(tbl, range(20), sec_title = 'ian πŸ‘Ώ')
          	box.add_subview(tbl)
          	v.present('sheet')
          	r = ui.Rect(*tbl.superview.bounds).inset(10,10)
          	tbl.frame = r```
          1 Reply Last reply Reply Quote 0
          • blmacbeth
            blmacbeth last edited by

            Ask and he shall receive. It's not perfect, yet. There are some clipping problems I can't figure out.

            # coding: utf-8
            from objc_util import *
            import ui
            
            UIColor = ObjCClass('UIColor')
            
            def Color(red=0, green=0, blue=0, alpha=1):
            	return UIColor.colorWithRed_green_blue_alpha_(red, green, blue, alpha)
            
            class ShadowView (ui.View):
            	def __init__(self, *args, **kwargs):
            		super(ShadowView, self).__init__()
            		self.pntr = ObjCInstance(self)
            		self.pntr.layer().setMasksToBounds_(False) ## Go ahead and do this.
            		
            	@property 
            	def corner_radius(self):
            		return self.pntr.layer().cornerRadius()
            		
            	@corner_radius.setter
            	def corner_radius(self, val):
            		self.pntr.layer().setCornerRadius_(val)
            		
            	@property
            	def border_color(self):
            		return self.pntr.layer().borderColor()
            		
            	@border_color.setter
            	def border_color(self, color):
            		self.pntr.layer().setBorderColor_(Color(*color).CGColor())
            		
            	@property
            	def border_width(self):
            		return self.pntr.layer().borderWidth()
            		
            	@border_width.setter
            	def border_width(self, val):
            		self.pntr.layer().setBorderWidth_(val)
            		
            	@property 
            	def opacity(self):
            		return self.pntr.layer().opacity()
            		
            	@opacity.setter
            	def opacity(self, val):
            		self.pntr.layer().setOpacity_(value)
            		
            	@property 
            	def hidden(swlf):
            		return self.pntr.layer().hidden()
            		
            	@hidden.setter
            	def hidden(self, val):
            		self.pntr.layer().setHidden_(val)
            		
            	@property 
            	def masks_to_bounds(self):
            		return self.pntr.layer().masksToBounds()
            		
            	@masks_to_bounds.setter
            	def masks_to_bounds(self, val):
            		self.pntr.layer().setMasksToBounds_(val)
            		
            	@property 
            	def mask(self):
            		return self.pntr.layer().mask()
            		
            	@mask.setter
            	def mask(self, new_mask):
            		self.pntr.layer().setMask_(new_mask)
            		
            	@property
            	def double_sided(self):
            		return self.pntr.layer().doubleSided()
            		
            	@double_sided.setter
            	def double_sided(self, val):
            		self.pntr.layer().setDoubleSided_(val)
            		
            	@property
            	def shadow_opacity(self):
            		return self.pntr.layer().shadowOpacity()
            		
            	@shadow_opacity.setter
            	def shadow_opacity(self, val):
            		self.pntr.layer().setShadowOpacity_(val)
            		
            	@property
            	def shadow_radius(self):
            		return self.pntr.layer().shadowRadius()
            		
            	@shadow_radius.setter
            	def shadow_radius(self, val):
            		self.pntr.layer().setShadowRadius_(val)
            		
            	@property
            	def shadow_offset(self):
            		return self.pntr.layer().shadowOffset()
            		
            	@shadow_offset.setter
            	def shadow_offset(self, offset):
            		## offset should be a tuple, but I'll take a CGSize
            		if isinstance(offset, CGSize):
            			self.pntr.layer().setShadowOffset_(offset)
            		elif isinstance(offset, tuple):
            			self.pntr.layer().setShadowOffset_(CGSize(*offset))
            		else:
            			raise TypeError("Cannot use type %s. Use CGSize or tuple" % type(offset))
            			
            	@property
            	def shadow_color(self):
            		return self.pntr.layer().shadowColor()
            		
            	@shadow_color.setter
            	def shadow_color(self, color):
            		if isinstance(color, UIColor.CGColor()):
            			self.pntr.layer().setShadowColor_(color)
            		elif isinstance(color, tuple) and len(color) == 4:
            			self.pntr.layer().setShadowColor_(Color(*color).CGColor())
            		else:
            			raise ValueError('Cannot use type %s. Use UIColor or tuple' % type(color))
            			
            		@property
            		def shadow_path(self):
            			return self.pntr.layer().shadowPath()
            			
            		@shadow_path.setter
            		def shadow_path(self, path):
            			self.pntr.layer().setShadowPath_(path)
            			
            		@property
            		def style(self):
            			return self.pntr.layer().style()
            			
            		@style.setter
            		def style(self, style):
            			self.pntr.layer().setStyle_(style)
            			
            if __name__ == '__main__':	
            	view = ui.View(frame=(0,0,500,500))
            	box  = ShadowView(frame=(0,0,100,100))
            	
            	view.background_color = 'white'
            	box.background_color = 'red'
            	box.center = view.center
            	
            	view.add_subview(box)
            	
            	box.masks_to_bounds = False
            	box.corner_radius = 6.
            	box.border_color = (0,1,0)
            	box.border_width = 6
            	box.shadow_radius = 10
            	box.shadow_offset = (0,0)
            	box.shadow_opacity = 1
            	
            	view.present('sheet')
            

            I tested most of it, but there may still be some funny-ness.

            B.

            Phuket2 1 Reply Last reply Reply Quote 2
            • Phuket2
              Phuket2 @blmacbeth last edited by

              @blmacbeth , ok thanks. I will try it. Maybe I am wrong, but doesn't your call to super need to be like
              super(ShadowView, self).init(self, *args, **kwargs)

              If not, then I would love to know why not.

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

                @Phuket2 Since you've already passed self as an argument to super, you already get (bound) methods instead of normal functions, so you don't need to pass self as the first parameter to __init__. Though you are right, the *args and **kwargs do need to be passed (if you want ui.View to interpret them, which I assume is the case). For ui.View the docs say that you don't need to call super().__init__() at all, perhaps everything important is already handled by __new__.

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

                  @Phuket2 Ha! You caught me. That may be a problem… it should look like:

                  super(ShadowView, self).__init__(*args, **kwargs)
                  

                  I must have been in a zone to miss that. There is no need to repeat self in the __init__ call because super(ShadowView, self) returns an instance of the superclass, which will pass self implicitly.

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

                    @dgelessus , thanks. I tend not to call super anymore. I normally call the class init method. I think I did that because I was doing multiple inheritance and was having a hard time following what was going on 😭, to this day I still don't know the most correct way.
                    I am pretty sure I have checked this theory of not having to pass on params to ui.View, I know it's in the docs. As far as I can see it does not work. Maybe if you have no init. Not sure that should cancel new, but maybe it's been written to work that way. So many combinations, I get confused 😱

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

                      @blmacbeth , lol. I understand. I thought you had some special trick up your sleeve 😝

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

                        @Phuket2 I wish I have a cool trick up my sleeve! But to comment on your response about not calling super: it is best practice to call super when subclassing. This is because it allows you to refactor your code with less changes made afterwards.

                        For example: let's say I someday make a kick-ass version of UIView and UIViewController that make ui.View look like children's toys. So, you want to incorporate the new view classes into your old code. The way you have, you would need to change every instance of ui.View.__init__(...). By calling super you no longer have to do all that tedious work. It makes life slightly easier.

                        I'm not saying that what your doing is wrong; I have plenty of classes that do the same thing. But o have started using super because of the refactoring issue.

                        Now, this could all be a load of bullshit I am feeding you, so go look it up yourself and let me know if I'm correct! πŸ˜›

                        B.

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

                          @blmacbeth , hmmm, I am a little on the drunk side now πŸŽ‰πŸ˜Ž almost 11:30pm here now. So maybe I should wait until tomorrow to look it up 😱
                          But I started getting a problem when inheriting from multiple classes. Gets confusing about which base class is being called ( it did for me anyway). That's when I started using the implicit calls to base class's init methods instead. But I see your point though. I haven't managed to write anything significant enough in Python were it's been a problem to refactor 😭
                          Still trying though

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

                            re needing to call View.init, see
                            https://forum.omz-software.com/topic/2548/inheritance-and-kwargs-popping-consumption/5

                            If you do not implement your own init, you do not need to call super init.
                            If you have an init, you do need to call the View.init

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

                              From what I've heard, you need to use super() for some aspects of multiple inheritance to work properly. I know almost nothing about the details of multiple inheritance on Python though, so I can't tell you why exactly that is and what would break otherwise. Mostly because multiple inheritance is not needed very often.

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