Skip to content

Commit

Permalink
presentation: support adding textboxes
Browse files Browse the repository at this point in the history
Allow adding a textbox to a slide
  • Loading branch information
tbaliance committed Nov 18, 2017
1 parent f5a8df0 commit 8030eab
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 22 deletions.
31 changes: 29 additions & 2 deletions _examples/presentation/simple/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,40 @@
package main

import (
"log"

"baliance.com/gooxml/color"
"baliance.com/gooxml/measurement"
"baliance.com/gooxml/schema/soo/dml"

"baliance.com/gooxml/presentation"
)

func main() {
ppt := presentation.New()
slide := ppt.AddSlide()
_ = slide
for i := 0; i < 5; i++ {
slide := ppt.AddSlide()

tb := slide.AddTextBox()
tb.Properties().SetGeometry(dml.ST_ShapeTypeStar10)

tb.Properties().SetWidth(3 * measurement.Inch)
pos := measurement.Distance(i) * measurement.Inch
tb.Properties().SetPosition(pos, pos)

tb.Properties().SetSolidFill(color.AliceBlue)
tb.Properties().LineProperties().SetSolidFill(color.Blue)

p := tb.AddParagraph()
p.Properties().SetAlign(dml.ST_TextAlignTypeCtr)

r := p.AddRun()
r.SetText("gooxml")
r.Properties().SetSize(24 * measurement.Point)

}
if err := ppt.Validate(); err != nil {
log.Fatal(err)
}
ppt.SaveToFile("simple.pptx")
}
Binary file modified _examples/presentation/simple/simple.pptx
Binary file not shown.
5 changes: 5 additions & 0 deletions drawing/paragraphproperties.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,8 @@ func (p ParagraphProperties) SetNumbered(scheme dml.ST_TextAutonumberScheme) {
p.x.BuAutoNum.TypeAttr = scheme
}
}

// SetAlign controls the paragraph alignment
func (p ParagraphProperties) SetAlign(a dml.ST_TextAlignType) {
p.x.AlgnAttr = a
}
49 changes: 49 additions & 0 deletions drawing/shapeproperties.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
package drawing

import (
"baliance.com/gooxml"
"baliance.com/gooxml/color"
"baliance.com/gooxml/measurement"

"baliance.com/gooxml/schema/soo/dml"
)
Expand Down Expand Up @@ -53,3 +55,50 @@ func (s ShapeProperties) LineProperties() LineProperties {
}
return LineProperties{s.x.Ln}
}

func (s ShapeProperties) ensureXfrm() {
if s.x.Xfrm == nil {
s.x.Xfrm = dml.NewCT_Transform2D()
}
}

// SetWidth sets the width of the shape.
func (s ShapeProperties) SetWidth(w measurement.Distance) {
s.ensureXfrm()
if s.x.Xfrm.Ext == nil {
s.x.Xfrm.Ext = dml.NewCT_PositiveSize2D()
}
s.x.Xfrm.Ext.CxAttr = int64(w / measurement.EMU)
}

// SetHeight sets the height of the shape.
func (s ShapeProperties) SetHeight(h measurement.Distance) {
s.ensureXfrm()
if s.x.Xfrm.Ext == nil {
s.x.Xfrm.Ext = dml.NewCT_PositiveSize2D()
}
s.x.Xfrm.Ext.CyAttr = int64(h / measurement.EMU)
}

// SetSize sets the width and height of the shape.
func (s ShapeProperties) SetSize(w, h measurement.Distance) {
s.SetWidth(w)
s.SetHeight(h)
}

// SetPosition sets the position of the shape.
func (s ShapeProperties) SetPosition(x, y measurement.Distance) {
if s.x.Xfrm.Off == nil {
s.x.Xfrm.Off = dml.NewCT_Point2D()
}
s.x.Xfrm.Off.XAttr.ST_CoordinateUnqualified = gooxml.Int64(int64(x / measurement.EMU))
s.x.Xfrm.Off.YAttr.ST_CoordinateUnqualified = gooxml.Int64(int64(y / measurement.EMU))
}

// SetGeometry sets the shape type of the shape
func (s ShapeProperties) SetGeometry(g dml.ST_ShapeType) {
if s.x.PrstGeom == nil {
s.x.PrstGeom = dml.NewCT_PresetGeometry2D()
}
s.x.PrstGeom.PrstAttr = g
}
33 changes: 13 additions & 20 deletions presentation/presentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,20 @@ func (p *Presentation) X() *pml.Presentation {
return p.x
}

func (p *Presentation) nextSlideID() uint32 {
id := uint32(256)
for _, s := range p.x.SldIdLst.SldId {
if s.IdAttr >= id {
id = s.IdAttr + 1
}
}
return id
}

