{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ViewPatterns #-}

module DearImGui.Raw.DragDrop
  ( -- * Source
    beginSource
  , setPayload
  , endSource
    -- * Target
  , beginTarget
  , acceptPayload
  , endTarget
    -- * Payload object
  , Payload(..)
  , getData
  , getDataSize
    -- ** Direct access
  , getPayload
  , clear
  , isDataType
  , isPreview
  , isDelivery
  )
  where

-- base
import Control.Monad.IO.Class
  ( MonadIO, liftIO )
import Foreign
  ( Ptr, castPtr, nullPtr )
import Foreign.C

-- dear-imgui
import DearImGui.Raw.Context
  ( imguiContext )
import DearImGui.Enums
import DearImGui.Structs

-- inline-c
import qualified Language.C.Inline as C

-- inline-c-cpp
import qualified Language.C.Inline.Cpp as Cpp

C.context (Cpp.cppCtx <> C.bsCtx <> imguiContext)
C.include "imgui.h"
Cpp.using "namespace ImGui"

-- | Call after submitting an item which may be dragged.
--
-- When this return True, you can call 'setPayload' + 'endDragDropSource'.
beginSource :: MonadIO m => ImGuiDragDropFlags -> m Bool
beginSource :: forall (m :: * -> *). MonadIO m => ImGuiDragDropFlags -> m Bool
beginSource ImGuiDragDropFlags
flags = IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { BeginDragDropSource( $(ImGuiDragDropFlags flags) ) } |]

