package ps import ( "encoding/json" "fmt" "log" "strings" ) // LayerSet holds a group of Layer objects and a group of LayerSet objects. type LayerSet struct { name string bounds [2][2]int parent Group current bool // Whether we've checked this layer since we loaded from disk. visible bool artLayers []*ArtLayer layerSets []*LayerSet } // LayerSetJSON is an exported version of LayerSet, that allows LayerSets to be // saved to and loaded from JSON. type LayerSetJSON struct { Name string Bounds [2][2]int Visible bool ArtLayers []*ArtLayer LayerSets []*LayerSet } // MarshalJSON returns the LayerSet in JSON form. func (l *LayerSet) MarshalJSON() ([]byte, error) { return json.Marshal(&LayerSetJSON{ Name: l.name, Bounds: l.bounds, Visible: l.visible, ArtLayers: l.artLayers, LayerSets: l.layerSets, }) } // UnmarshalJSON loads the json data into this LayerSet. func (l *LayerSet) UnmarshalJSON(b []byte) error { tmp := &LayerSetJSON{} if err := json.Unmarshal(b, &tmp); err != nil { return err } l.name = tmp.Name l.bounds = tmp.Bounds l.visible = tmp.Visible l.artLayers = tmp.ArtLayers for _, lyr := range l.artLayers { lyr.SetParent(l) } l.layerSets = tmp.LayerSets for _, set := range l.layerSets { set.SetParent(l) } l.current = false return nil } // Name returns the name of the LayerSet func (l LayerSet) Name() string { return l.name } // ArtLayers returns the LayerSet's ArtLayers. func (l *LayerSet) ArtLayers() []*ArtLayer { if Mode != Fast { for _, lyr := range l.artLayers { if !lyr.current { if err := lyr.Refresh(); err != nil { log.Println(err) } lyr.current = true } } } return l.artLayers } // ArtLayer returns the first top level ArtLayer matching // the given name. func (l *LayerSet) ArtLayer(name string) *ArtLayer { for _, lyr := range l.artLayers { if lyr.name == name { if Mode == 0 && !lyr.current { err := lyr.Refresh() if err != nil { if err = l.Refresh(); err != nil { log.Panic(err) } if err := lyr.Refresh(); err != nil { log.Panic(err) } } } return lyr } } return nil } // LayerSets returns the LayerSets contained within // this set. func (l *LayerSet) LayerSets() []*LayerSet { return l.layerSets } // LayerSet returns the first top level LayerSet matching // the given name. func (l *LayerSet) LayerSet(name string) *LayerSet { for _, set := range l.layerSets { if set.name == name { return set } } return nil } // MustExist returns a Layer from the set with the given name, and // panics if it doesn't exist. // // If there is a LayerSet and an ArtLayer with the same name, // it will return the LayerSet. func (l *LayerSet) MustExist(name string) Layer { set := l.LayerSet(name) if set == nil { lyr := l.ArtLayer(name) if lyr == nil { log.Panicf("no Layer found at \"%s%s\"", l.Path(), name) } return lyr } return set } // Bounds returns the furthest corners of the LayerSet. func (l LayerSet) Bounds() [2][2]int { return l.bounds } // SetParent puts this LayerSet into the given group. func (l *LayerSet) SetParent(g Group) { l.parent = g } // Parent returns this layerSet's parent. func (l *LayerSet) Parent() Group { return l.parent } // Path returns the layer path to this Set. func (l *LayerSet) Path() string { if l.parent == nil { return l.name } return fmt.Sprintf("%s%s/", l.parent.Path(), l.name) } // NewLayerSet grabs the LayerSet with the given path and returns it. func NewLayerSet(path string, g Group) (*LayerSet, error) { path = strings.Replace(path, "//", "/", -1) byt, err := DoJS("getLayerSet.jsx", JSLayer(path), JSLayerMerge(path)) if err != nil { return nil, err } var out *LayerSet err = json.Unmarshal(byt, &out) if err != nil { log.Println(JSLayer(path)) log.Println(string(byt)) return nil, err } out.SetParent(g) log.Printf("Loading ActiveDocument/%s\n", out.Path()) for _, lyr := range out.artLayers { lyr.SetParent(out) } for i, set := range out.layerSets { var s *LayerSet s, err = NewLayerSet(fmt.Sprintf("%s%s/", path, set.Name()), out) if err != nil { log.Fatal(err) } out.layerSets[i] = s s.SetParent(out) } out.current = true return out, err } // Visible returns whether or not the LayerSet is currently visible. func (l LayerSet) Visible() bool { return l.visible } // SetVisible makes the LayerSet visible. func (l *LayerSet) SetVisible(b bool) error { if l.visible == b { return nil } js := fmt.Sprintf("%s.visible=%v;", strings.TrimRight( JSLayer(l.Path()), ";"), b) if _, err := DoJS("compilejs.jsx", js); err != nil { return err } l.visible = b return nil } // SetPos snaps the given layerset boundry to the given point. // Valid options for bound are: "TL", "TR", "BL", "BR" func (l *LayerSet) SetPos(x, y int, bound string) { if !l.visible || (x == 0 && y == 0) { return } path := JSLayer(l.Path()) mrgPath := JSLayerMerge(l.Path()) byt, err := DoJS("LayerSetBounds.jsx", path, mrgPath) if err != nil { log.Println(string(byt)) log.Panic(err) } var bnds *[2][2]int err = json.Unmarshal(byt, &bnds) if err != nil { fmt.Println(string(byt)) log.Panic(err) } l.bounds = *bnds var lyrX, lyrY int switch bound[:1] { case "B": lyrY = l.bounds[1][1] case "T": fallthrough default: lyrY = l.bounds[0][1] } switch bound[1:] { case "R": lyrX = l.bounds[1][0] case "L": fallthrough default: lyrX = l.bounds[0][0] } byt, err = DoJS("moveLayer.jsx", JSLayer(l.Path()), fmt.Sprint(x-lyrX), fmt.Sprint(y-lyrY), JSLayerMerge(l.Path())) if err != nil { fmt.Println("byte:", string(byt)) panic(err) } var lyr LayerSet if err = json.Unmarshal(byt, &lyr); err != nil { fmt.Println("byte:", string(byt)) log.Panic(err) } l.bounds = lyr.bounds } // Refresh syncs the LayerSet with Photoshop. func (l *LayerSet) Refresh() error { var tmp *LayerSet byt, err := DoJS("getLayerSet.jsx", JSLayer(l.Path())) if err != nil { if err = DoAction("Undo", "DK"); err != nil { return err } if byt, err = DoJS("getLayerSet.jsx", JSLayer(l.Path())); err != nil { return err } } err = json.Unmarshal(byt, &tmp) if err != nil { log.Println("Error in LayerSet.Refresh() \"", string(byt), "\"", "for", l.Path()) return err } tmp.SetParent(l.Parent()) for _, lyr := range l.artLayers { err = lyr.Refresh() if err != nil { l.artLayers = tmp.artLayers break } } for _, set := range l.layerSets { if err = set.Refresh(); err != nil { return err } } l.name = tmp.name l.bounds = tmp.bounds l.visible = tmp.visible l.current = true return nil } func (l *LayerSet) Set(ll *LayerSet) { if ll == nil { panic("AHHHHHH") } l = ll }