// AddSlide adds a new slide to the presentation.
func (p *Presentation) AddSlide() Slide {
sd := pml.NewCT_SlideIdListEntry()
sd.IdAttr = 256
sd.IdAttr = p.nextSlideID()
p.x.SldIdLst.SldId = append(p.x.SldIdLst.SldId, sd)

slide := pml.NewSld()
Expand All @@ -250,24 +260,6 @@ func (p *Presentation) AddSlide() Slide {
slide.CSld.SpTree.GrpSpPr.Xfrm.ChOff = slide.CSld.SpTree.GrpSpPr.Xfrm.Off
slide.CSld.SpTree.GrpSpPr.Xfrm.ChExt = slide.CSld.SpTree.GrpSpPr.Xfrm.Ext

/*
c := pml.NewCT_GroupShapeChoice()
slide.CSld.SpTree.Choice = append(slide.CSld.SpTree.Choice, c)
sp := pml.NewCT_Shape()
c.Sp = append(c.Sp, sp)
sp.NvSpPr.NvPr.Ph = pml.NewCT_Placeholder()
sp.NvSpPr.NvPr.Ph.TypeAttr = pml.ST_PlaceholderTypeCtrTitle
sp.TxBody = dml.NewCT_TextBody()
para := dml.NewCT_TextParagraph()
sp.TxBody.P = append(sp.TxBody.P, para)
run := dml.NewEG_TextRun()
para.EG_TextRun = append(para.EG_TextRun, run)
run.R = dml.NewCT_RegularTextRun()
run.R.T = "testing 123"
*/
p.slides = append(p.slides, slide)
srelID := p.prels.AddAutoRelationship(gooxml.DocTypePresentation, gooxml.OfficeDocumentType,
len(p.slides), gooxml.SlideType)
Expand Down Expand Up @@ -478,11 +470,12 @@ func (p *Presentation) Validate() error {
if err := p.x.Validate(); err != nil {
return err
}
for i, s := range p.slides {
for i, s := range p.Slides() {
if err := s.ValidateWithPath(fmt.Sprintf("Slide[%d]", i)); err != nil {
return err
}
}

for i, sm := range p.masters {
if err := sm.ValidateWithPath(fmt.Sprintf("SlideMaster[%d]", i)); err != nil {
return err
Expand Down
47 changes: 47 additions & 0 deletions presentation/slide.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ package presentation
import (
"errors"

"baliance.com/gooxml/measurement"
"baliance.com/gooxml/schema/soo/dml"

"baliance.com/gooxml/schema/soo/pml"
)

Expand Down Expand Up @@ -68,3 +71,47 @@ func (s Slide) GetPlaceholderByIndex(idx uint32) (PlaceHolder, error) {
}
return PlaceHolder{}, errors.New("unable to find placeholder")
}

// ValidateWithPath validates the slide passing path informaton for a better
// error message
func (s Slide) ValidateWithPath(path string) error {
// schema checks
if err := s.x.ValidateWithPath(path); err != nil {
return err
}

// stuff we've figured out
for _, c := range s.x.CSld.SpTree.Choice {
for _, sp := range c.Sp {
if sp.TxBody != nil {
if len(sp.TxBody.P) == 0 {
return errors.New(path + " : slide shape with a txbody must contain paragraphs")
}
}
}
}
return nil
}

// AddTextBox adds an empty textbox to a slide.
func (s Slide) AddTextBox() TextBox {
c := pml.NewCT_GroupShapeChoice()
s.x.CSld.SpTree.Choice = append(s.x.CSld.SpTree.Choice, c)

sp := pml.NewCT_Shape()
c.Sp = append(c.Sp, sp)
sp.SpPr = dml.NewCT_ShapeProperties()
sp.SpPr.Xfrm = dml.NewCT_Transform2D()
sp.SpPr.PrstGeom = dml.NewCT_PresetGeometry2D()
sp.SpPr.PrstGeom.PrstAttr = dml.ST_ShapeTypeRect
sp.TxBody = dml.NewCT_TextBody()
sp.TxBody.BodyPr = dml.NewCT_TextBodyProperties()
sp.TxBody.BodyPr.WrapAttr = dml.ST_TextWrappingTypeSquare
sp.TxBody.BodyPr.SpAutoFit = dml.NewCT_TextShapeAutofit()

tb := TextBox{sp}
tb.Properties().SetWidth(3 * measurement.Inch)
tb.Properties().SetHeight(1 * measurement.Inch)
tb.Properties().SetPosition(0, 0)
return tb
}
34 changes: 34 additions & 0 deletions presentation/textbox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2017 Baliance. All rights reserved.
//
// Use of this source code is governed by the terms of the Affero GNU General
// Public License version 3.0 as published by the Free Software Foundation and
// appearing in the file LICENSE included in the packaging of this file. A
// commercial license can be purchased by contacting [email protected].

package presentation

import (
"baliance.com/gooxml/drawing"
"baliance.com/gooxml/schema/soo/dml"
"baliance.com/gooxml/schema/soo/pml"
)

// TextBox is a text box within a slide.
type TextBox struct {
x *pml.CT_Shape
}

// AddParagraph adds a paragraph to the text box
func (t TextBox) AddParagraph() drawing.Paragraph {
p := dml.NewCT_TextParagraph()
t.x.TxBody.P = append(t.x.TxBody.P, p)
return drawing.MakeParagraph(p)
}

// Properties returns the properties of the TextBox.
func (t TextBox) Properties() drawing.ShapeProperties {
if t.x.SpPr == nil {
t.x.SpPr = dml.NewCT_ShapeProperties()
}
return drawing.MakeShapeProperties(t.x.SpPr)
}

0 comments on commit 8030eab

Please sign in to comment.