 | A callback for mouse dragging. Deals with offsetting the 'CameraShift' in
-- 'ProgramState'.
motion :: IORef ProgramState -> MotionCallback
motion ps p@(Position newX newY) = do
  pState <- get ps
  let nowMS = pState ^. mouseState
      (oldMS, oldPos) = pState ^. dragState

  case oldPos of
    Nothing -> ps $$! pState & dragState .~ (nowMS, Just p)
    Just (Position oldX oldY) ->
      if oldMS == nowMS
      then do
        let CameraShift st sp sr = pState ^. cameraShift

            zDifference = fromIntegral (newY - oldY) + sr

            dx = fromIntegral $ newX - oldX
            dy = fromIntegral $ newY - oldY

            newTheta = st + dy * (pi / 800)
            newPhi = sp - dx * (pi / 800)


        let p' = case nowMS of
              MouseState Down _ _ -> pState & cameraShift
                                     .~ CameraShift newTheta newPhi sr
              MouseState _ Down _ -> pState & cameraShift
                                     .~ CameraShift st sp zDifference
              MouseState _ _ _ -> pState


        ps $$! p' &  dragState . _2 .~ Just p

      else ps $$! pState & dragState .~ (nowMS, Just p)

-- | Advances camera focus between pre-defined points on the cube. Effectively a
-- poor-man's zipper.
a
motion :: IORef ProgramState -> MotionCallback
motion ps p@(Position newX newY) = do
  pState <- get ps
  let nowMS = pState ^. mouseState
      (oldMS, oldPos) = pState ^. dragState

  case oldPos of
    Nothing -> ps $$! pState & dragState .~ (nowMS, Just p)
    Just (Position oldX oldY) ->
      if oldMS == nowMS
      then do
        let CameraShift st sp sr = pState ^. cameraShift

            zDifference = fromIntegral (newY - oldY) + sr

            dx = fromIntegral $ newX - oldX
            dy = fromIntegral $ newY - oldY

            newTheta = st + dy * (pi / 800)
            newPhi = sp - dx * (pi / 800)


        let p' = case nowMS of
              MouseState Down _ _ -> pState & cameraShift
                                     .~ CameraShift newTheta newPhi sr
              MouseState _ Down _ -> pState & cameraShift
                                     .~ CameraShift st sp zDifference
              MouseState _ _ _ -> pState


        ps $$! p' &  dragState . _2 .~ Just p

      else ps $$! pState & dragState .~ (nowMS, Just p)

-- | Advances camera focus between pre-defined points on the cube. Effectively a
-- poor-man's zipper.
motion ps p@(Position newX newY) = do
  pState <- get ps
  let nowMS = pState ^. mouseState
      (oldMS, oldPos) = pState ^. dragState

  case oldPos of
    Nothing -> ps $$! pState & dragState .~ (nowMS, Just p)
    Just (Position oldX oldY) ->
      if oldMS == nowMS
      then do
        let CameraShift st sp sr = pState ^. cameraShift

            zDifference = fromIntegral (newY - oldY) + sr

            dx = fromIntegral $ newX - oldX
            dy = fromIntegral $ newY - oldY

            newTheta = st + dy * (pi / 800)
            newPhi = sp - dx * (pi / 800)


        let p' = case nowMS of
              MouseState Down _ _ -> pState & cameraShift
                                     .~ CameraShift newTheta newPhi sr
              MouseState _ Down _ -> pState & cameraShift
                                     .~ CameraShift st sp zDifference
              MouseState _ _ _ -> pState


        ps $$! p' &  dragState . _2 .~ Just p

      else ps $$! pState & dragState .~ (nowMS, Just p)

-- | Advances camera focus between pre-defined points on the cube. Effectively a
-- poor-man's zipper.