summaryrefslogtreecommitdiff
path: root/src/lib/SW602GraphicStyle.h
blob: 43282c8d7e4423155283a61c3503e259f2906a7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libsw602 project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#ifndef INCLUDED_SW602_GRAPHIC_STYLE_H
#define INCLUDED_SW602_GRAPHIC_STYLE_H

#include <ostream>
#include <string>
#include <vector>

#include "librevenge/librevenge.h"

#include "SW602Types.h"

namespace libsw602
{

/** a structure used to define a picture style

 \note in order to define the internal surface style, first it looks for
 a gradient, if so it uses it. Then it looks for a pattern. Finally if
 it found nothing, it uses surfaceColor and surfaceOpacity.*/
class SW602GraphicStyle
{
public:
  //! an enum used to define the basic line cap
  enum LineCap { C_Butt, C_Square, C_Round };
  //! an enum used to define the basic line join
  enum LineJoin { J_Miter, J_Round, J_Bevel };
  //! an enum used to define the gradient type
  enum GradientType { G_None, G_Axial, G_Linear, G_Radial, G_Rectangular, G_Square, G_Ellipsoid };

  //! a structure used to define an arrow
  struct Arrow
  {
    //! constructor ( no arrow)
    Arrow() : m_width(0), m_viewBox(), m_path(""), m_isCentered(false)
    {
    }
    //! constructor
    Arrow(float w, SW602Box2i const &box, std::string path, bool centered=false) :
      m_width(w), m_viewBox(box), m_path(path), m_isCentered(centered)
    {
    }
    //! returns a basic plain arrow
    static Arrow plain()
    {
      return Arrow(5, SW602Box2i(SW602Vec2i(0,0),SW602Vec2i(20,30)), "m10 0-10 30h20z", false);
    }
    //! operator<<
    friend std::ostream &operator<<(std::ostream &o, Arrow const &arrow)
    {
      if (arrow.isEmpty()) return o;
      o << "w=" << arrow.m_width << ",";
      o << "viewbox=" << arrow.m_viewBox << ",";
      o << "path=" << arrow.m_path << ",";
      if (arrow.m_isCentered) o << "centered,";
      return o;
    }
    //! operator==
    bool operator==(Arrow const &arrow) const
    {
      return m_width>=arrow.m_width && m_width<=arrow.m_width &&
             m_viewBox==arrow.m_viewBox && m_path==arrow.m_path && m_isCentered==arrow.m_isCentered;
    }
    //! operator!=
    bool operator!=(Arrow const &arrow) const
    {
      return !(*this==arrow);
    }
    //! operator<
    bool operator<(Arrow const &arrow) const
    {
      if (m_isCentered<arrow.m_isCentered) return m_isCentered ? true : false;
      return m_width<arrow.m_width && m_viewBox<arrow.m_viewBox && m_path < arrow.m_path;
    }
    //! operator<=
    bool operator<=(Arrow const &arrow) const
    {
      return *this<arrow || *this==arrow;
    }
    //! operator>
    bool operator>(Arrow const &arrow) const
    {
      return !(*this<=arrow);
    }
    //! operator>=
    bool operator>=(Arrow const &arrow) const
    {
      return !(*this<arrow);
    }
    //! returns true if there is no arrow
    bool isEmpty() const
    {
      return m_width<=0 || m_path.empty();
    }
    //! add a arrow to the propList knowing the type (start, end)
    void addTo(librevenge::RVNGPropertyList &propList, std::string const &type) const;

    //! the arrow width in point
    float m_width;
    //! the arrow viewbox
    SW602Box2i m_viewBox;
    //! the arrow path
    std::string m_path;
    //! flag to know if the arrow is centered
    bool m_isCentered;
  };

