Cover Flow Gadget

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Oliver13
Beiträge: 35
Registriert: 08.05.2010 15:49

Cover Flow Gadget

Beitrag von Oliver13 »

Hallo,

auf http://forums.purebasic.com/english/vie ... 13&t=45835 habe ich ein Beispiel für ein CoverFlow gefunden und dieses mal (mehr schlecht als recht, zugegebenermassen...) in ein UserGadget konvertiert.

Vielleicht hat ja jemand Lust, das noch zu optimieren, z.B.
- Grössenanpassung
- Weicheres Scrollen /weniger Flackern
- Hervorheben des ausgewählten Eintrags
- erweiterte Maus- und Tastaturunterstützung
...


Wichtig:
Ich habe den eventmanager von ts-soft verwendet; es wird also das include file von http://www.purebasic.fr/german/viewtopi ... =8&t=26471 benötigt.

Viele Grüsse
Oliver

Code: Alles auswählen

; CoverFlowGadget

;  ; Cover flow written by Michael Vogel
; ---------------------------------------------

; done...
; + configurable sizes, background color etc.
; + cursor keys to scroll left and right

; to do...
; – faster scrolling with shift ???
; – mouse drag and drop?
; – fast (!) shadow effects?

; http://forums.purebasic.com/english/viewtopic.php?f=13&t=45835




XIncludeFile "EM_EventManager.pbi"
; http://www.purebasic.fr/german/viewtopic.php?f=8&t=26471


Enumeration
  #ShelfLeft
  #ShelfRight
  #ShelfQuit
  
  #Cover
  #CoverImage
  #CoverImageTemp
  #CoverImagePool=200
  
EndEnumeration
#LovelyBird=$0A9C5E

#MaxCoverImages=30

#ShelfColor=#White

#ShelfSize=12;      Anzahl der Covers in einer Zeile (äußerste nicht sichtbar)
#ShelfPhase=5;      Anzahl der Phasen beim Durchblättern
#ShelfSpace=6;      Pixel zwischen Thumbnails
#ShelfMin=128;      Verkleinerung in Relation zum zentralen Cover (256)
#ShelfVert=150;      Vertikaler Versatz (0..256)
#ShelfWave=4;      Sinuswellenbreite

#ShelfMid=#ShelfSize>>1
#FontSize=20

Macro DoEvent()
  Repeat : WaitWindowEvent() : ForEver
EndMacro

Structure tCoverSizeType
  rx.i
  ry.i
  ox.i
  oy.i
EndStructure


Structure tCoverFlowGadget
  id.i
  canvas.i
  buttonleft.i
  buttonright.i
  MaxCoverImages.i;=30
  ShelfColor.i;=White
  ShelfSize.i;=12;      Anzahl der Covers in einer Zeile (äußerste nicht sichtbar)
  ShelfPhase.i;=5;      Anzahl der Phasen beim Durchblättern
  ShelfSpace.i;=6;      Pixel zwischen Thumbnails
  ShelfMin.i;=128;      Verkleinerung in Relation zum zentralen Cover (256)
  ShelfVert.i;=150;      Vertikaler Versatz (0..256)
  ShelfWave.i;=4;      Sinuswellenbreite
  ShelfMid.i;=ShelfSize>>1
  FontSize.i;=20
  thumbsizeX.i
  thumbsizeY.i
  ShelfX.i
  ShelfY.i
  CacheImage.i
  x.i
  y.i
  w.i
  h.i
  CoverImage.i
  Map CoverImagePool.i()
  Array CoverSize.tCoverSizeType(0,0)
  iCurrentShelf.i
  
EndStructure
Procedure.i CoverFlowGadget_Phaser(min,max,phase)
  
  ProcedureReturn min+(max-min)*phase/(#ShelfPhase+1)
  
EndProcedure 

Procedure CoverFlowGadget_ShelfCalc(id)
  If IsGadget(id)
    Protected *CoverFlowObject .tCoverFlowGadget = GetGadgetData (id)
    If Not *CoverFlowObject
      ProcedureReturn 
    EndIf
  EndIf
  
  With *CoverFlowObject
    
    ; Calculate Cover Sizes and Offsets...
    
    n=0
    p=0
    m=\ShelfSize>>1
    
    For i=0 To \ShelfSize
      z=m-i
      If z<0
        z=-z
      EndIf
      If z>\ShelfWave
        f=\ShelfMin
      Else
        f=256-(256-\ShelfMin)*Sin(#PI*z/\ShelfWave/2)
      EndIf
      \CoverSize(i,0)\rx=21+(\ThumbSizeX*f)>>8
      \CoverSize(i,0)\ry=(\ThumbSizeY*f)>>8
      \CoverSize(i,0)\oy=\ShelfSpace+\ThumbSizeY-(\CoverSize(i,0)\ry*\ShelfVert+\ThumbSizeY*(256-\ShelfVert))>>8
      If i=0
        \CoverSize(i,0)\ox=-(\ThumbSizeX*\ShelfMin)>>8
      Else
        \CoverSize(i,0)\ox=\CoverSize(i-1,0)\ox+\CoverSize(i-1,0)\rx+\ShelfSpace
      EndIf
    Next i
    
    ; Calculate Values for Phases...
    For i=0 To \ShelfSize-1
      rxmin=\CoverSize(i,0)\rx
      rxmax=\CoverSize(i+1,0)\rx
      rymin=\CoverSize(i,0)\ry
      rymax=\CoverSize(i+1,0)\ry
      oxmin=\CoverSize(i,0)\ox
      oxmax=\CoverSize(i+1,0)\ox
      oymin=\CoverSize(i,0)\oy
      oymax=\CoverSize(i+1,0)\oy
      
      For p=1 To \ShelfPhase
        
        \CoverSize(i,p)\rx=CoverFlowGadget_Phaser(rxmin,rxmax,p)
        \CoverSize(i,p)\ry=CoverFlowGadget_Phaser(rymin,rymax,p)
        \CoverSize(i,p)\ox=CoverFlowGadget_Phaser(oxmin,oxmax,p)
        \CoverSize(i,p)\oy=CoverFlowGadget_Phaser(oymin,oymax,p)
      Next p
    Next i
    
    \ShelfX=\w-42;\CoverSize(\ShelfSize,0)\ox
    \ShelfY=\ShelfSpace*4+\ThumbSizeY+\FontSize
    SetGadgetData (id, *CoverFlowObject)
  EndWith  
EndProcedure



Procedure CoverFlowGadget_GetCurrentShelf(id)
  If IsGadget(id)
    Protected *CoverFlowObject .tCoverFlowGadget = GetGadgetData (id)
    If Not *CoverFlowObject
      ProcedureReturn 
    EndIf
  EndIf
  
  ProcedureReturn *CoverFlowObject\iCurrentShelf
  
EndProcedure

Procedure CoverFlowGadget_CreateImages(id, iNum)
  If IsGadget(id)
    Protected *CoverFlowObject .tCoverFlowGadget = GetGadgetData (id)
    If Not *CoverFlowObject
      ProcedureReturn 
    EndIf
  EndIf
  
  With *CoverFlowObject
    
    ; Create Cover Images...
    While NextMapElement(\CoverImagePool())
      If IsImage(\CoverImagePool())
        FreeImage(\CoverImagePool())
      EndIf
    Wend
    ClearMap (\coverimagePool()) 
    For i=0 To iNum
      \CoverImagePool(Str(i))=CreateImage(#PB_Any,\ThumbSizeX,\ThumbSizeY)
      StartDrawing(ImageOutput(\CoverImagePool(Str(i))))
      Box(0,0,\ThumbSizeX,\ThumbSizeY,#LovelyBird)
      Circle(Random(\ThumbSizeX),Random(\ThumbSizeY),Random(\ThumbSizeY),Random($FFFFFF))
      DrawingMode(#PB_2DDrawing_Outlined)
      Box(0,0,\ThumbSizeX,\ThumbSizeY,#White-#ShelfColor)
      s.s="#"+Str(i)
      DrawText((\ThumbSizeX-TextWidth(s))>>1,(\ThumbSizeY-TextHeight(s))>>1,s,#LovelyBird)
      StopDrawing()
    Next i  
  EndWith  
  SetGadgetData (id, *CoverFlowObject)
EndProcedure


Procedure CoverFlowGadget_ShelfShow(id,nShow,p=0)
  If IsGadget(id)
    Protected *CoverFlowObject .tCoverFlowGadget = GetGadgetData (id)
    If Not *CoverFlowObject
      ProcedureReturn 
    EndIf
  EndIf
  
  
  With *CoverFlowObject
    
    Protected i,NewID
    Protected mode,n
    Protected s.s
    
    
    
    If nShow<0: nShow=0:EndIf
    If nShow>MapSize(\CoverImagePool())-1: nShow=MapSize(\CoverImagePool())-1:EndIf
    n=nShow
    
    ; Show Covers...
    
    StartDrawing(ImageOutput(\CacheImage))
    Box(0,0,\ShelfX,\ShelfY,\ShelfColor)
    
    ;   DrawingFont(ShelfFont)
    i=n
    If p>\ShelfPhase>>1
      i-1
    EndIf
    s="Image #"+Str(i)
    i=TextWidth(s)
    DrawText((\ShelfX-i)>>1,\ShelfSpace<<1+\ThumbSizeY,s,$c0c0c0,\ShelfColor)
    
    If p
      mode=#PB_Image_Raw
    Else
      mode=#PB_Image_Smooth
    EndIf
    
    n-\ShelfMid
    For i=0 To \ShelfSize-1
      If n+i>=0 And n+i<=MapSize(\CoverImagePool())-1
        CopyImage(\CoverImagePool(Str(n+i)),#CoverImageTemp)
        newID=ResizeImage(#CoverImageTemp,\CoverSize(i,p)\rx,\CoverSize(i,p)\ry,mode)
        DrawImage(NewID,\CoverSize(i,p)\ox,\CoverSize(i,p)\oy)
      EndIf
    Next i
    
    StopDrawing()
    ;   SetGadgetState(\CoverImage,\CacheImage)
    
    StartDrawing(CanvasOutput(\canvas))
    DrawImage(ImageID(\CacheImage),0,0)
    StopDrawing()
    FreeImage(#CoverImageTemp)
    \iCurrentShelf=nShow
    SetGadgetData(id,*CoverFlowObject)
  EndWith
  
EndProcedure

Procedure CoverFlowGadget_ButtonClick(*ev.EM_Events)
  Protected id=GetGadgetData(*ev\eventgadget)
  If IsGadget(id)
    Protected *CoverFlowObject .tCoverFlowGadget = GetGadgetData (id)
    If Not *CoverFlowObject
      ProcedureReturn 
    EndIf
  EndIf
  
  With  *CoverFlowObject
    Protected iCurrentShelf=\iCurrentShelf
    
    If GetGadgetText(*ev\eventgadget)="<"
      iCurrentShelf-1
    Else
      iCurrentShelf+1
    EndIf
  EndWith
  
  For pp=1 To *CoverFlowObject\ShelfPhase
    CoverFlowGadget_ShelfShow(id,iCurrentShelf,pp)
    ;WaitWindowEvent(1)
  Next pp
  
  CoverFlowGadget_ShelfShow(id,iCurrentShelf)  
EndProcedure

Procedure CoverFlowGadget(id.i, x.i, y.i, width.i, height.i, ThumbnailX=120, ThumbnailY=120)
  Protected *GadgetObject.tCoverFlowGadget = AllocateMemory ( SizeOf ( tCoverFlowGadget) )
  
  If id = #PB_Any
    id = ContainerGadget(#PB_Any, x, y, width, height)
  Else
    ContainerGadget(id, x, y, width, height)
  EndIf
  
  
  
  
  With *GadgetObject
    \thumbsizeX=ThumbnailX
    \thumbsizeY=ThumbnailY
    
    \id=id
    \canvas=CanvasGadget(#PB_Any,21,0,width-42,\thumbsizeY+12)
    \buttonleft=ButtonGadget(#PB_Any,0,0,20,\thumbsizeY+12,"<")
    SetGadgetData(\buttonleft,id)
    \buttonright=ButtonGadget(#PB_Any,width-20,0,20,\thumbsizeY+12,">")
    SetGadgetData(\buttonright,id)
    CloseGadgetList()
    \MaxCoverImages.i=30
    EM_Seteventhandler(\buttonleft,#EM_Gadget,@CoverFlowGadget_ButtonClick())
    EM_Seteventhandler(\buttonright,#EM_Gadget,@CoverFlowGadget_ButtonClick())
    \ShelfColor=$FFFFFF;White
    
    \ShelfSize=(width-42)/\thumbsizeX;      Anzahl der Covers in einer Zeile (äußerste nicht sichtbar)
    \ShelfPhase=20;      Anzahl der Phasen beim Durchblättern
    \ShelfSpace=6;      Pixel zwischen Thumbnails
    \ShelfMin=128;      Verkleinerung in Relation zum zentralen Cover (256)
    \ShelfVert=150;      Vertikaler Versatz (0..256)
    \ShelfWave=4;      Sinuswellenbreite
    \ShelfMid=\ShelfSize>>1
    \FontSize=20
    \x=x
    \y=y
    \w=width
    \h=height
    
    NewMap \CoverImagePool()
    Dim \CoverSize(\ShelfSize,\ShelfPhase)
    SetGadgetData  (id , *GadgetObject )
  EndWith
  
  CoverFlowGadget_ShelfCalc(id)  
  
  *GadgetObject =GetGadgetData(id)
  With *GadgetObject
    \CacheImage=CreateImage(#PB_Any,\ShelfX,\ShelfY)
  EndWith
  SetGadgetData  (id , *GadgetObject )
  CoverFlowGadget_CreateImages(id,*GadgetObject\ShelfPhase )  
  
  
  
  
  ProcedureReturn id
  
EndProcedure

Procedure IsCoverFlowGadget (id)
  If IsGadget(id)
    Protected *CoverFlowObject .tCoverFlowGadget = GetGadgetData (id)
    If Not *CoverFlowObject
      ProcedureReturn 
    EndIf
  Else
    ProcedureReturn
  EndIf
  ProcedureReturn #True
EndProcedure


CompilerIf #PB_Compiler_IsIncludeFile=0
  
  
  
  Procedure Event_CloseWindow()
    End
    
  EndProcedure
  
  
  Procedure Test()
    ; Open Window...
    OpenWindow(#Cover,0,0,1000,200,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
    ;    AddKeyboardShortcut(#Cover,#PB_Shortcut_Right,#ShelfRight)
    ;    AddKeyboardShortcut(#Cover,#PB_Shortcut_Left,#ShelfLeft)
    ;    AddKeyboardShortcut(#Cover,#PB_Shortcut_Escape,#ShelfQuit)
    EM_SetEventHandler(#PB_Event_CloseWindow, #EM_Special, @Event_CloseWindow())
    
    id=CoverFlowGadget(#PB_Any,0,0,1000,200,120,180)
    
    CoverFlowGadget_ShelfShow(id,6)
    doevent()
  EndProcedure
  
  
  Test()
CompilerEndIf
Zuletzt geändert von Oliver13 am 27.03.2013 20:01, insgesamt 2-mal geändert.
Benutzeravatar
Kiffi
Beiträge: 10715
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Cover Flow Gadget

Beitrag von Kiffi »

doevent() fehlt in Deinem Code.

Grüße ... Kiffi
a²+b²=mc²
Oliver13
Beiträge: 35
Registriert: 08.05.2010 15:49

Re: Cover Flow Gadget

Beitrag von Oliver13 »

Kiffi hat geschrieben:doevent() fehlt in Deinem Code.

Grüße ... Kiffi
Danke, ist nun drin
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Cover Flow Gadget

Beitrag von NicTheQuick »

Unter Linux musste ich noch die Konstante "#White = $ffffff" deklarieren und "doevents()" hab ich mal einfach mit "Repeat : WaitWindowEvent() : ForEver" ersetzt.

Trotzdem macht es glaube ich nicht ganz das, was du wolltest. Oder unter Linux läuft da was anders. Jedenfalls bewegt sich alles immer ganz kurz nach rechts, wen man einen der Buttons klickt. Ich mache gleich mal ein Video davon.

Edit:
Hier: CoverFlowGadget.ogv
Benutzeravatar
Kiffi
Beiträge: 10715
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Cover Flow Gadget

Beitrag von Kiffi »

@Oliver13: Meines Erachtens hast Du den Code von Michael verschlimmbessert.
Sein Code ist wesentlich 'smoothiger' und seine Cover reichen auch bis an beide
Ränder (siehe NTQs Video).

Grüße ... Kiffi
a²+b²=mc²
Oliver13
Beiträge: 35
Registriert: 08.05.2010 15:49

Re: Cover Flow Gadget

Beitrag von Oliver13 »

Kiffi hat geschrieben:@Oliver13: Meines Erachtens hast Du den Code von Michael verschlimmbessert.
Sein Code ist wesentlich 'smoothiger' und seine Cover reichen auch bis an beide
Ränder (siehe NTQs Video).

Grüße ... Kiffi
Klar, darauf habe ich ja eingangs auch hingewiesen.. :-)
Das ist erstmal ne quick&dirty Lösung für ein Usergadget, da kann man sicherlich noch vieles draus machen.

@Nic: Grundsätzlich scheint es von der Funktionalität schon richtig. Sieht aber natürlich noch nicht so schön aus wie im Original...
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Cover Flow Gadget

Beitrag von NicTheQuick »

Der Original-Code geht bei mir nicht. Schon schlimm genug, dass er #WM_CLOSE nutzt anstatt das PB-Pendant...
Antworten