]> git.lyx.org Git - features.git/blob - src/insets/InsetNewline.cpp
Improve row flushing
[features.git] / src / insets / InsetNewline.cpp
1 /**
2  * \file InsetNewline.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "InsetNewline.h"
15
16 #include "Cursor.h"
17 #include "Dimension.h"
18 #include "FuncRequest.h"
19 #include "FuncStatus.h"
20 #include "Lexer.h"
21 #include "MetricsInfo.h"
22 #include "output_docbook.h"
23 #include "output_xhtml.h"
24 #include "texstream.h"
25
26 #include "frontends/Application.h"
27 #include "frontends/FontMetrics.h"
28 #include "frontends/Painter.h"
29
30 #include "support/debug.h"
31 #include "support/docstream.h"
32 #include "support/docstring.h"
33
34 using namespace std;
35
36 namespace lyx {
37
38 InsetNewline::InsetNewline() : Inset(nullptr)
39 {}
40
41
42 int InsetNewline::rowFlags() const
43 {
44         if (params_.kind == InsetNewlineParams::LINEBREAK)
45                 return AlwaysBreakAfter;
46         else
47             return AlwaysBreakAfter | Flush;
48 }
49
50
51 void InsetNewlineParams::write(ostream & os) const
52 {
53         switch (kind) {
54         case InsetNewlineParams::NEWLINE:
55                 os << "newline";
56                 break;
57         case InsetNewlineParams::LINEBREAK:
58                 os <<  "linebreak";
59                 break;
60         }
61 }
62
63
64 void InsetNewlineParams::read(Lexer & lex)
65 {
66         string token;
67         lex.setContext("InsetNewlineParams::read");
68         lex >> token;
69         if (token == "newline")
70                 kind = InsetNewlineParams::NEWLINE;
71         else if (token == "linebreak")
72                 kind = InsetNewlineParams::LINEBREAK;
73         else
74                 lex.printError("Unknown kind: `$$Token'");
75 }
76
77
78 void InsetNewline::write(ostream & os) const
79 {
80         os << "Newline ";
81         params_.write(os);
82 }
83
84
85 void InsetNewline::read(Lexer & lex)
86 {
87         params_.read(lex);
88         lex >> "\\end_inset";
89 }
90
91
92 void InsetNewline::metrics(MetricsInfo & mi, Dimension & dim) const
93 {
94         frontend::FontMetrics const & fm = theFontMetrics(mi.base.font);
95         dim.asc = fm.maxAscent();
96         dim.des = fm.maxDescent();
97         dim.wid = fm.width('n');
98 }
99
100
101 void InsetNewline::doDispatch(Cursor & cur, FuncRequest & cmd)
102 {
103         switch (cmd.action()) {
104
105         case LFUN_INSET_MODIFY: {
106                 InsetNewlineParams params;
107                 cur.recordUndo();
108                 string2params(to_utf8(cmd.argument()), params);
109                 params_.kind = params.kind;
110                 break;
111         }
112
113         default:
114                 Inset::doDispatch(cur, cmd);
115                 break;
116         }
117 }
118
119
120 bool InsetNewline::getStatus(Cursor & cur, FuncRequest const & cmd,
121         FuncStatus & status) const
122 {
123         switch (cmd.action()) {
124         // we handle these
125         case LFUN_INSET_MODIFY:
126                 if (cmd.getArg(0) == "newline") {
127                         InsetNewlineParams params;
128                         string2params(to_utf8(cmd.argument()), params);
129                         status.setOnOff(params_.kind == params.kind);
130                 }
131                 status.setEnabled(true);
132                 return true;
133         default:
134                 return Inset::getStatus(cur, cmd, status);
135         }
136 }
137
138
139 ColorCode InsetNewline::ColorName() const
140 {
141         switch (params_.kind) {
142                 case InsetNewlineParams::NEWLINE:
143                         return Color_eolmarker;
144                         break;
145                 case InsetNewlineParams::LINEBREAK:
146                         return Color_pagebreak;
147                         break;
148         }
149         // not really useful, but to avoids gcc complaints
150         return Color_eolmarker;
151 }
152
153
154 void InsetNewline::latex(otexstream & os, OutputParams const & rp) const
155 {
156         switch (params_.kind) {
157                 case InsetNewlineParams::NEWLINE:
158                         if (!rp.newlinecmd.empty())
159                                 os << "\\" << rp.newlinecmd << "\n";
160                         else if (rp.inTableCell == OutputParams::PLAIN)
161                                 os << "\\newline\n";
162                         else
163                                 os << "\\\\\n";
164                         break;
165                 case InsetNewlineParams::LINEBREAK:
166                         os << "\\linebreak{}\n";
167                         break;
168                 default:
169                         os << "\\\\\n";
170                         break;
171         }
172 }
173
174
175 int InsetNewline::plaintext(odocstringstream & os,
176         OutputParams const &, size_t) const
177 {
178         os << '\n';
179         return PLAINTEXT_NEWLINE;
180 }
181
182
183 void InsetNewline::docbook(XMLStream &, OutputParams const &) const
184 {
185         // New lines are handled by Paragraph::simpleDocBookOnePar.
186 }
187
188
189 docstring InsetNewline::xhtml(XMLStream & xs, OutputParams const &) const
190 {
191         xs << xml::CR() << xml::CompTag("br") << xml::CR();
192         return docstring();
193 }
194
195
196 void InsetNewline::draw(PainterInfo & pi, int x, int y) const
197 {
198         FontInfo font;
199         font.setColor(ColorName());
200
201         frontend::FontMetrics const & fm = theFontMetrics(pi.base.font);
202         int const wid = fm.width('n');
203         int const asc = fm.maxAscent();
204
205         int xp[3];
206         int yp[3];
207
208         yp[0] = int(y - 0.875 * asc * 0.75);
209         yp[1] = int(y - 0.500 * asc * 0.75);
210         yp[2] = int(y - 0.125 * asc * 0.75);
211
212         if (pi.ltr_pos) {
213                 xp[0] = int(x + wid * 0.375);
214                 xp[1] = int(x);
215                 xp[2] = int(x + wid * 0.375);
216         } else {
217                 xp[0] = int(x + wid * 0.625);
218                 xp[1] = int(x + wid);
219                 xp[2] = int(x + wid * 0.625);
220         }
221
222         pi.pain.lines(xp, yp, 3, ColorName());
223
224         yp[0] = int(y - 0.500 * asc * 0.75);
225         yp[1] = int(y - 0.500 * asc * 0.75);
226         yp[2] = int(y - asc * 0.75);
227
228         if (pi.ltr_pos) {
229                 xp[0] = int(x);
230                 xp[1] = int(x + wid);
231                 xp[2] = int(x + wid);
232         } else {
233                 xp[0] = int(x + wid);
234                 xp[1] = int(x);
235                 xp[2] = int(x);
236         }
237
238         pi.pain.lines(xp, yp, 3, ColorName());
239
240         if (params_.kind == InsetNewlineParams::LINEBREAK) {
241
242                 yp[2] = int(y - 0.500 * asc * 0.75);
243
244                 if (pi.ltr_pos) {
245                         xp[0] = int(x + 1.3 * wid);
246                         xp[1] = int(x + 2 * wid);
247                         xp[2] = int(x + 2 * wid);
248                 } else {
249                         xp[0] = int(x - 0.3 * wid);
250                         xp[1] = int(x - wid);
251                         xp[2] = int(x - wid);
252                 }
253                 pi.pain.lines(xp, yp, 3, ColorName());
254
255                 yp[0] = int(y - 0.875 * asc * 0.75);
256                 yp[1] = int(y - 0.500 * asc * 0.75);
257                 yp[2] = int(y - 0.125 * asc * 0.75);
258
259                 if (pi.ltr_pos) {
260                         xp[0] = int(x + 2 * wid * 0.813);
261                         xp[1] = int(x + 2 * wid);
262                         xp[2] = int(x + 2 * wid * 0.813);
263                 } else {
264                         xp[0] = int(x - wid * 0.625);
265                         xp[1] = int(x - wid);
266                         xp[2] = int(x - wid * 0.625);
267                 }
268                 pi.pain.lines(xp, yp, 3, ColorName());
269         }
270 }
271
272
273 string InsetNewline::contextMenuName() const
274 {
275         return "context-newline";
276 }
277
278
279 void InsetNewline::string2params(string const & in, InsetNewlineParams & params)
280 {
281         params = InsetNewlineParams();
282         if (in.empty())
283                 return;
284         istringstream data(in);
285         Lexer lex;
286         lex.setStream(data);
287         lex.setContext("InsetNewline::string2params");
288         lex >> "newline";
289         params.read(lex);
290 }
291
292
293 string InsetNewline::params2string(InsetNewlineParams const & params)
294 {
295         ostringstream data;
296         data << "newline" << ' ';
297         params.write(data);
298         return data.str();
299 }
300
301
302 } // namespace lyx