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.


    Cover Flow view

    Pythonista
    1.6 custom-view mac scene
    6
    51
    38850
    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.
    • Webmaster4o
      Webmaster4o last edited by Webmaster4o

      New code, supports different screen sizes, and auto-resizes with device rotation. Also supports arbitrary numbers of images. It will display your images whether you have 1 image or 100. Now running it will also pick random images from the included images to present.

      # coding: utf-8
      import ui
      from PIL import Image
      from io import BytesIO
      from time import sleep
      from math import exp, log, copysign, ceil
      
      BGCOLOR = '#0F0F0F'
      
      def pil_to_ui(img):
      	b = BytesIO()
      	img.save(b, "PNG")
      	data = b.getvalue()
      	b.close()
      	return ui.Image.from_data(data)
      
      				
      class CoverFlow(ui.View):
      	def __init__(self, images):
      		self.images = [pil_to_ui(image) for image in images]
      		if len(self.images) < 9:
      			self.images *= int(ceil(9./len(self.images)))
      		self.frame = (0, 0, 1024, 768)
      		self.oldframe = (0, 0, 1024)
      		self.background_color = BGCOLOR
      		#Make frames for all views
      		N = 9
      		frames = []
      		#Create frames
      		for i in xrange(N):
      			#Thanks to @JonB for this code.
      			w=370/1024.*self.width*exp(-2.4*(abs((i-N/2.0+0.5)/N)**(1.38/N**0.25)))
      			xc=512/1024.*self.width+copysign(470.0/1024*self.width*log(w/(370.0/1024*self.width)),i-N/2)
      			yc= (192/1024.*self.width-w)
      			frames.append((xc-0.5*w, yc+0.5*w, w, w))
      		
      		#Create subviews for the minimum of 9 images
      		for index, frame in enumerate(frames):
      			iv = ui.ImageView(frame=frame)
      			iv.image = self.images[index]
      			iv.prev_frame = iv.frame
      			self.add_subview(iv)
      			if index > 4:
      				iv.send_to_back()
      				
      		#Handle any additional images that are provided
      		for i in self.images[9:]:
      			iv9 = ui.ImageView(frame=frames[-1])
      			iv9.image = i
      			iv9.prev_frame = iv9.frame
      			self.add_subview(iv9)
      			iv9.send_to_back()
      	
      	def layout(self):
      		if self.frame != self.oldframe:
      			N = 9
      			frames = []
      			#Create frames
      			for i in range(N):
      				#Thanks to @JonB for this code.
      				w=370/1024.*self.width*exp(-2.4*(abs((i-N/2.0+0.5)/N)**(1.38/N**0.25)))
      				xc=512/1024.*self.width+copysign(470.0/1024*self.width*log(w/(370.0/1024*self.width)),i-N/2)
      				yc= (192/1024.*self.width-w)
      				frames.append((xc-0.5*w, yc+0.5*w, w, w))
      			
      			for sv in self.subviews:
      				self.remove_subview(sv)
      			#Create subviews for the minimum of 9 images
      			for index, frame in enumerate(frames):
      				iv = ui.ImageView(frame=frame)
      				iv.image = self.images[index]
      				iv.prev_frame = iv.frame
      				self.add_subview(iv)
      				if index > 4:
      					iv.send_to_back()
      					
      			#Handle any additional images that are provided
      			for i in self.images[9:]:
      				iv9 = ui.ImageView(frame=frames[-1])
      				iv9.image = i
      				iv9.prev_frame = iv9.frame
      				self.add_subview(iv9)
      				iv9.send_to_back()
      			self.oldframe = self.frame
      		
      	def anim(self):
      		#Change frames
      		len_subviews = len(self.subviews)
      		for i, sub in enumerate(self.subviews):
      			next = self.subviews[(i + (1 if self.touch_direction else -1)) % len_subviews]
      			sub.frame = next.prev_frame
      		for sub in self.subviews:
      			sub.prev_frame = sub.frame
      		
      		#Resort self.images
      		if self.touch_direction:
      			self.images = [self.images[-1]]+self.images
      			self.images.pop(-1)
      		else:
      			self.images = self.images + [self.images[0]]
      			self.images.pop(0)
      		#Reorder layers based on the fact that biggest images are in front
      		#Bring smallest images to front first
      		for s in sorted(self.subviews, key=lambda x: x.frame[3]): s.bring_to_front()
      
      	def touch_began(self, touch):
      		self.touch_direction = None
      
      	def touch_moved(self, touch):
      		if touch.location != touch.prev_location:
      			self.touch_direction = int(touch.location.x > touch.prev_location.x)
      		else:
      			pass
      
      	def touch_ended(self, touch):
      		if self.touch_direction != None:
      			ui.animate(self.anim, duration=0.25)
      
      if __name__ == '__main__':
      	#Pick random images from default textures
      	import os, random
      	app_path = os.path.abspath(os.path.join(os.__file__, '../../../..'))
      	os.chdir(app_path + '/Textures')
      	imagenames = os.listdir(os.curdir)
      	validnames = []
      	for x in imagenames:
      		if not (x.startswith('ionicons') or x.startswith('Typicons')):
      			validnames.append(x)
      	
      	images = [Image.open(random.choice(validnames)) for x in xrange(15)]
      	view = ui.View(background_color=BGCOLOR)
      	cf = CoverFlow(images)
      	view.add_subview(cf)
      	cf.present(hide_title_bar=1)
      

      layout literally removes all the subviews and recreates them, because I couldn't figure out how to adjust the frames easily, but the layout method takes under a hundredth of a second to perform so I don't think it's a problem.

      Phuket2 1 Reply Last reply Reply Quote 2
      • Webmaster4o
        Webmaster4o last edited by

        Realized I can cut out most of __init__, gist is here. I think I'm done with it, now. I'd like to maybe get rid of the objects animating sliding behind, I'll edit the gist for that.

        1 Reply Last reply Reply Quote 1
        • techteej
          techteej last edited by

          @Webmaster4o I would recommend making it a repo instead- as you can accept pull requests and make it easier to collaborate and build on.

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

            Sure. I've also just realized that the only thing (I think) preventing it from being 1.5-compatible is the assigning of arbitrary attributes to views (sv.prev_frame). I should be able to eliminate this easily, then it'll work on non-beta devices.

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

              Having trouble setting alpha to 0 for the frame passing behind. I tried to set the frames alpha before and after animating, but this doesn't work because code after ui.animate is executed before the animation has finished. My code was this, but it's sloppy and doesn't work:
              def animate(self):
              len_subviews = len(self.subviews)

              	for i, sub in enumerate(self.subviews):
              		next = self.subviews[(i + (1 if self.touch_direction else -1)) % len_subviews]
              		if next.prev_frame[0] < sub.prev_frame[0]:
              			resetter = sub
              			sub.alpha = 0
              	
              	def anim():
              		#Change frames
              		for i, sub in enumerate(self.subviews):
              			next = self.subviews[(i + (1 if self.touch_direction else -1)) % len_subviews]
              			sub.frame = next.prev_frame
              
              	#Animate
              	ui.animate(anim, 0.25)
              	resetter.alpha = 1
              	#Re-sort self.images
              	if self.touch_direction:
              		self.images = [self.images[-1]]+self.images
              		self.images.pop(-1)
              	else:
              		self.images = self.images + [self.images[0]]
              		self.images.pop(0)
              	
              	#Reorder layers based on the fact that biggest images are in front,
              	#Bring smallest images to front first
              	for s in sorted(self.subviews, key=lambda x: x.frame[3]): s.bring_to_front()
              	
              	#Reassign prev_frame
              	for sub in self.subviews:
              		sub.prev_frame = sub.frame
              
              1 Reply Last reply Reply Quote 0
              • Phuket2
                Phuket2 @Webmaster4o last edited by

                @Webmaster4o, I don't have much time to look at the forum at the moment. Many friends in town now. But your CoverFlow class is a great improvement.

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

                  Gist updated with backwards compatibility to 1.5, successful on my iPhone running ios7 and 1.5. I probably will end up making it a repo soon.

                  1 Reply Last reply Reply Quote 1
                  • TutorialDoctor
                    TutorialDoctor last edited by

                    Nice work! Coming along nicely. I am wondering if this could browse IOS photos? What would you use it for?

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

                      Browsing iOS photos is a good idea.

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

                        @TutorialDoctor, you ask what it could be used for. I think is just nice ui control, same as a slider. I think a nice step fwd would be to be able to provide a ui.view. Then not just images anymore. Also the cover controller doesn't care, just providing a series of frames with all the correct math and animations and touch events.

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