nextState :: Event -> State -> Maybe State
nextState event state = case event of
  MouseMotion x y _ _ | middleButton state -> Just state
    { phi   = phi' state   + 0.01 * fromIntegral (fromIntegral y - y' state)
    , theta = theta' state + 0.01 * fromIntegral (fromIntegral x - x' state)
    }
  MouseMotion x _ _ _ | leftButton  state -> Just state { i = i' state + 0.01 * fromIntegral (fromIntegral x - x' state) }
  MouseMotion x _ _ _ | rightButton state -> Just state { j = j' state + 0.01 * fromIntegral (fromIntegral x - x' state) }

  MouseButtonDown x y ButtonMiddle -> Just state
    { leftButton   = False
    , middleButton = True
    , rightButton  = False
    , x' = fromIntegral x
    , y' = fromIntegral y
    , phi' = phi state
    , theta' = theta state
    }

  MouseButtonDown x y ButtonLeft -> Just state
    { leftButton   = True
    , middleButton = False
    , rightButton  = False
    , x' = fromIntegral x
    , y' = fromIntegral y
    , i' = i state
    , j' = j state
    }

  MouseButtonDown x y ButtonRight -> Just state
    { leftButton   = False
    , middleButton = False
    , rightButton  = True
    , x' = fromIntegral x
    , y' = fromIntegral y
    , i' = i state
    , j' = j state
    }

  MouseButtonUp _ _ ButtonLeft   -> Just state { leftButton   = False }
  MouseButtonUp _ _ ButtonMiddle -> Just state { middleButton = False }
  MouseButtonUp _ _ ButtonRight  -> Just state { rightButton  = False }
  MouseButtonDown _ _ ButtonWheelUp   -> Just state { scale' = scale' state * 1.2 }
  MouseButtonDown _ _ ButtonWheelDown -> Just state { scale' = scale' state / 1.2 }
  _ -> Nothing
nextState :: Event -> State -> Maybe State
nextState event state = case event of
  MouseMotion x y _ _ | middleButton state -> Just state
    { phi   = phi' state   + 0.01 * fromIntegral (fromIntegral y - y' state)
    , theta = theta' state + 0.01 * fromIntegral (fromIntegral x - x' state)
    }
  MouseMotion x _ _ _ | leftButton  state -> Just state { i = i' state + 0.01 * fromIntegral (fromIntegral x - x' state) }
  MouseMotion x _ _ _ | rightButton state -> Just state { j = j' state + 0.01 * fromIntegral (fromIntegral x - x' state) }

  MouseButtonDown x y ButtonMiddle -> Just state
    { leftButton   = False
    , middleButton = True
    , rightButton  = False
    , x' = fromIntegral x
    , y' = fromIntegral y
    , phi' = phi state
    , theta' = theta state
    }

  MouseButtonDown x y ButtonLeft -> Just state
    { leftButton   = True
    , middleButton = False
    , rightButton  = False
    , x' = fromIntegral x
    , y' = fromIntegral y
    , i' = i state
    , j' = j state
    }

  MouseButtonDown x y ButtonRight -> Just state
    { leftButton   = False
    , middleButton = False
    , rightButton  = True
    , x' = fromIntegral x
    , y' = fromIntegral y
    , i' = i state
    , j' = j state
    }

  MouseButtonUp _ _ ButtonLeft   -> Just state { leftButton   = False }
  MouseButtonUp _ _ ButtonMiddle -> Just state { middleButton = False }
  MouseButtonUp _ _ ButtonRight  -> Just state { rightButton  = False }
  MouseButtonDown _ _ ButtonWheelUp   -> Just state { scale' = scale' state * 1.2 }
  MouseButtonDown _ _ ButtonWheelDown -> Just state { scale' = scale' state / 1.2 }
  _ -> Nothing
nextState event state = case event of
  MouseMotion x y _ _ | middleButton state -> Just state
    { phi   = phi' state   + 0.01 * fromIntegral (fromIntegral y - y' state)
    , theta = theta' state + 0.01 * fromIntegral (fromIntegral x - x' state)
    }
  MouseMotion x _ _ _ | leftButton  state -> Just state { i = i' state + 0.01 * fromIntegral (fromIntegral x - x' state) }
  MouseMotion x _ _ _ | rightButton state -> Just state { j = j' state + 0.01 * fromIntegral (fromIntegral x - x' state) }

  MouseButtonDown x y ButtonMiddle -> Just state
    { leftButton   = False
    , middleButton = True
    , rightButton  = False
    , x' = fromIntegral x
    , y' = fromIntegral y
    , phi' = phi state
    , theta' = theta state
    }

  MouseButtonDown x y ButtonLeft -> Just state
    { leftButton   = True
    , middleButton = False
    , rightButton  = False
    , x' = fromIntegral x
    , y' = fromIntegral y
    , i' = i state
    , j' = j state
    }

  MouseButtonDown x y ButtonRight -> Just state
    { leftButton   = False
    , middleButton = False
    , rightButton  = True
    , x' = fromIntegral x
    , y' = fromIntegral y
    , i' = i state
    , j' = j state
    }

  MouseButtonUp _ _ ButtonLeft   -> Just state { leftButton   = False }
  MouseButtonUp _ _ ButtonMiddle -> Just state { middleButton = False }
  MouseButtonUp _ _ ButtonRight  -> Just state { rightButton  = False }
  MouseButtonDown _ _ ButtonWheelUp   -> Just state { scale' = scale' state * 1.2 }
  MouseButtonDown _ _ ButtonWheelDown -> Just state { scale' = scale' state / 1.2 }
  _ -> Nothing