// // Copyright (C) 2020-2022 David Cosgrove and other RDKit contributors // // @@ All Rights Reserved @@ // This file is part of the RDKit. // The contents are covered by the terms of the BSD license // which is included in the file license.txt, found at the root // of the RDKit source tree. // // // Original author: David Cosgrove (CozChemIx). // // This is an abstract base class for drawing text into a MolDraw2D // object. #ifndef RDKIT_DRAWTEXT_H #define RDKIT_DRAWTEXT_H #include #include #include #include #include #include using RDGeom::Point2D; namespace RDKit { class MolDraw2D; namespace MolDraw2D_detail { // for aligning the drawing of text to the passed in coords. enum class TextDrawType : unsigned char { TextDrawNormal = 0, TextDrawSuperscript, TextDrawSubscript }; std::ostream &operator<<(std::ostream &oss, const OrientType &o); std::ostream &operator<<(std::ostream &oss, const TextAlignType &tat); std::ostream &operator<<(std::ostream &oss, const TextDrawType &tdt); // **************************************************************************** // This is an implementation class, not intended to be used by the great // unwashed. If you want to draw a string used MolDraw2D::drawString(). class RDKIT_MOLDRAW2D_EXPORT DrawText { public: virtual ~DrawText() = 0; static constexpr double DEFAULT_FONT_SCALE = 0.6; // seems to be a good number DrawText(double max_fnt_sz, double min_fnt_sz); DrawText(const DrawText &) = delete; DrawText(DrawText &&) = delete; DrawText &operator=(const DrawText &) = delete; DrawText &operator=(DrawText &&) = delete; DrawColour const &colour() const; void setColour(const DrawColour &col); // size in "pixels" i.e scale() * base_font_size_. double fontSize() const; void setFontSize(double new_size); double baseFontSize() const; void setBaseFontSize(double new_size); double maxFontSize() const; void setMaxFontSize(double new_max); double minFontSize() const; void setMinFontSize(double new_max); double fontScale() const; // returns false if min or max font size is hit, true otherwise. // ignoreLimits ignores minFontSize and maxFontSize. bool setFontScale(double new_scale, bool ignoreLimits = false); // these are only relevant for the FreeType DrawText classes. virtual std::string getFontFile() const { return ""; } virtual void setFontFile(const std::string &font_file) { RDUNUSED_PARAM(font_file); } //! using the current scale, work out the size of the label /*! Bear in mind when implementing this, that, for example, NH2 will appear as NH2 to convey that the 2 is a subscript, and this needs to be accounted for in the width and height. */ virtual void getStringSize(const std::string &label, double &label_width, double &label_height) const; // returns the extremes of the label, in draw (pixel) coords. dontSplit // true suppresses the call to atomLabelToPieces. void getStringExtremes(const std::string &label, OrientType orient, double &x_min, double &y_min, double &x_max, double &y_max, bool dontSplit = false) const; // get the rectangles that go round each character of the string. If // dontSplit is false, it assumes it's an atom label and splits it // in a sensible way for that. If the OrientType is C, it applies // textAlign, otherwise the text is aligned set appropriately for the // OrientType. void getStringRects(const std::string &text, OrientType orient, std::vector> &rects, std::vector &draw_modes, std::vector &draw_chars, bool dontSplit = false, TextAlignType textAlign = TextAlignType::MIDDLE) const; //! drawString centres the string on cds. virtual void drawString(const std::string &str, const Point2D &cds, TextAlignType align); // Aligns them according to OrientType. This version assumes it's an // atomic symbol and calls atomLabelToPieces. This will behave // badly with general text. Surround the string with // if that's an issue, or use the version above. void drawString(const std::string &label, const Point2D &cds, OrientType orient); // put the label on end2, and then move end2 so that it is at // the intersection of a string rectangle and the line from end1 to // end2, if there is an intersection. Mostly for trimming bonds // back from atom labels. end1 and end2 in draw coords. void adjustLineForString(const std::string &label, OrientType orient, const Point2D &end1, Point2D &end2) const; // draw the char, with the bottom left hand corner at cds virtual void drawChar(char c, const Point2D &cds) = 0; // puts a colourful rectangle around each character in the string. // For debugging, mostly. void drawStringRects(const std::string &label, OrientType orient, TextAlignType talign, const Point2D &cds, MolDraw2D &mol_draw) const; // cds in draw coords // does the label at cds intersect the given StringRect. bool doesRectIntersect(const std::string &label, OrientType orient, const Point2D &cds, const StringRect &rect) const; // does the vector of StringRects, each translated by cds, intersect the // given StringRect. bool doesRectIntersect(const std::vector> &rects, const Point2D &cds, const StringRect &rect) const; bool doesLineIntersect(const std::string &label, OrientType orient, const Point2D &cds, const Point2D &end1, const Point2D &end2, double padding) const; bool doesLineIntersect(const std::vector> &rects, const Point2D &cds, const Point2D &end1, const Point2D &end2, double padding) const; bool doesStringIntersect( const std::vector> &rects, const Point2D &cds1, const std::string &label2, OrientType orient2, const Point2D &cds2) const; bool doesStringIntersect(const std::string &label1, OrientType orient1, const Point2D &cds1, const std::string &label2, OrientType orient2, const Point2D &cds2) const; virtual void alignString( TextAlignType align, const std::vector &draw_modes, std::vector> &rects) const; // adjust the string rectangles up and down for super- and subscripts void adjustStringRectsForSuperSubScript( const std::vector &draw_modes, std::vector> &rects) const; // return a scale factor appropriate for the character and draw type // (normal or super- or subscript) double selectScaleFactor(char c, TextDrawType draw_type) const; // amount to scale subscripts and superscripts by constexpr static double SUBS_SCALE = 0.66; constexpr static double SUPER_SCALE = 0.66; DrawColour colour_; double font_scale_; double max_font_size_; double min_font_size_; double base_font_size_ = DEFAULT_FONT_SCALE; // return a vector of StringRects, one for each char in text, with // super- and subscripts taken into account. Sizes in pixel coords, // i.e. scaled by fontScale(). virtual void getStringRects(const std::string &text, std::vector> &rects, std::vector &draw_modes, std::vector &draw_chars) const = 0; void drawChars(const Point2D &a_cds, const std::vector> &rects, const std::vector &draw_modes, const std::vector &draw_chars); }; //! establishes whether to put string draw mode into super- or sub-script //! mode based on contents of instring from i onwards. Increments i //! appropriately //! \returns true or false depending on whether it did something or not RDKIT_MOLDRAW2D_EXPORT bool setStringDrawMode(const std::string &instring, TextDrawType &draw_mode, size_t &i); // take the label for the given atom and return the individual pieces // that need to be drawn for it. So NH2 will return // "N", "H2". std::vector atomLabelToPieces(const std::string &label, OrientType orient); } // namespace MolDraw2D_detail } // namespace RDKit #endif // RDKIT_DRAWTEXT_H