#ifndef MICROTEX_BOX_GROUP_H #define MICROTEX_BOX_GROUP_H #include "atom/atom.h" #include "graphic/graphic_basic.h" #include "utils/nums.h" namespace microtex { /*************************************************************************************************** * rule boxes * ***************************************************************************************************/ /** A box composed of a horizontal row of child boxes */ class HBox : public BoxGroup { private: void recalculate(const Box& box); std::pair, sptr> split(int pos, int shift); public: std::vector _breakPositions; HBox() = default; /** Create a horizontal box with alignment */ HBox(const sptr& box, float width, Alignment alignment); /** Create a horizontal box that child box aligned at center with bias */ HBox(const sptr& box, float width, float bias); explicit HBox(const sptr& box); sptr cloneBox(); void add(const sptr& box) override; void add(int pos, const sptr& box) override; void replaceFirst(const sptr& from, const sptr& to) override; inline void addBreakPosition(int pos) { _breakPositions.push_back(pos); } std::pair, sptr> split(int pos) { return split(pos, 1); } std::pair, sptr> splitRemove(int pos) { return split(pos, 2); } void draw(Graphics2D& g2, float x, float y) override; boxname(HBox); }; /** A box composed of other boxes, put one above the other */ class VBox : public BoxGroup { private: float _leftMostPos, _rightMostPos; void recalculateWidth(const Box& box); public: VBox() : _leftMostPos(F_MAX), _rightMostPos(F_MIN) {} VBox(const sptr& box, float rest, Alignment alignment); inline float leftMostPos() const { return _leftMostPos; } void add(const sptr& box) override; void add(const sptr& box, float interline); void add(int pos, const sptr& box) override; void draw(Graphics2D& g2, float x, float y) override; boxname(VBox); }; /*************************************************************************************************** * operation boxes * ***************************************************************************************************/ class ColorBox : public DecorBox { private: color _foreground = transparent; color _background = transparent; public: ColorBox() = delete; explicit ColorBox(const sptr& box, color fg = transparent, color bg = transparent); void draw(Graphics2D& g2, float x, float y) override; boxname(ColorBox); }; /** A box representing a scale operation */ class ScaleBox : public DecorBox { private: float _sx = 1, _sy = 1; void init(const sptr& b, float sx, float sy); public: ScaleBox() = delete; ScaleBox(const sptr& b, float sx, float sy) : DecorBox(b) { init(b, sx, sy); } ScaleBox(const sptr& b, float factor) : DecorBox(b) { init(b, factor, factor); } void draw(Graphics2D& g2, float x, float y) override; boxname(ScaleBox); }; /** A box representing a reflected box */ class ReflectBox : public DecorBox { public: ReflectBox() = delete; explicit ReflectBox(const sptr& b); void draw(Graphics2D& g2, float x, float y) override; boxname(ReflectBox); }; /** Enumeration representing rotation origin */ enum class Rotation { bl, // Bottom Left bc, // Bottom Center br, // Bottom Right tl, // Top Left tc, // Top Center tr, // Top Right Bl, // Baseline Left Br, // Baseline Right Bc, // Baseline Center cl, // Center Left cc, // Center Center cr, // Center Right none = -1 }; /** A box representing a rotate operation */ class RotateBox : public DecorBox { private: float _angle = 0; float _xmax = 0, _xmin = 0, _ymax = 0, _ymin = 0; float _shiftX = 0, _shiftY = 0; void init(const sptr& b, float angle, float x, float y); static Point calculateShift(const Box& b, Rotation option); public: RotateBox() = delete; RotateBox(const sptr& b, float angle, float x, float y) : DecorBox(b) { init(b, angle, x, y); } RotateBox(const sptr& b, float angle, const Point& origin) : DecorBox(b) { init(b, angle, origin.x, origin.y); } RotateBox(const sptr& b, float angle, Rotation option) : DecorBox(b) { const Point& p = calculateShift(*b, option); init(b, angle, p.x, p.y); } void draw(Graphics2D& g2, float x, float y) override; boxname(RotateBox); static Rotation getOrigin(std::string option); }; /*************************************************************************************************** * wrapped boxes * ***************************************************************************************************/ /** A box representing a wrapped box by square frame */ class FramedBox : public DecorBox { public: float _thickness = 1; float _space = 0; color _line = transparent; color _bg = transparent; void init(const sptr& box, float thickness, float space); public: FramedBox() = delete; FramedBox(const sptr& box, float thickness, float space) : DecorBox(box) { init(box, thickness, space); } FramedBox(const sptr& box, float thickness, float space, color line, color bg) : DecorBox(box) { init(box, thickness, space); _line = line; _bg = bg; } void draw(Graphics2D& g2, float x, float y) override; boxname(FramedBox); }; /** A box representing a wrapped box by oval frame */ class OvalBox : public FramedBox { private: float _multiplier, _diameter; public: OvalBox() = delete; explicit OvalBox(const sptr& fbox, float multiplier = 0.5f, float diameter = 0.f) : FramedBox(fbox->_base, fbox->_thickness, fbox->_space), _multiplier(multiplier), _diameter(diameter) {} void draw(Graphics2D& g2, float x, float y) override; boxname(OvalBox); }; /** A box representing a wrapped box by shadowed frame */ class ShadowBox : public FramedBox { private: float _shadowRule; public: ShadowBox() = delete; ShadowBox(const sptr& fbox, float shadowRule) : FramedBox(fbox->_base, fbox->_thickness, fbox->_space) { _shadowRule = shadowRule; _depth += shadowRule; _width += shadowRule; } void draw(Graphics2D& g2, float x, float y) override; boxname(ShadowBox); }; /** A box representing 'wrapper' that with insets in left, top, right and bottom */ class WrapperBox : public DecorBox { private: float _l; color _fg = 0, _bg = 0; public: WrapperBox() = delete; WrapperBox(const sptr& base, float width, float rowheight, float rowdepth, Alignment align) : DecorBox(base), _l(0) { _height = rowheight; _depth = rowdepth; _width = width; if (base->_width < 0) _width += base->_width; if (align == Alignment::right) { _l = width - _base->_width; } else if (align == Alignment::center) { _l = (width - _base->_width) / 2.f; } } inline void setForeground(color fg) { _fg = fg; } inline void setBackground(color bg) { _bg = bg; } void addInsets(float l, float t, float r, float b); void draw(Graphics2D& g2, float x, float y) override; boxname(WrapperBox); }; } // namespace microtex #endif // MICROTEX_BOX_GROUP_H