-- | Type is a user defined string of maximum 32 characters.
--
-- Strings starting with '_' are reserved for dear imgui internal types.
-- Data is copied and held by imgui.
-- Returns True when payload has been accepted.
setPayload :: MonadIO m => CString -> Ptr a -> CSize -> ImGuiCond -> m Bool
setPayload :: forall (m :: * -> *) a.
MonadIO m =>
CString -> Ptr a -> CSize -> ImGuiCond -> m Bool
setPayload CString
typePtr Ptr a
dataPtr CSize
sz ImGuiCond
cond = IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { SetDragDropPayload( $(char* typePtr), $(void* dataPtr'), $(size_t sz), $(ImGuiCond cond) ) } |]
  where
    dataPtr' :: Ptr b
dataPtr' = Ptr a -> Ptr b
forall a b. Ptr a -> Ptr b
castPtr Ptr a
dataPtr

-- | Only call if 'beginSource' returns True!
endSource :: MonadIO m => m ()
endSource :: forall (m :: * -> *). MonadIO m => m ()
endSource = IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  IO ()
[C.block| void { EndDragDropSource( ); } |]

-- | Call after submitting an item that may receive a payload.
--
-- If this returns True, you can call 'acceptPayload' + 'endTarget'.
beginTarget :: MonadIO m => m Bool
beginTarget :: forall (m :: * -> *). MonadIO m => m Bool
beginTarget = IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO CBool
[C.exp| bool { BeginDragDropTarget() } |]

-- | Accept contents of a given type.
--
-- If "ImGuiDragDropFlags_AcceptBeforeDelivery" is set you can peek into the payload before the mouse button is released.
acceptPayload :: MonadIO m => CString -> ImGuiDragDropFlags -> m (Maybe Payload)
acceptPayload :: forall (m :: * -> *).
MonadIO m =>
CString -> ImGuiDragDropFlags -> m (Maybe Payload)
acceptPayload CString
typePtr ImGuiDragDropFlags
flags = IO (Maybe Payload) -> m (Maybe Payload)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  Ptr ImGuiPayload
ptr <- [C.exp| const ImGuiPayload* { AcceptDragDropPayload( $(char* typePtr), $(ImGuiDragDropFlags flags) ) } |]
  if Ptr ImGuiPayload
ptr Ptr ImGuiPayload -> Ptr ImGuiPayload -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr ImGuiPayload
forall {b}. Ptr b
nullPtr then
    Maybe Payload -> IO (Maybe Payload)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Payload
forall a. Maybe a
Nothing
  else
    Maybe Payload -> IO (Maybe Payload)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe Payload -> IO (Maybe Payload))
-> Maybe Payload -> IO (Maybe Payload)
forall a b. (a -> b) -> a -> b
$ Payload -> Maybe Payload
forall a. a -> Maybe a
Just (Ptr ImGuiPayload -> Payload
Payload Ptr ImGuiPayload
ptr)

-- | Only call if 'beginTarget' returns true!
endTarget :: MonadIO m => m ()
endTarget :: forall (m :: * -> *). MonadIO m => m ()
endTarget = IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  IO ()
[C.block| void { EndDragDropTarget(); } |]

-- | Peek directly into the current payload from anywhere.
--
-- Returns NULL when drag and drop is finished or inactive.
-- Use 'isDataType' to test for the payload type.
getPayload :: MonadIO m => m (Maybe Payload)
getPayload :: forall (m :: * -> *). MonadIO m => m (Maybe Payload)
getPayload = IO (Maybe Payload) -> m (Maybe Payload)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  Ptr ImGuiPayload
ptr <- IO (Ptr ImGuiPayload)
[C.exp| const ImGuiPayload* { GetDragDropPayload() } |]
  if Ptr ImGuiPayload
ptr Ptr ImGuiPayload -> Ptr ImGuiPayload -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr ImGuiPayload
forall {b}. Ptr b
nullPtr then
    Maybe Payload -> IO (Maybe Payload)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Payload
forall a. Maybe a
Nothing
  else
    Maybe Payload -> IO (Maybe Payload)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe Payload -> IO (Maybe Payload))
-> Maybe Payload -> IO (Maybe Payload)
forall a b. (a -> b) -> a -> b
$ Payload -> Maybe Payload
forall a. a -> Maybe a
Just (Ptr ImGuiPayload -> Payload
Payload Ptr ImGuiPayload
ptr)

-- | DragDrop payload data handle
--
-- Wraps @ImGuiPayload*@.
newtype Payload = Payload (Ptr ImGuiPayload)
  deriving (Payload -> Payload -> Bool
(Payload -> Payload -> Bool)
-> (Payload -> Payload -> Bool) -> Eq Payload
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Payload -> Payload -> Bool
== :: Payload -> Payload -> Bool
$c/= :: Payload -> Payload -> Bool
/= :: Payload -> Payload -> Bool
Eq, Int -> Payload -> ShowS
[Payload] -> ShowS
Payload -> String
(Int -> Payload -> ShowS)
-> (Payload -> String) -> ([Payload] -> ShowS) -> Show Payload
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Payload -> ShowS
showsPrec :: Int -> Payload -> ShowS
$cshow :: Payload -> String
show :: Payload -> String
$cshowList :: [Payload] -> ShowS
showList :: [Payload] -> ShowS
Show)

getData :: MonadIO m => Payload -> m (Ptr ())
getData :: forall (m :: * -> *). MonadIO m => Payload -> m (Ptr ())
getData (Payload Ptr ImGuiPayload
payloadPtr) = IO (Ptr ()) -> m (Ptr ())
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  [C.exp| void* { $(ImGuiPayload* payloadPtr)->Data } |]

getDataSize :: MonadIO m => Payload -> m CInt
getDataSize :: forall (m :: * -> *). MonadIO m => Payload -> m CInt
getDataSize (Payload Ptr ImGuiPayload
payloadPtr) = IO CInt -> m CInt
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  [C.exp| int { $(ImGuiPayload* payloadPtr)->DataSize } |]

-- | Clear the DearImGui copy of payload data.
--
-- Gets called on 'endTarget' right after delivery.
clear :: MonadIO m => Payload -> m ()
clear :: forall (m :: * -> *). MonadIO m => Payload -> m ()
clear (Payload Ptr ImGuiPayload
payloadPtr) = IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  [C.block| void { $(ImGuiPayload* payloadPtr)->Clear(); } |]

isDataType :: MonadIO m => Payload -> CString -> m Bool
isDataType :: forall (m :: * -> *). MonadIO m => Payload -> CString -> m Bool
isDataType (Payload Ptr ImGuiPayload
payloadPtr) CString
typePtr = IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { $(ImGuiPayload* payloadPtr)->IsDataType($(char* typePtr)) } |]

isPreview :: MonadIO m => Payload -> m Bool
isPreview :: forall (m :: * -> *). MonadIO m => Payload -> m Bool
isPreview (Payload Ptr ImGuiPayload
payloadPtr) = IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { $(ImGuiPayload* payloadPtr)->IsPreview() } |]

isDelivery :: MonadIO m => Payload -> m Bool
isDelivery :: forall (m :: * -> *). MonadIO m => Payload -> m Bool
isDelivery (Payload Ptr ImGuiPayload
payloadPtr) = IO Bool -> m Bool
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO do
  (CBool
0 CBool -> CBool -> Bool
forall a. Eq a => a -> a -> Bool
/=) (CBool -> Bool) -> IO CBool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [C.exp| bool { $(ImGuiPayload* payloadPtr)->IsDelivery() } |]