1<?php
2
3namespace PhpOffice\PhpSpreadsheet\Style;
4
5use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
6
7class Fill extends Supervisor
8{
9    // Fill types
10    const FILL_NONE = 'none';
11    const FILL_SOLID = 'solid';
12    const FILL_GRADIENT_LINEAR = 'linear';
13    const FILL_GRADIENT_PATH = 'path';
14    const FILL_PATTERN_DARKDOWN = 'darkDown';
15    const FILL_PATTERN_DARKGRAY = 'darkGray';
16    const FILL_PATTERN_DARKGRID = 'darkGrid';
17    const FILL_PATTERN_DARKHORIZONTAL = 'darkHorizontal';
18    const FILL_PATTERN_DARKTRELLIS = 'darkTrellis';
19    const FILL_PATTERN_DARKUP = 'darkUp';
20    const FILL_PATTERN_DARKVERTICAL = 'darkVertical';
21    const FILL_PATTERN_GRAY0625 = 'gray0625';
22    const FILL_PATTERN_GRAY125 = 'gray125';
23    const FILL_PATTERN_LIGHTDOWN = 'lightDown';
24    const FILL_PATTERN_LIGHTGRAY = 'lightGray';
25    const FILL_PATTERN_LIGHTGRID = 'lightGrid';
26    const FILL_PATTERN_LIGHTHORIZONTAL = 'lightHorizontal';
27    const FILL_PATTERN_LIGHTTRELLIS = 'lightTrellis';
28    const FILL_PATTERN_LIGHTUP = 'lightUp';
29    const FILL_PATTERN_LIGHTVERTICAL = 'lightVertical';
30    const FILL_PATTERN_MEDIUMGRAY = 'mediumGray';
31
32    /**
33     * @var int
34     */
35    public $startcolorIndex;
36
37    /**
38     * @var int
39     */
40    public $endcolorIndex;
41
42    /**
43     * Fill type.
44     *
45     * @var string
46     */
47    protected $fillType = self::FILL_NONE;
48
49    /**
50     * Rotation.
51     *
52     * @var float
53     */
54    protected $rotation = 0;
55
56    /**
57     * Start color.
58     *
59     * @var Color
60     */
61    protected $startColor;
62
63    /**
64     * End color.
65     *
66     * @var Color
67     */
68    protected $endColor;
69
70    /**
71     * Create a new Fill.
72     *
73     * @param bool $isSupervisor Flag indicating if this is a supervisor or not
74     *                                    Leave this value at default unless you understand exactly what
75     *                                        its ramifications are
76     * @param bool $isConditional Flag indicating if this is a conditional style or not
77     *                                    Leave this value at default unless you understand exactly what
78     *                                        its ramifications are
79     */
80    public function __construct($isSupervisor = false, $isConditional = false)
81    {
82        // Supervisor?
83        parent::__construct($isSupervisor);
84
85        // Initialise values
86        if ($isConditional) {
87            $this->fillType = null;
88        }
89        $this->startColor = new Color(Color::COLOR_WHITE, $isSupervisor, $isConditional);
90        $this->endColor = new Color(Color::COLOR_BLACK, $isSupervisor, $isConditional);
91
92        // bind parent if we are a supervisor
93        if ($isSupervisor) {
94            $this->startColor->bindParent($this, 'startColor');
95            $this->endColor->bindParent($this, 'endColor');
96        }
97    }
98
99    /**
100     * Get the shared style component for the currently active cell in currently active sheet.
101     * Only used for style supervisor.
102     *
103     * @return Fill
104     */
105    public function getSharedComponent()
106    {
107        return $this->parent->getSharedComponent()->getFill();
108    }
109
110    /**
111     * Build style array from subcomponents.
112     *
113     * @param array $array
114     *
115     * @return array
116     */
117    public function getStyleArray($array)
118    {
119        return ['fill' => $array];
120    }
121
122    /**
123     * Apply styles from array.
124     *
125     * <code>
126     * $spreadsheet->getActiveSheet()->getStyle('B2')->getFill()->applyFromArray(
127     *     [
128     *         'fillType' => Fill::FILL_GRADIENT_LINEAR,
129     *         'rotation' => 0,
130     *         'startColor' => [
131     *             'rgb' => '000000'
132     *         ],
133     *         'endColor' => [
134     *             'argb' => 'FFFFFFFF'
135     *         ]
136     *     ]
137     * );
138     * </code>
139     *
140     * @param array $pStyles Array containing style information
141     *
142     * @throws PhpSpreadsheetException
143     *
144     * @return Fill
145     */
146    public function applyFromArray(array $pStyles)
147    {
148        if ($this->isSupervisor) {
149            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($this->getStyleArray($pStyles));
150        } else {
151            if (isset($pStyles['fillType'])) {
152                $this->setFillType($pStyles['fillType']);
153            }
154            if (isset($pStyles['rotation'])) {
155                $this->setRotation($pStyles['rotation']);
156            }
157            if (isset($pStyles['startColor'])) {
158                $this->getStartColor()->applyFromArray($pStyles['startColor']);
159            }
160            if (isset($pStyles['endColor'])) {
161                $this->getEndColor()->applyFromArray($pStyles['endColor']);
162            }
163            if (isset($pStyles['color'])) {
164                $this->getStartColor()->applyFromArray($pStyles['color']);
165                $this->getEndColor()->applyFromArray($pStyles['color']);
166            }
167        }
168
169        return $this;
170    }
171
172    /**
173     * Get Fill Type.
174     *
175     * @return string
176     */
177    public function getFillType()
178    {
179        if ($this->isSupervisor) {
180            return $this->getSharedComponent()->getFillType();
181        }
182
183        return $this->fillType;
184    }
185
186    /**
187     * Set Fill Type.
188     *
189     * @param string $pValue Fill type, see self::FILL_*
190     *
191     * @return Fill
192     */
193    public function setFillType($pValue)
194    {
195        if ($this->isSupervisor) {
196            $styleArray = $this->getStyleArray(['fillType' => $pValue]);
197            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
198        } else {
199            $this->fillType = $pValue;
200        }
201
202        return $this;
203    }
204
205    /**
206     * Get Rotation.
207     *
208     * @return float
209     */
210    public function getRotation()
211    {
212        if ($this->isSupervisor) {
213            return $this->getSharedComponent()->getRotation();
214        }
215
216        return $this->rotation;
217    }
218
219    /**
220     * Set Rotation.
221     *
222     * @param float $pValue
223     *
224     * @return Fill
225     */
226    public function setRotation($pValue)
227    {
228        if ($this->isSupervisor) {
229            $styleArray = $this->getStyleArray(['rotation' => $pValue]);
230            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
231        } else {
232            $this->rotation = $pValue;
233        }
234
235        return $this;
236    }
237
238    /**
239     * Get Start Color.
240     *
241     * @return Color
242     */
243    public function getStartColor()
244    {
245        return $this->startColor;
246    }
247
248    /**
249     * Set Start Color.
250     *
251     * @param Color $pValue
252     *
253     * @throws PhpSpreadsheetException
254     *
255     * @return Fill
256     */
257    public function setStartColor(Color $pValue)
258    {
259        // make sure parameter is a real color and not a supervisor
260        $color = $pValue->getIsSupervisor() ? $pValue->getSharedComponent() : $pValue;
261
262        if ($this->isSupervisor) {
263            $styleArray = $this->getStartColor()->getStyleArray(['argb' => $color->getARGB()]);
264            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
265        } else {
266            $this->startColor = $color;
267        }
268
269        return $this;
270    }
271
272    /**
273     * Get End Color.
274     *
275     * @return Color
276     */
277    public function getEndColor()
278    {
279        return $this->endColor;
280    }
281
282    /**
283     * Set End Color.
284     *
285     * @param Color $pValue
286     *
287     * @throws PhpSpreadsheetException
288     *
289     * @return Fill
290     */
291    public function setEndColor(Color $pValue)
292    {
293        // make sure parameter is a real color and not a supervisor
294        $color = $pValue->getIsSupervisor() ? $pValue->getSharedComponent() : $pValue;
295
296        if ($this->isSupervisor) {
297            $styleArray = $this->getEndColor()->getStyleArray(['argb' => $color->getARGB()]);
298            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
299        } else {
300            $this->endColor = $color;
301        }
302
303        return $this;
304    }
305
306    /**
307     * Get hash code.
308     *
309     * @return string Hash code
310     */
311    public function getHashCode()
312    {
313        if ($this->isSupervisor) {
314            return $this->getSharedComponent()->getHashCode();
315        }
316        // Note that we don't care about colours for fill type NONE, but could have duplicate NONEs with
317        //  different hashes if we don't explicitly prevent this
318        return md5(
319            $this->getFillType() .
320            $this->getRotation() .
321            ($this->getFillType() !== self::FILL_NONE ? $this->getStartColor()->getHashCode() : '') .
322            ($this->getFillType() !== self::FILL_NONE ? $this->getEndColor()->getHashCode() : '') .
323            __CLASS__
324        );
325    }
326}
327