diff options
Diffstat (limited to 'src/lib/SW602GraphicStyle.h')
-rw-r--r-- | src/lib/SW602GraphicStyle.h | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/src/lib/SW602GraphicStyle.h b/src/lib/SW602GraphicStyle.h new file mode 100644 index 0000000..43282c8 --- /dev/null +++ b/src/lib/SW602GraphicStyle.h @@ -0,0 +1,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: */ |