  //! a structure used to define the gradient limit in SW602GraphicStyle
  struct GradientStop
  {
    //! constructor
    GradientStop(float offset=0.0, SW602Color const &col=SW602Color::black(), float opacity=1.0) :
      m_offset(offset), m_color(col), m_opacity(opacity)
    {
    }
    /** compare two gradient */
    int cmp(GradientStop const &a) const
    {
      if (m_offset < a.m_offset) return -1;
      if (m_offset > a.m_offset) return 1;
      if (m_color < a.m_color) return -1;
      if (m_color > a.m_color) return 1;
      if (m_opacity < a.m_opacity) return -1;
      if (m_opacity > a.m_opacity) return 1;
      return 0;
    }
    //! a print operator
    friend std::ostream &operator<<(std::ostream &o, GradientStop const &st)
    {
      o << "offset=" << st.m_offset << ",";
      o << "color=" << st.m_color << ",";
      if (st.m_opacity<1.0)
        o << "opacity=" << st.m_opacity*100.f << "%,";
      return o;
    }
    //! the offset
    float m_offset;
    //! the color
    SW602Color m_color;
    //! the opacity
    float m_opacity;
  };
  /** a basic pattern used in a SW602GraphicStyle:
      - either given a list of 8x8, 16x16, 32x32 bytes with two colors
      - or with a picture ( and an average color)
   */
  struct Pattern
  {
    //! constructor
    Pattern() : m_dim(0,0), m_data(), m_picture(), m_pictureAverageColor(SW602Color::white())
    {
      m_colors[0]=SW602Color::black();
      m_colors[1]=SW602Color::white();
    }
    //!  constructor from a binary data
    Pattern(SW602Vec2i dim, SW602EmbeddedObject const &picture, SW602Color const &avColor) :
      m_dim(dim), m_data(), m_picture(picture), m_pictureAverageColor(avColor)
    {
      m_colors[0]=SW602Color::black();
      m_colors[1]=SW602Color::white();
    }
    //! virtual destructor
    virtual ~Pattern() {}
    //! return true if we does not have a pattern
    bool empty() const
    {
      if (m_dim[0]==0 || m_dim[1]==0) return true;
      if (!m_picture.m_dataList.empty()) return false;
      if (m_dim[0]!=8 && m_dim[0]!=16 && m_dim[0]!=32) return true;
      return m_data.size()!=size_t((m_dim[0]/8)*m_dim[1]);
    }
    //! return the average color
    bool getAverageColor(SW602Color &col) const;
    //! check if the pattern has only one color; if so returns true...
    bool getUniqueColor(SW602Color &col) const;
    /** tries to convert the picture in a binary data ( ppm) */
    bool getBinary(SW602EmbeddedObject &picture) const;

    /** compare two patterns */
    int cmp(Pattern const &a) const
    {
      int diff = m_dim.cmp(a.m_dim);
      if (diff) return diff;
      if (m_data.size() < a.m_data.size()) return -1;
      if (m_data.size() > a.m_data.size()) return 1;
      for (size_t h=0; h < m_data.size(); ++h)
      {
        if (m_data[h]<a.m_data[h]) return 1;
        if (m_data[h]>a.m_data[h]) return -1;
      }
      for (int i=0; i<2; ++i)
      {
        if (m_colors[i] < a.m_colors[i]) return 1;
        if (m_colors[i] > a.m_colors[i]) return -1;
      }
      if (m_pictureAverageColor < a.m_pictureAverageColor) return 1;
      if (m_pictureAverageColor > a.m_pictureAverageColor) return -1;
      diff=m_picture.cmp(a.m_picture);
      if (diff) return diff;
      return 0;
    }
    //! a print operator
    friend std::ostream &operator<<(std::ostream &o, Pattern const &pat)
    {
      o << "dim=" << pat.m_dim << ",";
      if (!pat.m_picture.isEmpty())
      {
        o << "pict=" << pat.m_picture << ",";
        o << "col[average]=" << pat.m_pictureAverageColor << ",";
      }
      else
      {
        if (!pat.m_colors[0].isBlack()) o << "col0=" << pat.m_colors[0] << ",";
        if (!pat.m_colors[1].isWhite()) o << "col1=" << pat.m_colors[1] << ",";
        o << "[";
        for (size_t h=0; h < pat.m_data.size(); ++h)
          o << std::hex << (int) pat.m_data[h] << std::dec << ",";
        o << "],";
      }
      return o;
    }
    //! the dimension width x height
    SW602Vec2i m_dim;

