Powerpoint writer: Position images correctly in two-column layout.

You can have two images side-by-side, or text alongside an image. The
image will be fit correctly within the column.
This commit is contained in:
Jesse Rosenthal 2018-01-14 01:37:51 -05:00
parent 1577289672
commit 64c4451ef3

View file

@ -42,7 +42,6 @@ import Data.Time.Clock (UTCTime)
import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime) import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime)
import System.FilePath.Posix (splitDirectories, splitExtension, takeExtension) import System.FilePath.Posix (splitDirectories, splitExtension, takeExtension)
import Text.XML.Light import Text.XML.Light
import qualified Text.XML.Light.Cursor as XMLC
import Text.Pandoc.Definition import Text.Pandoc.Definition
import qualified Text.Pandoc.UTF8 as UTF8 import qualified Text.Pandoc.UTF8 as UTF8
import Text.Pandoc.Class (PandocMonad) import Text.Pandoc.Class (PandocMonad)
@ -126,7 +125,7 @@ data WriterEnv = WriterEnv { envMetadata :: Meta
-- the end of the slide file name and -- the end of the slide file name and
-- the rId number -- the rId number
, envSlideIdOffset :: Int , envSlideIdOffset :: Int
, envColumnNumber :: Maybe Int , envContentType :: ContentType
} }
deriving (Show) deriving (Show)
@ -145,9 +144,14 @@ instance Default WriterEnv where
, envInNoteSlide = False , envInNoteSlide = False
, envCurSlideId = 1 , envCurSlideId = 1
, envSlideIdOffset = 1 , envSlideIdOffset = 1
, envColumnNumber = Nothing , envContentType = NormalContent
} }
data ContentType = NormalContent
| TwoColumnLeftContent
| TwoColumnRightContent
deriving (Show, Eq)
data MediaInfo = MediaInfo { mInfoFilePath :: FilePath data MediaInfo = MediaInfo { mInfoFilePath :: FilePath
, mInfoLocalId :: Int , mInfoLocalId :: Int
, mInfoGlobalId :: Int , mInfoGlobalId :: Int
@ -912,15 +916,20 @@ shapeHasId ns ident element
-- column is id=4. -- column is id=4.
getContentShape :: PandocMonad m => NameSpaces -> Element -> P m Element getContentShape :: PandocMonad m => NameSpaces -> Element -> P m Element
getContentShape ns spTreeElem getContentShape ns spTreeElem
| isElem ns "p" "spTree" spTreeElem = | isElem ns "p" "spTree" spTreeElem = do
case filterChild contentType <- asks envContentType
(\e -> (isElem ns "p" "sp" e) && (shapeHasId ns "3" e)) let ident = case contentType of
spTreeElem NormalContent -> "3"
of TwoColumnLeftContent -> "3"
Just e -> return e TwoColumnRightContent -> "4"
Nothing -> throwError $ case filterChild
PandocSomeError $ (\e -> (isElem ns "p" "sp" e) && (shapeHasId ns ident e))
"Could not find shape for Powerpoint content" spTreeElem
of
Just e -> return e
Nothing -> throwError $
PandocSomeError $
"Could not find shape for Powerpoint content"
getContentShape _ _ = throwError $ getContentShape _ _ = throwError $
PandocSomeError $ PandocSomeError $
"Attempted to find content on non shapeTree" "Attempted to find content on non shapeTree"
@ -1552,40 +1561,15 @@ contentToElement layout hdrShape shapes
let hdrShapeElements = if null hdrShape let hdrShapeElements = if null hdrShape
then [] then []
else [element] else [element]
contentElements <- shapesToElements layout shapes contentElements <- local
(\env -> env {envContentType = NormalContent})
(shapesToElements layout shapes)
return $ return $
replaceNamedChildren ns "p" "sp" replaceNamedChildren ns "p" "sp"
(hdrShapeElements ++ contentElements) (hdrShapeElements ++ contentElements)
spTree spTree
contentToElement _ _ _ = return $ mknode "p:sp" [] () contentToElement _ _ _ = return $ mknode "p:sp" [] ()
setIdx'' :: NameSpaces -> String -> Content -> Content
setIdx'' _ idx (Elem element) =
let tag = XMLC.getTag element
attrs = XMLC.tagAttribs tag
idxKey = (QName "idx" Nothing Nothing)
attrs' = Attr idxKey idx : (filter (\a -> attrKey a /= idxKey) attrs)
tag' = tag {XMLC.tagAttribs = attrs'}
in Elem $ XMLC.setTag tag' element
setIdx'' _ _ c = c
setIdx' :: NameSpaces -> String -> XMLC.Cursor -> XMLC.Cursor
setIdx' ns idx cur =
let modifiedCur = XMLC.modifyContent (setIdx'' ns idx) cur
in
case XMLC.nextDF modifiedCur of
Just cur' -> setIdx' ns idx cur'
Nothing -> XMLC.root modifiedCur
setIdx :: NameSpaces -> String -> Element -> Element
setIdx ns idx element =
let cur = XMLC.fromContent (Elem element)
cur' = setIdx' ns idx cur
in
case XMLC.toTree cur' of
Elem element' -> element'
_ -> element
twoColumnToElement :: PandocMonad m => Element -> [ParaElem] -> [Shape] -> [Shape] -> P m Element twoColumnToElement :: PandocMonad m => Element -> [ParaElem] -> [Shape] -> [Shape] -> P m Element
twoColumnToElement layout hdrShape shapesL shapesR twoColumnToElement layout hdrShape shapesL shapesR
| ns <- elemToNameSpaces layout | ns <- elemToNameSpaces layout
@ -1595,13 +1579,17 @@ twoColumnToElement layout hdrShape shapesL shapesR
let hdrShapeElements = if null hdrShape let hdrShapeElements = if null hdrShape
then [] then []
else [element] else [element]
contentElementsL <- shapesToElements layout shapesL contentElementsL <- local
contentElementsR <- shapesToElements layout shapesR (\env -> env {envContentType =TwoColumnLeftContent})
let contentElementsL' = map (setIdx ns "1") contentElementsL (shapesToElements layout shapesL)
contentElementsR' = map (setIdx ns "2") contentElementsR contentElementsR <- local
(\env -> env {envContentType =TwoColumnRightContent})
(shapesToElements layout shapesR)
-- let contentElementsL' = map (setIdx ns "1") contentElementsL
-- contentElementsR' = map (setIdx ns "2") contentElementsR
return $ return $
replaceNamedChildren ns "p" "sp" replaceNamedChildren ns "p" "sp"
(hdrShapeElements ++ contentElementsL' ++ contentElementsR') (hdrShapeElements ++ contentElementsL ++ contentElementsR)
spTree spTree
twoColumnToElement _ _ _ _= return $ mknode "p:sp" [] () twoColumnToElement _ _ _ _= return $ mknode "p:sp" [] ()