@@ -28,6 +28,7 @@ type FormControlType byte
28
28
const (
29
29
FormControlNote FormControlType = iota
30
30
FormControlButton
31
+ FormControlCheckbox
31
32
FormControlRadio
32
33
)
33
34
@@ -114,8 +115,9 @@ func (f *File) AddComment(sheet string, opts Comment) error {
114
115
})
115
116
}
116
117
117
- // DeleteComment provides the method to delete comment in a sheet by given
118
- // worksheet name. For example, delete the comment in Sheet1!$A$30:
118
+ // DeleteComment provides the method to delete comment in a worksheet by given
119
+ // worksheet name and cell reference. For example, delete the comment in
120
+ // Sheet1!$A$30:
119
121
//
120
122
// err := f.DeleteComment("Sheet1", "A30")
121
123
func (f * File ) DeleteComment (sheet , cell string ) error {
@@ -315,6 +317,80 @@ func (f *File) AddFormControl(sheet string, opts FormControl) error {
315
317
})
316
318
}
317
319
320
+ // DeleteFormControl provides the method to delete form control in a worksheet
321
+ // by given worksheet name and cell reference. For example, delete the form
322
+ // control in Sheet1!$A$30:
323
+ //
324
+ // err := f.DeleteFormControl("Sheet1", "A30")
325
+ func (f * File ) DeleteFormControl (sheet , cell string ) error {
326
+ ws , err := f .workSheetReader (sheet )
327
+ if err != nil {
328
+ return err
329
+ }
330
+ col , row , err := CellNameToCoordinates (cell )
331
+ if err != nil {
332
+ return err
333
+ }
334
+ if ws .LegacyDrawing == nil {
335
+ return err
336
+ }
337
+ sheetRelationshipsDrawingVML := f .getSheetRelationshipsTargetByID (sheet , ws .LegacyDrawing .RID )
338
+ vmlID , _ := strconv .Atoi (strings .TrimSuffix (strings .TrimPrefix (sheetRelationshipsDrawingVML , "../drawings/vmlDrawing" ), ".vml" ))
339
+ drawingVML := strings .ReplaceAll (sheetRelationshipsDrawingVML , ".." , "xl" )
340
+ vml := f .VMLDrawing [drawingVML ]
341
+ if vml == nil {
342
+ vml = & vmlDrawing {
343
+ XMLNSv : "urn:schemas-microsoft-com:vml" ,
344
+ XMLNSo : "urn:schemas-microsoft-com:office:office" ,
345
+ XMLNSx : "urn:schemas-microsoft-com:office:excel" ,
346
+ XMLNSmv : "http://macVmlSchemaUri" ,
347
+ ShapeLayout : & xlsxShapeLayout {
348
+ Ext : "edit" , IDmap : & xlsxIDmap {Ext : "edit" , Data : vmlID },
349
+ },
350
+ ShapeType : & xlsxShapeType {
351
+ Stroke : & xlsxStroke {JoinStyle : "miter" },
352
+ VPath : & vPath {GradientShapeOK : "t" , ConnectType : "rect" },
353
+ },
354
+ }
355
+ // load exist VML shapes from xl/drawings/vmlDrawing%d.vml
356
+ d , err := f .decodeVMLDrawingReader (drawingVML )
357
+ if err != nil {
358
+ return err
359
+ }
360
+ if d != nil {
361
+ vml .ShapeType .ID = d .ShapeType .ID
362
+ vml .ShapeType .CoordSize = d .ShapeType .CoordSize
363
+ vml .ShapeType .Spt = d .ShapeType .Spt
364
+ vml .ShapeType .Path = d .ShapeType .Path
365
+ for _ , v := range d .Shape {
366
+ s := xlsxShape {
367
+ ID : v .ID ,
368
+ Type : v .Type ,
369
+ Style : v .Style ,
370
+ Button : v .Button ,
371
+ Filled : v .Filled ,
372
+ FillColor : v .FillColor ,
373
+ InsetMode : v .InsetMode ,
374
+ Stroked : v .Stroked ,
375
+ StrokeColor : v .StrokeColor ,
376
+ Val : v .Val ,
377
+ }
378
+ vml .Shape = append (vml .Shape , s )
379
+ }
380
+ }
381
+ }
382
+ for i , sp := range vml .Shape {
383
+ var shapeVal decodeShapeVal
384
+ if err = xml .Unmarshal ([]byte (fmt .Sprintf ("<shape>%s</shape>" , sp .Val )), & shapeVal ); err == nil &&
385
+ shapeVal .ClientData .ObjectType != "Note" && shapeVal .ClientData .Column == col - 1 && shapeVal .ClientData .Row == row - 1 {
386
+ vml .Shape = append (vml .Shape [:i ], vml .Shape [i + 1 :]... )
387
+ break
388
+ }
389
+ }
390
+ f .VMLDrawing [drawingVML ] = vml
391
+ return err
392
+ }
393
+
318
394
// countVMLDrawing provides a function to get VML drawing files count storage
319
395
// in the folder xl/drawings.
320
396
func (f * File ) countVMLDrawing () int {
@@ -380,20 +456,16 @@ func (f *File) addVMLObject(opts vmlOptions) error {
380
456
}
381
457
drawingVML := "xl/drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
382
458
sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv .Itoa (vmlID ) + ".vml"
459
+ sheetXMLPath , _ := f .getSheetXMLPath (opts .Sheet )
460
+ sheetRels := "xl/worksheets/_rels/" + strings .TrimPrefix (sheetXMLPath , "xl/worksheets/" ) + ".rels"
383
461
if ws .LegacyDrawing != nil {
384
462
// The worksheet already has a VML relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml.
385
463
sheetRelationshipsDrawingVML = f .getSheetRelationshipsTargetByID (opts .Sheet , ws .LegacyDrawing .RID )
386
464
vmlID , _ = strconv .Atoi (strings .TrimSuffix (strings .TrimPrefix (sheetRelationshipsDrawingVML , "../drawings/vmlDrawing" ), ".vml" ))
387
465
drawingVML = strings .ReplaceAll (sheetRelationshipsDrawingVML , ".." , "xl" )
388
466
} else {
389
467
// Add first VML drawing for given sheet.
390
- sheetXMLPath , _ := f .getSheetXMLPath (opts .Sheet )
391
- sheetRels := "xl/worksheets/_rels/" + strings .TrimPrefix (sheetXMLPath , "xl/worksheets/" ) + ".rels"
392
468
rID := f .addRels (sheetRels , SourceRelationshipDrawingVML , sheetRelationshipsDrawingVML , "" )
393
- if ! opts .FormCtrl {
394
- sheetRelationshipsComments := "../comments" + strconv .Itoa (vmlID ) + ".xml"
395
- f .addRels (sheetRels , SourceRelationshipComments , sheetRelationshipsComments , "" )
396
- }
397
469
f .addSheetNameSpace (opts .Sheet , SourceRelationship )
398
470
f .addSheetLegacyDrawing (opts .Sheet , rID )
399
471
}
@@ -405,6 +477,10 @@ func (f *File) addVMLObject(opts vmlOptions) error {
405
477
if err = f .addComment (commentsXML , opts ); err != nil {
406
478
return err
407
479
}
480
+ if sheetXMLPath , ok := f .getSheetXMLPath (opts .Sheet ); ok && f .getSheetComments (filepath .Base (sheetXMLPath )) == "" {
481
+ sheetRelationshipsComments := "../comments" + strconv .Itoa (vmlID ) + ".xml"
482
+ f .addRels (sheetRels , SourceRelationshipComments , sheetRelationshipsComments , "" )
483
+ }
408
484
}
409
485
return f .addContentTypePart (vmlID , "comments" )
410
486
}
@@ -475,75 +551,87 @@ func formCtrlText(opts *vmlOptions) []vmlFont {
475
551
return font
476
552
}
477
553
478
- var (
479
- formCtrlPresets = map [FormControlType ]struct {
480
- objectType string
481
- filled string
482
- fillColor string
483
- stroked string
484
- strokeColor string
485
- strokeButton string
486
- fill * vFill
487
- textHAlign string
488
- textVAlign string
489
- noThreeD * string
490
- firstButton * string
491
- shadow * vShadow
492
- }{
493
- FormControlNote : {
494
- objectType : "Note" ,
495
- filled : "" ,
496
- fillColor : "#FBF6D6" ,
497
- stroked : "" ,
498
- strokeColor : "#EDEAA1" ,
499
- strokeButton : "" ,
500
- fill : & vFill {
501
- Color2 : "#FBFE82" ,
502
- Angle : - 180 ,
503
- Type : "gradient" ,
504
- Fill : & oFill {Ext : "view" , Type : "gradientUnscaled" },
505
- },
506
- textHAlign : "" ,
507
- textVAlign : "" ,
508
- noThreeD : nil ,
509
- firstButton : nil ,
510
- shadow : & vShadow {On : "t" , Color : "black" , Obscured : "t" },
511
- },
512
- FormControlButton : {
513
- objectType : "Button" ,
514
- filled : "" ,
515
- fillColor : "buttonFace [67]" ,
516
- stroked : "" ,
517
- strokeColor : "windowText [64]" ,
518
- strokeButton : "t" ,
519
- fill : & vFill {
520
- Color2 : "buttonFace [67]" ,
521
- Angle : - 180 ,
522
- Type : "gradient" ,
523
- Fill : & oFill {Ext : "view" , Type : "gradientUnscaled" },
524
- },
525
- textHAlign : "Center" ,
526
- textVAlign : "Center" ,
527
- noThreeD : nil ,
528
- firstButton : nil ,
529
- shadow : nil ,
554
+ var formCtrlPresets = map [FormControlType ]struct {
555
+ objectType string
556
+ filled string
557
+ fillColor string
558
+ stroked string
559
+ strokeColor string
560
+ strokeButton string
561
+ fill * vFill
562
+ textHAlign string
563
+ textVAlign string
564
+ noThreeD * string
565
+ firstButton * string
566
+ shadow * vShadow
567
+ }{
568
+ FormControlNote : {
569
+ objectType : "Note" ,
570
+ filled : "" ,
571
+ fillColor : "#FBF6D6" ,
572
+ stroked : "" ,
573
+ strokeColor : "#EDEAA1" ,
574
+ strokeButton : "" ,
575
+ fill : & vFill {
576
+ Color2 : "#FBFE82" ,
577
+ Angle : - 180 ,
578
+ Type : "gradient" ,
579
+ Fill : & oFill {Ext : "view" , Type : "gradientUnscaled" },
530
580
},
531
- FormControlRadio : {
532
- objectType : "Radio" ,
533
- filled : "f" ,
534
- fillColor : "window [65]" ,
535
- stroked : "f" ,
536
- strokeColor : "windowText [64]" ,
537
- strokeButton : "" ,
538
- fill : nil ,
539
- textHAlign : "" ,
540
- textVAlign : "Center" ,
541
- noThreeD : stringPtr ("" ),
542
- firstButton : stringPtr ("" ),
543
- shadow : nil ,
581
+ textHAlign : "" ,
582
+ textVAlign : "" ,
583
+ noThreeD : nil ,
584
+ firstButton : nil ,
585
+ shadow : & vShadow {On : "t" , Color : "black" , Obscured : "t" },
586
+ },
587
+ FormControlButton : {
588
+ objectType : "Button" ,
589
+ filled : "" ,
590
+ fillColor : "buttonFace [67]" ,
591
+ stroked : "" ,
592
+ strokeColor : "windowText [64]" ,
593
+ strokeButton : "t" ,
594
+ fill : & vFill {
595
+ Color2 : "buttonFace [67]" ,
596
+ Angle : - 180 ,
597
+ Type : "gradient" ,
598
+ Fill : & oFill {Ext : "view" , Type : "gradientUnscaled" },
544
599
},
545
- }
546
- )
600
+ textHAlign : "Center" ,
601
+ textVAlign : "Center" ,
602
+ noThreeD : nil ,
603
+ firstButton : nil ,
604
+ shadow : nil ,
605
+ },
606
+ FormControlCheckbox : {
607
+ objectType : "Checkbox" ,
608
+ filled : "f" ,
609
+ fillColor : "window [65]" ,
610
+ stroked : "f" ,
611
+ strokeColor : "windowText [64]" ,
612
+ strokeButton : "" ,
613
+ fill : nil ,
614
+ textHAlign : "" ,
615
+ textVAlign : "Center" ,
616
+ noThreeD : stringPtr ("" ),
617
+ firstButton : nil ,
618
+ shadow : nil ,
619
+ },
620
+ FormControlRadio : {
621
+ objectType : "Radio" ,
622
+ filled : "f" ,
623
+ fillColor : "window [65]" ,
624
+ stroked : "f" ,
625
+ strokeColor : "windowText [64]" ,
626
+ strokeButton : "" ,
627
+ fill : nil ,
628
+ textHAlign : "" ,
629
+ textVAlign : "Center" ,
630
+ noThreeD : stringPtr ("" ),
631
+ firstButton : stringPtr ("" ),
632
+ shadow : nil ,
633
+ },
634
+ }
547
635
548
636
// addDrawingVML provides a function to create VML drawing XML as
549
637
// xl/drawings/vmlDrawing%d.vml by given data ID, XML path and VML options. The
@@ -634,7 +722,7 @@ func (f *File) addDrawingVML(dataID int, drawingVML string, opts *vmlOptions) er
634
722
if opts .FormCtrl {
635
723
sp .ClientData .FmlaMacro = opts .Macro
636
724
}
637
- if opts .Type == FormControlRadio && opts .Checked {
725
+ if ( opts .Type == FormControlCheckbox || opts . Type == FormControlRadio ) && opts .Checked {
638
726
sp .ClientData .Checked = stringPtr ("1" )
639
727
}
640
728
s , _ := xml .Marshal (sp )
0 commit comments