    //! the two indexed colors
    SW602Color m_colors[2];
    //! the pattern data: a sequence of data: p[0..7,0],p[8..15,0]...p[0..7,1],p[8..15,1], ...
    std::vector<unsigned char> m_data;
  protected:
    //! a picture
    SW602EmbeddedObject m_picture;
    //! the picture average color
    SW602Color m_pictureAverageColor;
  };
  //! constructor
  SW602GraphicStyle() :  m_lineWidth(1), m_lineDashWidth(), m_lineCap(C_Butt), m_lineJoin(J_Miter), m_lineOpacity(1), m_lineColor(SW602Color::black()),
    m_fillRuleEvenOdd(false), m_surfaceColor(SW602Color::white()), m_surfaceOpacity(0),
    m_shadowColor(SW602Color::black()), m_shadowOpacity(0), m_shadowOffset(1,1),
    m_pattern(),
    m_gradientType(G_None), m_gradientStopList(), m_gradientAngle(0), m_gradientBorder(0), m_gradientPercentCenter(0.5f,0.5f), m_gradientRadius(1),
    m_backgroundColor(SW602Color::white()), m_backgroundOpacity(-1), m_bordersList(), m_frameName(""), m_frameNextName(""),
    m_rotate(0), m_extra("")
  {
    m_arrows[0]=m_arrows[1]=Arrow();
    m_flip[0]=m_flip[1]=false;
    m_gradientStopList.push_back(GradientStop(0.0, SW602Color::white()));
    m_gradientStopList.push_back(GradientStop(1.0, SW602Color::black()));
  }
  /** returns an empty style. Can be used to initialize a default frame style...*/
  static SW602GraphicStyle emptyStyle()
  {
    SW602GraphicStyle res;
    res.m_lineWidth=0;
    return res;
  }
  //! virtual destructor
  virtual ~SW602GraphicStyle() { }
  //! returns true if the border is defined
  bool hasLine() const
  {
    return m_lineWidth>0 && m_lineOpacity>0;
  }
  //! set the surface color
  void setSurfaceColor(SW602Color const &col, float opacity = 1)
  {
    m_surfaceColor = col;
    m_surfaceOpacity = opacity;
  }
  //! returns true if the surface is defined
  bool hasSurfaceColor() const
  {
    return m_surfaceOpacity > 0;
  }
  //! set the pattern
  void setPattern(Pattern const &pat, float opacity = 1)
  {
    m_pattern=pat;
    m_surfaceOpacity = opacity;
  }
  //! returns true if the pattern is defined
  bool hasPattern() const
  {
    return !m_pattern.empty() && m_surfaceOpacity > 0;
  }
  //! returns true if the gradient is defined
  bool hasGradient(bool complex=false) const
  {
    return m_gradientType != G_None && (int) m_gradientStopList.size() >= (complex ? 3 : 2);
  }
  //! returns true if the interior surface is defined
  bool hasSurface() const
  {
    return hasSurfaceColor() || hasPattern() || hasGradient();
  }
  //! set the background color
  void setBackgroundColor(SW602Color const &col, float opacity = 1)
  {
    m_backgroundColor = col;
    m_backgroundOpacity = opacity;
  }
  //! returns true if the background is defined
  bool hasBackgroundColor() const
  {
    return m_backgroundOpacity > 0;
  }
  //! set the shadow color
  void setShadowColor(SW602Color const &col, float opacity = 1)
  {
    m_shadowColor = col;
    m_shadowOpacity = opacity;
  }
  //! returns true if the shadow is defined
  bool hasShadow() const
  {
    return m_shadowOpacity > 0;
  }
  //! return true if the frame has some border
  bool hasBorders() const
  {
    return !m_bordersList.empty();
  }
  //! return true if the frame has some border
  bool hasSameBorders() const
  {
    if (m_bordersList.empty()) return true;
    if (m_bordersList.size()!=4) return false;
    for (size_t i=1; i<m_bordersList.size(); ++i)
    {
      if (m_bordersList[i]!=m_bordersList[0])
        return false;
    }
    return true;
  }
  //! return the frame border: libsw602::Left | ...
  std::vector<SW602Border> const &borders() const
  {
    return m_bordersList;
  }
  //! reset the border
  void resetBorders()
  {
    m_bordersList.resize(0);
  }
  //! sets the cell border: wh=libsw602::LeftBit|...
  void setBorders(int wh, SW602Border const &border);
  //! a print operator
  friend std::ostream &operator<<(std::ostream &o, SW602GraphicStyle const &st);
  //! add all the parameters to the propList excepted the frame parameter: the background and the borders
  void addTo(librevenge::RVNGPropertyList &pList, bool only1d=false) const;
  //! add all the frame parameters to propList: the background and the borders
  void addFrameTo(librevenge::RVNGPropertyList &pList) const;
  /** compare two styles */
  int cmp(SW602GraphicStyle const &a) const;

  //! the linewidth
  float m_lineWidth;
  //! the dash array: a sequence of (fullsize, emptysize)
  std::vector<float> m_lineDashWidth;
  //! the line cap
  LineCap m_lineCap;
  //! the line join
  LineJoin m_lineJoin;
  //! the line opacity: 0=transparent
  float m_lineOpacity;
  //! the line color
  SW602Color m_lineColor;
  //! true if the fill rule is evenod
  bool m_fillRuleEvenOdd;
  //! the surface color
  SW602Color m_surfaceColor;
  //! true if the surface has some color
  float m_surfaceOpacity;

  //! the shadow color
  SW602Color m_shadowColor;
  //! true if the shadow has some color
  float m_shadowOpacity;
  //! the shadow offset
  SW602Vec2f m_shadowOffset;

  //! the pattern if it exists
  Pattern m_pattern;

  //! the gradient type
  GradientType m_gradientType;
  //! the list of gradient limits
  std::vector<GradientStop> m_gradientStopList;
  //! the gradient angle
  float m_gradientAngle;
  //! the gradient border opacity
  float m_gradientBorder;
  //! the gradient center
  SW602Vec2f m_gradientPercentCenter;
  //! the gradient radius
  float m_gradientRadius;

  //! the two arrows corresponding to start and end extremity
  Arrow m_arrows[2];

  //
  // related to the frame
  //

  //! the background color
  SW602Color m_backgroundColor;
  //! true if the background has some color
  float m_backgroundOpacity;
  //! the borders SW602Border::Pos (for a frame)
  std::vector<SW602Border> m_bordersList;
  //! the frame name
  std::string m_frameName;
  //! the frame next name (if there is a link)
  std::string m_frameNextName;

  //
  // some transformation: must probably be somewhere else
  //

  //! the rotation
  float m_rotate;
  //! two bool to indicated we need to flip the shape or not
  bool m_flip[2];

  //! extra data
  std::string m_extra;
};

}

#endif

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */