mirror of https://github.com/KLayout/klayout.git
WIP: preparations - introducing TextInfo
This commit is contained in:
parent
7b4ff5d823
commit
e8048d6686
|
|
@ -101,17 +101,22 @@ hershey_count_edges (const std::string &s, unsigned int f)
|
||||||
HersheyFont *fp = fonts [f];
|
HersheyFont *fp = fonts [f];
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
|
||||||
for (const char *cp = s.c_str (); *cp; ++cp) {
|
for (const char *cp = s.c_str (); *cp; ) {
|
||||||
|
|
||||||
unsigned char c = (unsigned char) *cp;
|
if (tl::skip_newline (cp)) {
|
||||||
if (c == '\012' || c == '\015') {
|
|
||||||
if (c == '\015' && cp[1] == '\012') {
|
// skip new line - they don't contribute edges
|
||||||
++cp;
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
uint32_t c = tl::utf32_from_utf8 (cp);
|
||||||
|
|
||||||
|
if (c < fp->end_char && c >= fp->start_char) {
|
||||||
|
n += fp->chars [c - fp->start_char].edge_end - fp->chars [c - fp->start_char].edge_start;
|
||||||
|
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||||
|
n += fp->chars [invalid_char - fp->start_char].edge_end - fp->chars [invalid_char - fp->start_char].edge_start;
|
||||||
}
|
}
|
||||||
} else if (c < fp->end_char && c >= fp->start_char) {
|
|
||||||
n += fp->chars [c - fp->start_char].edge_end - fp->chars [c - fp->start_char].edge_start;
|
|
||||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
|
||||||
n += fp->chars [invalid_char - fp->start_char].edge_end - fp->chars [invalid_char - fp->start_char].edge_start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -142,22 +147,27 @@ hershey_text_box (const std::string &s, unsigned int f)
|
||||||
int w = 0;
|
int w = 0;
|
||||||
int h = fp->ymax;
|
int h = fp->ymax;
|
||||||
|
|
||||||
for (const char *cp = s.c_str (); *cp; ++cp) {
|
for (const char *cp = s.c_str (); *cp; ) {
|
||||||
|
|
||||||
|
if (tl::skip_newline (cp)) {
|
||||||
|
|
||||||
unsigned char c = (unsigned char) *cp;
|
|
||||||
if (c == '\012' || c == '\015') {
|
|
||||||
if (c == '\015' && cp[1] == '\012') {
|
|
||||||
++cp;
|
|
||||||
}
|
|
||||||
if (w > wl) {
|
if (w > wl) {
|
||||||
wl = w;
|
wl = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
hl += line_spacing + h - fp->ymin;
|
hl += line_spacing + h - fp->ymin;
|
||||||
w = 0;
|
w = 0;
|
||||||
} else if (c < fp->end_char && c >= fp->start_char) {
|
|
||||||
w += fp->chars [c - fp->start_char].width;
|
} else {
|
||||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
|
||||||
w += fp->chars [invalid_char - fp->start_char].width;
|
uint32_t c = tl::utf32_from_utf8 (cp);
|
||||||
|
|
||||||
|
if (c < fp->end_char && c >= fp->start_char) {
|
||||||
|
w += fp->chars [c - fp->start_char].width;
|
||||||
|
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||||
|
w += fp->chars [invalid_char - fp->start_char].width;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -179,20 +189,24 @@ hershey_justify (const std::string &s, unsigned int f, db::DBox bx, HAlign halig
|
||||||
int w = 0;
|
int w = 0;
|
||||||
int h = fp->ymax;
|
int h = fp->ymax;
|
||||||
|
|
||||||
for (const char *cp = s.c_str (); *cp; ++cp) {
|
for (const char *cp = s.c_str (); *cp; ) {
|
||||||
|
|
||||||
|
if (tl::skip_newline (cp)) {
|
||||||
|
|
||||||
unsigned char c = (unsigned char) *cp;
|
|
||||||
if (c == '\012' || c == '\015') {
|
|
||||||
if (c == '\015' && cp[1] == '\012') {
|
|
||||||
++cp;
|
|
||||||
}
|
|
||||||
linestarts.push_back (db::DPoint (w, -hl));
|
linestarts.push_back (db::DPoint (w, -hl));
|
||||||
hl += line_spacing + h - fp->ymin;
|
hl += line_spacing + h - fp->ymin;
|
||||||
w = 0;
|
w = 0;
|
||||||
} else if (c < fp->end_char && c >= fp->start_char) {
|
|
||||||
w += fp->chars [c - fp->start_char].width;
|
} else {
|
||||||
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
|
||||||
w += fp->chars [invalid_char - fp->start_char].width;
|
uint32_t c = tl::utf32_from_utf8 (cp);
|
||||||
|
|
||||||
|
if (c < fp->end_char && c >= fp->start_char) {
|
||||||
|
w += fp->chars [c - fp->start_char].width;
|
||||||
|
} else if (invalid_char < fp->end_char && invalid_char >= fp->start_char) {
|
||||||
|
w += fp->chars [invalid_char - fp->start_char].width;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -221,20 +235,18 @@ hershey_justify (const std::string &s, unsigned int f, db::DBox bx, HAlign halig
|
||||||
}
|
}
|
||||||
*l = p;
|
*l = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// basic_hershey_edge_iterator implementation
|
// basic_hershey_edge_iterator implementation
|
||||||
|
|
||||||
basic_hershey_edge_iterator::basic_hershey_edge_iterator (const std::string &s, unsigned int f, const std::vector<db::DPoint> &line_starts)
|
basic_hershey_edge_iterator::basic_hershey_edge_iterator (const std::string &s, unsigned int f, const std::vector<db::DPoint> &line_starts)
|
||||||
: m_line (0), m_string (s), m_edge (0), m_edge_end (0), m_index (0), m_linestarts (line_starts)
|
: m_line (0), m_string (s), m_edge (0), m_edge_end (0), m_linestarts (line_starts)
|
||||||
{
|
{
|
||||||
m_fp = fonts [f];
|
m_fp = fonts [f];
|
||||||
m_end = (unsigned int) m_string.size ();
|
mp_cp = m_string.c_str ();
|
||||||
m_new_char = true;
|
|
||||||
|
|
||||||
if (m_linestarts.size () == 0) {
|
if (m_linestarts.empty ()) {
|
||||||
m_linestarts.push_back (db::DPoint (0.0, 0.0));
|
m_linestarts.push_back (db::DPoint (0.0, 0.0));
|
||||||
}
|
}
|
||||||
m_pos = m_linestarts [0];
|
m_pos = m_linestarts [0];
|
||||||
|
|
@ -243,66 +255,47 @@ basic_hershey_edge_iterator::basic_hershey_edge_iterator (const std::string &s,
|
||||||
bool
|
bool
|
||||||
basic_hershey_edge_iterator::at_end () const
|
basic_hershey_edge_iterator::at_end () const
|
||||||
{
|
{
|
||||||
return m_index >= m_end;
|
return *mp_cp == 0 && m_edge == m_edge_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
db::DEdge
|
db::DEdge
|
||||||
basic_hershey_edge_iterator::get ()
|
basic_hershey_edge_iterator::get ()
|
||||||
{
|
{
|
||||||
while (m_new_char && !at_end ()) {
|
while (m_edge == m_edge_end && *mp_cp) {
|
||||||
|
|
||||||
unsigned char c = (unsigned char) (m_index < m_end ? m_string [m_index] : ' ');
|
|
||||||
|
|
||||||
m_pos += m_delta;
|
m_pos += m_delta;
|
||||||
|
|
||||||
if (c < m_fp->end_char && c >= m_fp->start_char) {
|
m_edge = m_edge_end = 0;
|
||||||
|
m_delta = db::DVector ();
|
||||||
|
|
||||||
m_edge = m_fp->chars [c - m_fp->start_char].edge_start;
|
if (tl::skip_newline (mp_cp)) {
|
||||||
m_edge_end = m_fp->chars [c - m_fp->start_char].edge_end;
|
|
||||||
m_delta = db::DVector (m_fp->chars [c - m_fp->start_char].width, 0);
|
|
||||||
|
|
||||||
} else if (c != '\012' && c != '\015'
|
++m_line;
|
||||||
&& invalid_char < m_fp->end_char
|
|
||||||
&& invalid_char >= m_fp->start_char) {
|
|
||||||
|
|
||||||
m_edge = m_fp->chars [invalid_char - m_fp->start_char].edge_start;
|
if (m_line >= m_linestarts.size ()) {
|
||||||
m_edge_end = m_fp->chars [invalid_char - m_fp->start_char].edge_end;
|
db::DPoint last;
|
||||||
m_delta = db::DVector (m_fp->chars [invalid_char - m_fp->start_char].width, 0);
|
last = m_linestarts.back ();
|
||||||
|
last += db::DVector (0, -(m_fp->ymax - m_fp->ymin + line_spacing));
|
||||||
|
m_linestarts.push_back (last);
|
||||||
|
}
|
||||||
|
m_pos = m_linestarts [m_line];
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
m_edge = m_edge_end = 0;
|
uint32_t c = tl::utf32_from_utf8 (mp_cp);
|
||||||
m_delta = db::DVector ();
|
|
||||||
|
|
||||||
}
|
if (c < m_fp->start_char || c >= m_fp->end_char) {
|
||||||
|
c = invalid_char;
|
||||||
if (m_edge == m_edge_end) {
|
|
||||||
|
|
||||||
if (c == '\012' || c == '\015') {
|
|
||||||
if (c == '\015' && m_string.size () > m_index + 1 && m_string [m_index] == '\012') {
|
|
||||||
++m_index;
|
|
||||||
}
|
|
||||||
++m_line;
|
|
||||||
if (m_line >= m_linestarts.size ()) {
|
|
||||||
m_linestarts.push_back (m_linestarts.back () + db::DVector (0.0, -(m_fp->ymax - m_fp->ymin + line_spacing)));
|
|
||||||
}
|
|
||||||
m_pos = m_linestarts [m_line];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++m_index;
|
if (c < m_fp->end_char && c >= m_fp->start_char) {
|
||||||
|
m_edge = m_fp->chars [c - m_fp->start_char].edge_start;
|
||||||
|
m_edge_end = m_fp->chars [c - m_fp->start_char].edge_end;
|
||||||
|
m_delta = db::DVector (m_fp->chars [c - m_fp->start_char].width, 0);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
m_new_char = false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
while (m_line >= m_linestarts.size ()) {
|
|
||||||
db::DPoint last;
|
|
||||||
if (m_linestarts.size () > 0) {
|
|
||||||
last = m_linestarts.back ();
|
|
||||||
last += db::DVector (0, -(m_fp->ymax - m_fp->ymin + line_spacing));
|
|
||||||
}
|
|
||||||
m_linestarts.push_back (last);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!at_end ()) {
|
if (!at_end ()) {
|
||||||
|
|
@ -316,16 +309,9 @@ basic_hershey_edge_iterator::get ()
|
||||||
void
|
void
|
||||||
basic_hershey_edge_iterator::inc ()
|
basic_hershey_edge_iterator::inc ()
|
||||||
{
|
{
|
||||||
if (m_new_char) {
|
|
||||||
get ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! at_end ()) {
|
if (! at_end ()) {
|
||||||
++m_edge;
|
++m_edge;
|
||||||
if (m_edge == m_edge_end) {
|
get ();
|
||||||
++m_index;
|
|
||||||
m_new_char = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,10 @@ public:
|
||||||
void inc ();
|
void inc ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_new_char;
|
|
||||||
unsigned int m_line;
|
unsigned int m_line;
|
||||||
|
const char *mp_cp;
|
||||||
std::string m_string;
|
std::string m_string;
|
||||||
unsigned int m_edge, m_edge_end;
|
unsigned int m_edge, m_edge_end;
|
||||||
unsigned int m_index, m_end;
|
|
||||||
std::vector<db::DPoint> m_linestarts;
|
std::vector<db::DPoint> m_linestarts;
|
||||||
db::DPoint m_pos;
|
db::DPoint m_pos;
|
||||||
db::DVector m_delta;
|
db::DVector m_delta;
|
||||||
|
|
@ -177,14 +176,16 @@ struct DB_PUBLIC_TEMPLATE hershey
|
||||||
/**
|
/**
|
||||||
* @brief Obtain the size of the text
|
* @brief Obtain the size of the text
|
||||||
*
|
*
|
||||||
* @return The bounding box of the text with the scaling applied
|
* @return The bounding box of the text with the scaling and justification applied
|
||||||
*/
|
*/
|
||||||
box<C> bbox () const
|
db::DBox bbox () const
|
||||||
{
|
{
|
||||||
db::DBox b = hershey_text_box (m_string, m_font);
|
db::DBox b = hershey_text_box (m_string, m_font) * (1.0 / m_scale);
|
||||||
db::point<C> p1 (coord_traits::rounded (b.p1 ().x () / m_scale), coord_traits::rounded (b.p1 ().y () / m_scale));
|
if (! m_linestarts.empty ()) {
|
||||||
db::point<C> p2 (coord_traits::rounded (b.p2 ().x () / m_scale), coord_traits::rounded (b.p2 ().y () / m_scale));
|
return b.moved (m_linestarts.front () - db::DPoint ());
|
||||||
return box<C> (p1, p2);
|
} else {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -791,35 +791,6 @@ Bitmap::render_contour (std::vector<lay::RenderEdge> &edges)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char next_char_latin1_from_utf8 (const char *&cp, const char *cpf = 0)
|
|
||||||
{
|
|
||||||
unsigned char c = *cp;
|
|
||||||
if ((c & 0xe0) == 0xc0) {
|
|
||||||
if ((cp[1] & 0xc0) == 0x80 && (! cpf || cpf > cp + 1)) {
|
|
||||||
unsigned int x = ((unsigned int) ((unsigned char) c & 0x1f) << 6) | (unsigned int) (cp[1] & 0x3f);
|
|
||||||
cp += 1;
|
|
||||||
if (x < 255) {
|
|
||||||
c = x;
|
|
||||||
} else {
|
|
||||||
c = '?';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c = '?';
|
|
||||||
}
|
|
||||||
} else if ((c & 0xf0) == 0xe0) {
|
|
||||||
if ((cp[1] & 0xc0) == 0x80 && (cp[2] & 0xc0) == 0x80 && (! cpf || cpf > cp + 2)) {
|
|
||||||
cp += 2;
|
|
||||||
}
|
|
||||||
c = '?';
|
|
||||||
} else if ((c & 0xf8) == 0xf0) {
|
|
||||||
if ((cp[1] & 0xc0) == 0x80 && (cp[2] & 0xc0) == 0x80 && (cp[3] & 0xc0) == 0x80 && (! cpf || cpf > cp + 3)) {
|
|
||||||
cp += 3;
|
|
||||||
}
|
|
||||||
c = '?';
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Bitmap::render_text (const lay::RenderText &text)
|
Bitmap::render_text (const lay::RenderText &text)
|
||||||
{
|
{
|
||||||
|
|
@ -830,12 +801,11 @@ Bitmap::render_text (const lay::RenderText &text)
|
||||||
// count the lines and max. characters per line
|
// count the lines and max. characters per line
|
||||||
|
|
||||||
unsigned int lines = 1;
|
unsigned int lines = 1;
|
||||||
for (const char *cp = text.text.c_str (); *cp; ++cp) {
|
for (const char *cp = text.text.c_str (); *cp; ) {
|
||||||
if (*cp == '\012' || *cp == '\015') {
|
if (tl::skip_newline (cp)) {
|
||||||
if (*cp == '\015' && cp[1] == '\012') {
|
|
||||||
++cp;
|
|
||||||
}
|
|
||||||
++lines;
|
++lines;
|
||||||
|
} else {
|
||||||
|
++cp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -858,10 +828,9 @@ Bitmap::render_text (const lay::RenderText &text)
|
||||||
|
|
||||||
unsigned int length = 0;
|
unsigned int length = 0;
|
||||||
const char *cp = cp1;
|
const char *cp = cp1;
|
||||||
while (*cp && *cp != '\012' && *cp != '\015') {
|
while (*cp && !tl::is_newline (*cp)) {
|
||||||
next_char_latin1_from_utf8 (cp);
|
tl::utf32_from_utf8 (cp);
|
||||||
++length;
|
++length;
|
||||||
++cp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double xx;
|
double xx;
|
||||||
|
|
@ -880,11 +849,13 @@ Bitmap::render_text (const lay::RenderText &text)
|
||||||
|
|
||||||
for ( ; cp1 != cp; ++cp1) {
|
for ( ; cp1 != cp; ++cp1) {
|
||||||
|
|
||||||
unsigned char c = next_char_latin1_from_utf8 (cp1, cp);
|
uint32_t c = tl::utf32_from_utf8 (cp1, cp);
|
||||||
|
if (c < uint32_t (ff.first_char ()) || c >= uint32_t (ff.n_chars ()) + ff.first_char ()) {
|
||||||
|
// NOTE: '?' needs to be a valid character always
|
||||||
|
c = uint32_t ('?');
|
||||||
|
}
|
||||||
|
|
||||||
size_t cc = c; // to suppress a compiler warning ..
|
if (xx > -100.0 && xx < double (width ())) {
|
||||||
if (c >= ff.first_char () && cc < size_t (ff.n_chars ()) + size_t (ff.first_char ())
|
|
||||||
&& xx > -100.0 && xx < double (width ())) {
|
|
||||||
fill_pattern (int (y + 0.5), int (floor (xx)), ff.data () + (c - ff.first_char ()) * ff.height () * ff.stride (), ff.stride (), ff.height ());
|
fill_pattern (int (y + 0.5), int (floor (xx)), ff.data () + (c - ff.first_char ()) * ff.height () * ff.stride (), ff.stride (), ff.height ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -897,11 +868,7 @@ Bitmap::render_text (const lay::RenderText &text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// next line
|
// next line
|
||||||
if (*cp1 == '\012' || *cp1 == '\015') {
|
if (tl::skip_newline (cp1)) {
|
||||||
if (*cp1 == '\015' && cp1[1] == '\012') {
|
|
||||||
++cp1;
|
|
||||||
}
|
|
||||||
++cp1;
|
|
||||||
y -= double (ff.line_height ());
|
y -= double (ff.line_height ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -894,5 +894,5 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace edt
|
} // namespace lay
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -320,6 +320,11 @@ public:
|
||||||
return m_line_styles;
|
return m_line_styles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reimplementation of ViewObjectCanvas: Resolution
|
||||||
|
*/
|
||||||
|
double resolution () const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reimplementation of ViewObjectCanvas: Background color
|
* @brief Reimplementation of ViewObjectCanvas: Background color
|
||||||
*/
|
*/
|
||||||
|
|
@ -444,8 +449,6 @@ private:
|
||||||
void do_redraw_all (bool force_redraw = true);
|
void do_redraw_all (bool force_redraw = true);
|
||||||
|
|
||||||
void prepare_drawing ();
|
void prepare_drawing ();
|
||||||
virtual double resolution () const;
|
|
||||||
|
|
||||||
const std::vector<ViewOp> &scaled_view_ops (unsigned int lw);
|
const std::vector<ViewOp> &scaled_view_ops (unsigned int lw);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1721,6 +1721,14 @@ public:
|
||||||
return mp_canvas;
|
return mp_canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the canvas object (const version)
|
||||||
|
*/
|
||||||
|
const lay::LayoutCanvas *canvas () const
|
||||||
|
{
|
||||||
|
return mp_canvas;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
/**
|
/**
|
||||||
* @brief Gets the layer control panel
|
* @brief Gets the layer control panel
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2023 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "layTextInfo.h"
|
||||||
|
#include "layFixedFont.h"
|
||||||
|
#include "layLayoutViewBase.h"
|
||||||
|
#include "layLayoutCanvas.h"
|
||||||
|
|
||||||
|
namespace lay
|
||||||
|
{
|
||||||
|
|
||||||
|
TextInfo::TextInfo (const LayoutViewBase *view, const db::DCplxTrans &vp_trans)
|
||||||
|
: m_default_text_size (view->default_text_size ()),
|
||||||
|
m_default_font (db::Font (view->text_font ())),
|
||||||
|
m_apply_text_trans (view->apply_text_trans ()),
|
||||||
|
m_resolution (view->canvas ()->resolution ()),
|
||||||
|
m_vp_trans (vp_trans)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
TextInfo::TextInfo (double default_text_size, const db::Font &default_font, bool apply_text_trans, double resolution, const db::DCplxTrans &vp_trans)
|
||||||
|
: m_default_text_size (default_text_size),
|
||||||
|
m_default_font (default_font),
|
||||||
|
m_apply_text_trans (apply_text_trans),
|
||||||
|
m_resolution (resolution),
|
||||||
|
m_vp_trans (vp_trans)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
db::DBox
|
||||||
|
TextInfo::get_bbox (const db::DText &text) const
|
||||||
|
{
|
||||||
|
// offset in pixels (space between origin and text)
|
||||||
|
const double offset = 2.0;
|
||||||
|
|
||||||
|
db::DFTrans fp (db::DFTrans::r0);
|
||||||
|
db::DCoord h;
|
||||||
|
db::Font font = text.font () == db::NoFont ? m_default_font : text.font ();
|
||||||
|
|
||||||
|
if (m_apply_text_trans && font != db::NoFont && font != db::DefaultFont) {
|
||||||
|
fp = db::DFTrans (m_vp_trans.fp_trans () * text.trans ().fp_trans ());
|
||||||
|
h = m_vp_trans.ctrans (text.size () > 0 ? text.size () : m_default_text_size);
|
||||||
|
} else {
|
||||||
|
h = m_vp_trans.ctrans (m_default_text_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
db::HAlign halign = text.halign ();
|
||||||
|
db::VAlign valign = text.valign ();
|
||||||
|
|
||||||
|
double fy = 0.0;
|
||||||
|
if (valign == db::VAlignBottom || valign == db::NoVAlign) {
|
||||||
|
fy = 1.0;
|
||||||
|
} else if (valign == db::VAlignTop) {
|
||||||
|
fy = -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double fx = 0.0;
|
||||||
|
if (halign == db::HAlignLeft || halign == db::NoHAlign) {
|
||||||
|
fx = 1.0;
|
||||||
|
} else if (halign == db::HAlignRight) {
|
||||||
|
fx = -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
db::DVector tp1 (fx * offset, fy * offset + (fy - 1) * 0.5 * h);
|
||||||
|
db::DVector tp2 (fx * offset, fy * offset + (fy + 1) * 0.5 * h);
|
||||||
|
db::DPoint dp = db::DPoint () + text.trans ().disp ();
|
||||||
|
|
||||||
|
db::DBox b (dp + fp (tp1), dp + fp (tp2));
|
||||||
|
|
||||||
|
if (font == db::DefaultFont) {
|
||||||
|
|
||||||
|
const lay::FixedFont &ff = lay::FixedFont::get_font (m_resolution);
|
||||||
|
|
||||||
|
// count the lines
|
||||||
|
|
||||||
|
unsigned int lines = 1;
|
||||||
|
for (const char *cp = text.string (); *cp; ) {
|
||||||
|
if (tl::skip_newline (cp)) {
|
||||||
|
++lines;
|
||||||
|
} else {
|
||||||
|
tl::utf32_from_utf8 (cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the actual top left position
|
||||||
|
double ytop;
|
||||||
|
if (valign == db::VAlignBottom || valign == db::NoVAlign) {
|
||||||
|
ytop = b.bottom ();
|
||||||
|
ytop += double (ff.line_height () * (lines - 1) + ff.height ());
|
||||||
|
} else if (valign == db::VAlignCenter) {
|
||||||
|
ytop = b.center ().y ();
|
||||||
|
ytop += double ((ff.line_height () * (lines - 1) + ff.height ()) / 2);
|
||||||
|
} else {
|
||||||
|
ytop = b.top ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the bottom position
|
||||||
|
double ybottom = ytop - ff.line_height () * (lines - 1);
|
||||||
|
|
||||||
|
// left and right position
|
||||||
|
bool first = false;
|
||||||
|
double xleft = 0.0, xright = 0.0;
|
||||||
|
|
||||||
|
const char *cp = text.string ();
|
||||||
|
while (*cp) {
|
||||||
|
|
||||||
|
unsigned int length = 0;
|
||||||
|
while (*cp && !tl::skip_newline (cp)) {
|
||||||
|
tl::utf32_from_utf8 (cp);
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
|
||||||
|
double xl;
|
||||||
|
if (halign == db::HAlignRight) {
|
||||||
|
xl = b.right ();
|
||||||
|
xl -= double (ff.width () * length);
|
||||||
|
} else if (halign == db::HAlignCenter) {
|
||||||
|
xl = b.center ().x ();
|
||||||
|
xl -= double (ff.width () * length / 2);
|
||||||
|
} else {
|
||||||
|
xl = b.left ();
|
||||||
|
}
|
||||||
|
xl -= 0.5;
|
||||||
|
|
||||||
|
double xr = xl + double (ff.width () * length);
|
||||||
|
|
||||||
|
if (first || xl < xleft) {
|
||||||
|
xleft = xl;
|
||||||
|
}
|
||||||
|
if (first || xr > xright) {
|
||||||
|
xright = xr;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return db::DBox (xleft, ybottom, xright, ytop).transformed (m_vp_trans.inverted ());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
db::DHershey ht (text.string (), font);
|
||||||
|
ht.justify (b.transformed (m_vp_trans.inverted ()), halign, valign);
|
||||||
|
return ht.bbox ();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2023 Matthias Koefferlein
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_layTextInfo
|
||||||
|
#define HDR_layTextInfo
|
||||||
|
|
||||||
|
#include "laybasicCommon.h"
|
||||||
|
|
||||||
|
#include "dbText.h"
|
||||||
|
#include "dbBox.h"
|
||||||
|
|
||||||
|
namespace lay
|
||||||
|
{
|
||||||
|
|
||||||
|
class LayoutViewBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A class providing information about a text's visual bounding box
|
||||||
|
*
|
||||||
|
* The class can act as a BoxConverter.
|
||||||
|
*/
|
||||||
|
class LAYBASIC_PUBLIC TextInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*
|
||||||
|
* @param view The LayoutView from which to take the text display parameters
|
||||||
|
* @param vp_trans The effective micron-to-pixel transformation
|
||||||
|
*/
|
||||||
|
TextInfo (const LayoutViewBase *view, const db::DCplxTrans &vp_trans);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*
|
||||||
|
* @param default_text_size The default text size in micron
|
||||||
|
* @param default_font The default font
|
||||||
|
* @param apply_text_trans True if text transformations are to be applied
|
||||||
|
* @param resolution The resolution value (logical pixel size per physical unit pixel)
|
||||||
|
* @param vp_trans The effective micron-to-pixel transformation
|
||||||
|
*/
|
||||||
|
TextInfo (double default_text_size, const db::Font &default_font, bool apply_text_trans, double resolution, const db::DCplxTrans &vp_trans);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the visual bounding box of the given DText object
|
||||||
|
*
|
||||||
|
* The visual bounding box is returned in micrometer units.
|
||||||
|
* It encloses the glyphs of the text, taking into account the
|
||||||
|
* text view settings by the view.
|
||||||
|
*/
|
||||||
|
db::DBox operator() (const db::DText &text) const
|
||||||
|
{
|
||||||
|
return get_bbox (text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
double m_default_text_size;
|
||||||
|
db::Font m_default_font;
|
||||||
|
bool m_apply_text_trans;
|
||||||
|
double m_resolution;
|
||||||
|
db::DCplxTrans m_vp_trans;
|
||||||
|
|
||||||
|
db::DBox get_bbox (const db::DText &text) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -52,6 +52,7 @@ SOURCES += \
|
||||||
layEditable.cc \
|
layEditable.cc \
|
||||||
layEditorServiceBase.cc \
|
layEditorServiceBase.cc \
|
||||||
layFinder.cc \
|
layFinder.cc \
|
||||||
|
layTextInfo.cc \
|
||||||
layFixedFont.cc \
|
layFixedFont.cc \
|
||||||
layLayoutCanvas.cc \
|
layLayoutCanvas.cc \
|
||||||
layLineStylePalette.cc \
|
layLineStylePalette.cc \
|
||||||
|
|
@ -104,6 +105,7 @@ HEADERS += \
|
||||||
layEditorServiceBase.h \
|
layEditorServiceBase.h \
|
||||||
layLayoutCanvas.h \
|
layLayoutCanvas.h \
|
||||||
layFinder.h \
|
layFinder.h \
|
||||||
|
layTextInfo.h \
|
||||||
layFixedFont.h \
|
layFixedFont.h \
|
||||||
layLayoutViewBase.h \
|
layLayoutViewBase.h \
|
||||||
layLineStylePalette.h \
|
layLineStylePalette.h \
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,22 @@ inline bool safe_isspace (char c)
|
||||||
return c != 0 && static_cast<unsigned char> (c) < 0x80 && isspace (c);
|
return c != 0 && static_cast<unsigned char> (c) < 0x80 && isspace (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Utility: skip a newline
|
||||||
|
|
||||||
|
bool skip_newline (const char *&cp)
|
||||||
|
{
|
||||||
|
if (*cp == '\012' || *cp == '\015') {
|
||||||
|
if (*cp == '\015' && cp[1] == '\012') {
|
||||||
|
++cp;
|
||||||
|
}
|
||||||
|
++cp;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Utility: a strtod version that is independent of the locale
|
// Utility: a strtod version that is independent of the locale
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -987,6 +987,37 @@ TL_PUBLIC uint32_t utf32_upcase (uint32_t c32);
|
||||||
*/
|
*/
|
||||||
TL_PUBLIC uint32_t utf32_from_utf8 (const char *&cp, const char *cpe = 0);
|
TL_PUBLIC uint32_t utf32_from_utf8 (const char *&cp, const char *cpe = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the next characters are CR, LF or CR+LF and skips them
|
||||||
|
*
|
||||||
|
* This function returns true, if a line separated was found and skipped
|
||||||
|
*/
|
||||||
|
TL_PUBLIC bool skip_newline (const char *&cp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief checks if the given character is a CR character
|
||||||
|
*/
|
||||||
|
inline bool is_cr (char c)
|
||||||
|
{
|
||||||
|
return c == '\015';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief checks if the given character is a LF character
|
||||||
|
*/
|
||||||
|
inline bool is_lf (char c)
|
||||||
|
{
|
||||||
|
return c == '\012';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief checks if the given character is a CR or LF character
|
||||||
|
*/
|
||||||
|
inline bool is_newline (char c)
|
||||||
|
{
|
||||||
|
return is_cr (c) || is_lf (c);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tl
|
} // namespace tl
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue