Super Slider Pro

Whilst the original slider works fine to display a strip of thumbnail images derived from cast members, it has some limitations that become apparent if you want to start interacting with the thumbnails (changing them or animating them), or using dynamically loaded images from external files.

The major difference with this next version of the Slider script is that the 'LoadImages' method now expects a list of images, not cast members. It also has methods for appending images to the slider, as well as updating existing images. These last two methods will be useful if you want to load images as they become available (such as once they have been preloaded).

You may also notice that the Slide method doesn't modify the map list-rather, it modifies a list of indexes (the property 'mySlideMap'). This means that the order that images are added to the slider doesn't change (which is useful if you want to add 'DeleteAt' or "AddAt' methods to the script).

property myCanvas            -- the image object to draw into 

property myDestRect          -- the rect on the canvas to draw to 

property myBuffer            -- image used to composite the tiles

property myHeight, myWidth   -- size of this image

property myMapH              -- how much the view has been moved

property myMap               -- list of 'tiles'

property mySlideMap          -- a list of indexes to the map

property mySettings          -- settings (colour, etc)

property myPixel             -- utility image





on Initialise (me, aCanvas, aRectOnCanvas, settings)

  

  myCanvas = aCanvas

  myDestRect = aRectOnCanvas

  

  me._LoadSettings(settings)

  

  myWidth = myDestRect.width

  myHeight = myDestRect.height

  myBuffer = image(myWidth, myHeight, 24)

  myBuffer.fill(myBuffer.rect, rgb(0,0,0))

  myMapH= 0

  myMap = []

  mySlideMap = []

  

  -- create a pixel image (used for hilighting etc)

  myPixel = image(1,1,1)

  myPixel.setPixel(0,0,1)

  

end 



on LoadImages (me, aListOfImages)

  -- clears the currrent list of images, and loads a new set

  myMap = []

  myTileRects = []

  return me.AppendImages(aListOfImages)

  

end



on AppendImages (me, aListOfImages)

  -- append images to the map

  if aListOfImages.ilk <> #PropList then return #ParameterError

  

  mx = aListOfImages.count

  repeat with i = 1 to mx

    id = aListOfImages.getPropAt(i)

    img = aListOfImages[i]

    tile = me._CreateTile(img, id)

    -- add it to the map

    myMap.append(tile)

    mySlideMap.append(myMap.count)

  end repeat

end







on SetImageAt (me, img, id, pos)

  if (pos < 1 or pos > myMap.count) then return #IndexOutOfRange

  -- inserts an image at the specified position

  tile = me._CreateTile(img, id)

  -- add it to the map

  myMap.SetAt(pos, tile)

end



on UpdateImage (me, img, id)

  repeat with i = 1 to myMap.Count

    if myMap[i][#id] = id then 

      tile = me._CreateTile(img, id)

      myMap[i][#image] = tile.image

      myMap[i][#DRect] = tile.DRect

    end if

  end repeat  

end





on GetTile (me, whichTileId)

  -- returns the tile position under the point

  if whichTileId.ilk = #Integer then return myMap[whichTileId]

  repeat with i = 1 to myMap.Count

    if myMap[i][#id] = whichTileId then return myMap[i]

  end repeat  

end



on GetTileIDAtPoint (me, pntOnCanvas)

  -- returns the tile id under the point

  rectLeft = -myMapH

  repeat with i = 1 to mySlideMap.Count

    aTileIdx = mySlideMap[i]

    aRect = myMap[aTileIdx][#DRect].offset(rectLeft, 0)

    if inside(pntOnCanvas, aRect) then 

      thisTile = myMap[aTileIdx][#id]

      return thisTile

    end if

    rectLeft = rectLeft + aRect.width

    if rectLeft > myWidth then exit repeat

  end repeat  

  

end







on SelectTileByID (me, whichTileId, multiSelect)

  

  repeat with i = 1 to myMap.count

    if myMap[i][#id] = whichTileId then myMap[i][#Selected] = 1

    else if NOT(multiSelect) then myMap[i][#Selected] = 0

  end repeat

  

end



on SelectTileByPos (me, whichpos, multiSelect)

  

  repeat with i = 1 to myMap.count

    if i = whichpos then myMap[i][#Selected] = 1

    else if NOT(multiSelect) then myMap[i][#Selected] = 0

  end repeat

  

end





on Slide (me, shiftAmt)

  -- Shifts the display left or right by the specified amount. 

  -- Specify a positive amount to slide downwards

  if myMap.count < 1 then exit -- no images

  

  myMapH = myMapH + shiftAmt

  if shiftAmt > 0 then 

    -- check whether we have moved past the left most tile

    -- if so, move it from the start of the list and

    -- add it to the end

    aTileIdx = mySlideMap[1]

    aTile = myMap[aTileIdx]

    r = aTile.DRect

    w = r.width

    if myMapH >= w then 

      mySlideMap.deleteAt(1)

      mySlideMap.append(aTileIdx)

      myMapH = myMapH - w

    end if

  else if shiftAmt < 0 then 

    -- check whether we have moved past the right most tile

    -- if it is, move it from the end to the start of the list

    if myMapH <= 0 then 

      lastPos = myMap.count

      aTileIdx = mySlideMap[lastPos]

      aTile = myMap[aTileIdx]

      mySlideMap.deleteAt(lastPos)

      mySlideMap.addAt(1, aTileIdx)

      myMapH = myMapH + aTile[#DRect].width

    end if

  end if

  

  -- now draw the visible portion of the map onto the buffer image

  rectLeft = -myMapH

  buffer = myBuffer.duplicate()

  repeat with i = 1 to mySlideMap.count

    aTileIdx = mySlideMap[i]

    img = myMap[aTileIdx][#Image]

    destRect = myMap[aTileIdx][#DRect].offset(rectLeft, 0)

    buffer.copyPixels(img, destRect, img.rect)

    if myMap[aTileIdx][#selected] then 

      buffer.copyPixels(myPixel, destRect, myPixel.rect, [#BlendLevel: 100])

    end if

    rectLeft = rectLeft + destRect.width

    if rectLeft > myWidth then exit repeat

  end repeat

  myCanvas.copyPixels(buffer, myDestRect, buffer.rect)

  

end



on _CreateTile (me, img, id)

  if img.height > myHeight then 

    -- need to scale the image down

    originalRect = img.rect

    thescale = float(myHeight)/img.height

    scaledRect = rect(0, 0, integer(img.width*thescale), myHeight)

  else if img.height < myHeight then 

    -- need to centre the rect vertically

    vOff = (myHeight-img.height)/2

    scaledRect = img.rect.offset(0, vOff)

  else

    -- perfect fit!

    scaledRect = img.rect

  end if

  -- create the small version of the image

  tileImg = image(scaledRect.width, myHeight, 24)

  tileImg.fill(tileImg.rect, mySettings.backColour)

  tileImg.copyPixels(img, scaledRect, img.rect)

  if mySettings.BorderSize <> 0 then 

    tileImg.draw(tileImg.rect, [#ShapeType: #Rect, \

#LineSize:mySettings.BorderSize, #Color: mySettings.borderColour])

  end if

  -- store all the information we have about this tile

  tile = [#Image: tileImg, #DRect: tileImg.rect, #id: id, #Selected: 0]

  return tile

end



on _LoadSettings (me, settings)

  

  -- firstly, set the defaults

  mySettings = [:]

  mySettings[#backColour] = rgb("#f1f1f1")

  mySettings[#borderColour] = rgb("#000000")

  mySettings[#BorderSize] = 1

  

  -- now, over-ride them 

  if settings.ilk = #PropList then 

    mx = settings.count

    repeat with i = 1 to mx

      thisProp = settings.getPropAt(i)

      thisValue = settings.getAt(i)

      mySettings.setAProp(thisProp, thisValue)

    end repeat

  end if

  

end
First published 21/06/2005