module Manatee.Extension.PdfViewer.PdfView where
import Control.Applicative
import Control.Arrow
import Control.Concurrent.STM
import Control.Monad.State
import Data.Map (Map)
import Data.Text.Lazy (Text)
import Data.Typeable
import Graphics.Rendering.Cairo
import Graphics.UI.Gtk hiding (Statusbar, statusbarNew, get)
import Graphics.UI.Gtk.Gdk.SerializedEvent
import Graphics.UI.Gtk.Poppler.Document
import Graphics.UI.Gtk.Poppler.Page
import Manatee.Core.PageView
import Manatee.Core.Types
import Manatee.Extension.PdfViewer.PdfBuffer
import Manatee.Toolkit.General.Basic
import Manatee.Toolkit.General.STM
import Manatee.Toolkit.Gtk.Event
import Manatee.Toolkit.Gtk.Gtk
import Manatee.Toolkit.Gtk.ScrolledWindow
import qualified Data.Map as M
data PdfView =
PdfView {pdfViewPlugId :: TVar PagePlugId
,pdfViewScrolledWindow :: ScrolledWindow
,pdfViewView :: DrawingArea
,pdfViewBuffer :: PdfBuffer
,pdfViewPageIndex :: TVar Int
,pdfViewScale :: TVar Double
}
deriving Typeable
instance PageBuffer PdfBuffer where
pageBufferGetName = readTVarIO . pdfBufferPath
pageBufferSetName a = writeTVarIO (pdfBufferPath a)
pageBufferClient = pdfBufferClient
pageBufferCreateView a pId = PageViewWrap <$> pdfViewNew a pId
pageBufferMode = pdfBufferMode
instance PageView PdfView where
pageViewBuffer = PageBufferWrap . pdfViewBuffer
pageViewPlugId = pdfViewPlugId
pageViewFocus = widgetGrabFocus . pdfViewView
pageViewScrolledWindow = pdfViewScrolledWindow
pageViewHandleKeyAction = pdfViewHandleKeyAction
pdfViewNew :: PdfBuffer -> PagePlugId -> IO PdfView
pdfViewNew buffer plugId = do
pId <- newTVarIO plugId
scrolledWindow <- scrolledWindowNew_
view <- drawingAreaNew
scrolledWindowAddWithViewport scrolledWindow view
pageIndex <- newTVarIO 0
scale <- newTVarIO 0
let viewer = PdfView pId scrolledWindow view buffer pageIndex scale
view `on` exposeEvent $ tryEvent $ pdfViewDraw viewer
return viewer
pdfViewDraw :: PdfView -> EventM EExpose ()
pdfViewDraw view@(PdfView {pdfViewBuffer = buffer
,pdfViewScale = viewScale
,pdfViewPageIndex = pageIndex
}) = do
(winWidth, _) <- eventWindowSize
liftIO $ do
let (pageWidth, pageHeight) = pdfBufferPageSize buffer
doc = pdfBufferDocument buffer
area = pdfViewView view
readTVarIO viewScale
>>= \ value ->
when (value == 0) $ do
let scaleValue = (winWidth / pageWidth)
writeTVarIO viewScale scaleValue
widgetSetSizeRequest
area
(truncate winWidth)
(truncate (scaleValue * pageHeight * integralToDouble (pdfBufferNPages buffer)))
(indexRange, currentIndex) <- pdfViewGetIndexRange view
scaleValue <- readTVarIO viewScale
writeTVarIO pageIndex currentIndex
pageViewUpdateInfoStatus
view
"Page"
("Page (" ++ show (currentIndex + 1) ++ "/" ++ show (pdfBufferNPages buffer) ++ ")")
forM_ indexRange $ \ index -> do
page <- documentGetPage doc index
drawWindow <- widgetGetDrawWindow area
renderWithDrawable drawWindow $ do
setSourceRGB 1.0 1.0 1.0
translate 0 (scaleValue * pageHeight * integralToDouble index)
scale scaleValue scaleValue
pageRender page
pdfViewHandleKeyAction :: PdfView -> Text -> SerializedEvent -> IO ()
pdfViewHandleKeyAction view keystoke sEvent =
case M.lookup keystoke pdfViewKeymap of
Just action -> action view
Nothing -> widgetPropagateEvent (pdfViewView view) sEvent
pdfViewUpdateAdjustment :: PdfView -> (Double, Double) -> IO ()
pdfViewUpdateAdjustment view (width, height) = do
let sWin = pdfViewScrolledWindow view
hAdj <- scrolledWindowGetHAdjustment sWin
vAdj <- scrolledWindowGetVAdjustment sWin
adjustmentSetUpper hAdj width
adjustmentSetUpper vAdj height
pdfViewKeymap :: Map Text (PdfView -> IO ())
pdfViewKeymap =
M.fromList [("j", pageViewScrollVerticalStep True)
,("k", pageViewScrollVerticalStep False)
,("Down", pageViewScrollVerticalStep True)
,("Up", pageViewScrollVerticalStep False)
,(" ", pageViewScrollVerticalPage True)
,("b", pageViewScrollVerticalPage False)
,("J", pageViewScrollToBottom)
,("K", pageViewScrollToTop)
,("n", pdfViewNextPage)
,("p", pdfViewPrevPage)
,("N", pdfViewLastPage)
,("P", pdfViewFirstPage)
]
pdfViewGetIndexRange :: PdfView -> IO ([Int], Int)
pdfViewGetIndexRange PdfView {pdfViewBuffer = buffer
,pdfViewScale = scale
,pdfViewScrolledWindow = scrolledWindow} = do
vAdj <- scrolledWindowGetVAdjustment scrolledWindow
vAdjTop <- adjustmentGetValue vAdj
vAdjSize <- adjustmentGetPageSize vAdj
scaleValue <- readTVarIO scale
let vAdjBottom = vAdjTop + vAdjSize
(_, height) = ((*) scaleValue *** (*) scaleValue) $ pdfBufferPageSize buffer
nPages = pdfBufferNPages buffer
topIndex = truncate $ vAdjTop / height
bottonIndex = truncate $ vAdjBottom / height
startIndex = (\x -> if x < 0 then 0 else x) topIndex
endIndex = (\x -> if x >= nPages then nPages 1 else x)
$ if vAdjBottom integralToDouble bottonIndex * height == 0.0
then bottonIndex 1
else bottonIndex
currIndex = truncate $ (vAdjTop + vAdjSize / 2) / height
return ([startIndex..endIndex], currIndex)
pdfViewNextPage :: PdfView -> IO ()
pdfViewNextPage PdfView {pdfViewBuffer = buffer
,pdfViewPageIndex = pageIndex
,pdfViewScale = viewScale
,pdfViewScrolledWindow = scrolledWindow} = do
currentIndex <- readTVarIO pageIndex
scaleValue <- readTVarIO viewScale
let (_, height) = pdfBufferPageSize buffer
maxIndex = pdfBufferNPages buffer 1
nextIndex
| currentIndex >= maxIndex
= maxIndex
| otherwise
= currentIndex + 1
vAdj <- scrolledWindowGetVAdjustment scrolledWindow
adjustmentSetValue vAdj (integralToDouble nextIndex * height * scaleValue)
pdfViewPrevPage :: PdfView -> IO ()
pdfViewPrevPage PdfView {pdfViewBuffer = buffer
,pdfViewPageIndex = pageIndex
,pdfViewScale = viewScale
,pdfViewScrolledWindow = scrolledWindow} = do
currentIndex <- readTVarIO pageIndex
scaleValue <- readTVarIO viewScale
let (_, height) = pdfBufferPageSize buffer
prevIndex
| currentIndex <= 0
= 0
| otherwise
= currentIndex 1
vAdj <- scrolledWindowGetVAdjustment scrolledWindow
adjustmentSetValue vAdj (integralToDouble prevIndex * height * scaleValue)
pdfViewFirstPage :: PdfView -> IO ()
pdfViewFirstPage = pageViewScrollToTop
pdfViewLastPage :: PdfView -> IO ()
pdfViewLastPage PdfView {pdfViewBuffer = buffer
,pdfViewScale = viewScale
,pdfViewScrolledWindow = scrolledWindow} = do
let (_, height) = pdfBufferPageSize buffer
maxIndex = pdfBufferNPages buffer 1
scaleValue <- readTVarIO viewScale
vAdj <- scrolledWindowGetVAdjustment scrolledWindow
adjustmentSetValue vAdj (integralToDouble maxIndex * height * scaleValue)