diff options
author | Alexander Köplinger <alex.koeplinger@outlook.com> | 2020-01-28 18:26:36 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-28 18:26:36 +0300 |
commit | 726a9134c8523f849cb265000c27ed3c5b426d19 (patch) | |
tree | 517f5494c7f1237fadc3b2f96ab13551d41015f0 /mcs | |
parent | 4b4b29745058c4f0e3f2151902f031ca67cd7d01 (diff) | |
parent | b87c271b6f2d650187e36e58f87e71d70693c89c (diff) |
Merge pull request #18491 from PreferLinux/RTF+Textbox-work
I've implemented a heap of missing RTF and RichTextBox stuff, and also made some improvements or fixes to various aspects of it. I'm sorry this is so big...
To give an overview of the changes, here's a list:
- Removed the RTF Charcode / Charset handling that wasn't actually used, had a lot of missing functionality and was basically reimplementing character encoding handling, and replaced it with ensuring the correct character encoding is being used (changing when needed).
- Improved RTF handling of objects with object results (process the given object result). Sometimes pictures can be like this.
- Improved line wrapping and alignment
- Added or greatly improved support for:
- paragraph spacing
- line spacing
- paragraph indents (left, right, hanging)
- tabstops (left, centre, right, decimal)
- text background colour (like highlighting)
- superscript / subscript
- character offset (vertical)
- text visibility
- Significantly improved RichTextBox RTF generation
- Cache DPI, rather than doing `CreateGraphics()` every time it is needed
- A variety of other fixes and improvements, with a few I can think of relating to:
- caret position
- replacing text
- invalidation and drawing
- when tags are added or deleted
Diffstat (limited to 'mcs')
20 files changed, 2382 insertions, 2384 deletions
diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charcode.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charcode.cs deleted file mode 100644 index fc9ca63b12e..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charcode.cs +++ /dev/null @@ -1,413 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// COMPLETE - -using System.Collections; - -namespace System.Windows.Forms.RTF { - internal class Charcode { - #region Local Variables - private StandardCharCode[] codes; - private Hashtable reverse; - private int size; - #endregion // Local Variables - - #region Cached Values - static Charcode ansi_generic; - #endregion - - #region Public Constructors - public Charcode() : this(256) { - } - - private Charcode(int size) { - this.size = size; - this.codes = new StandardCharCode[size]; - this.reverse = new Hashtable(size); - - // No need to reinitialize array to its default value - //for (int i = 0; i < size; i++) { - // codes[i] = StandardCharCode.nothing; - //} - } - #endregion // Public Constructors - - #region Public Instance Properties - public int this[StandardCharCode c] { - get { - object obj; - - obj = reverse[c]; - if (obj != null) { - return (int)obj; - } - for (int i = 0; i < size; i++) { - if (codes[i] == c) { - return i; - } - } - - return -1; - } - } - - public StandardCharCode this[int c] { - get { - if (c < 0 || c >= size) { - return StandardCharCode.nothing; - } - - return codes[c]; - } - - private set { - if (c < 0 || c >= size) { - return; - } - - codes[c] = value; - reverse[value] = c; - } - } - #endregion // Public Instance Properties - - #region Public Instance Methods - #endregion // Public Instance Methods - - #region Public Static Methods - public static Charcode AnsiGeneric { - get { - if (ansi_generic != null) - return ansi_generic; - - ansi_generic = new Charcode(256); - - ansi_generic[0x06] = StandardCharCode.formula; - ansi_generic[0x1e] = StandardCharCode.nobrkhyphen; - ansi_generic[0x1f] = StandardCharCode.opthyphen; - ansi_generic[' '] = StandardCharCode.space; - ansi_generic['!'] = StandardCharCode.exclam; - ansi_generic['"'] = StandardCharCode.quotedbl; - ansi_generic['#'] = StandardCharCode.numbersign; - ansi_generic['$'] = StandardCharCode.dollar; - ansi_generic['%'] = StandardCharCode.percent; - ansi_generic['&'] = StandardCharCode.ampersand; - ansi_generic['\\'] = StandardCharCode.quoteright; - ansi_generic['('] = StandardCharCode.parenleft; - ansi_generic[')'] = StandardCharCode.parenright; - ansi_generic['*'] = StandardCharCode.asterisk; - ansi_generic['+'] = StandardCharCode.plus; - ansi_generic[','] = StandardCharCode.comma; - ansi_generic['-'] = StandardCharCode.hyphen; - ansi_generic['.'] = StandardCharCode.period; - ansi_generic['/'] = StandardCharCode.slash; - ansi_generic['0'] = StandardCharCode.zero; - ansi_generic['1'] = StandardCharCode.one; - ansi_generic['2'] = StandardCharCode.two; - ansi_generic['3'] = StandardCharCode.three; - ansi_generic['4'] = StandardCharCode.four; - ansi_generic['5'] = StandardCharCode.five; - ansi_generic['6'] = StandardCharCode.six; - ansi_generic['7'] = StandardCharCode.seven; - ansi_generic['8'] = StandardCharCode.eight; - ansi_generic['9'] = StandardCharCode.nine; - ansi_generic[':'] = StandardCharCode.colon; - ansi_generic[';'] = StandardCharCode.semicolon; - ansi_generic['<'] = StandardCharCode.less; - ansi_generic['='] = StandardCharCode.equal; - ansi_generic['>'] = StandardCharCode.greater; - ansi_generic['?'] = StandardCharCode.question; - ansi_generic['@'] = StandardCharCode.at; - ansi_generic['A'] = StandardCharCode.A; - ansi_generic['B'] = StandardCharCode.B; - ansi_generic['C'] = StandardCharCode.C; - ansi_generic['D'] = StandardCharCode.D; - ansi_generic['E'] = StandardCharCode.E; - ansi_generic['F'] = StandardCharCode.F; - ansi_generic['G'] = StandardCharCode.G; - ansi_generic['H'] = StandardCharCode.H; - ansi_generic['I'] = StandardCharCode.I; - ansi_generic['J'] = StandardCharCode.J; - ansi_generic['K'] = StandardCharCode.K; - ansi_generic['L'] = StandardCharCode.L; - ansi_generic['M'] = StandardCharCode.M; - ansi_generic['N'] = StandardCharCode.N; - ansi_generic['O'] = StandardCharCode.O; - ansi_generic['P'] = StandardCharCode.P; - ansi_generic['Q'] = StandardCharCode.Q; - ansi_generic['R'] = StandardCharCode.R; - ansi_generic['S'] = StandardCharCode.S; - ansi_generic['T'] = StandardCharCode.T; - ansi_generic['U'] = StandardCharCode.U; - ansi_generic['V'] = StandardCharCode.V; - ansi_generic['W'] = StandardCharCode.W; - ansi_generic['X'] = StandardCharCode.X; - ansi_generic['Y'] = StandardCharCode.Y; - ansi_generic['Z'] = StandardCharCode.Z; - ansi_generic['['] = StandardCharCode.bracketleft; - ansi_generic['\\'] = StandardCharCode.backslash; - ansi_generic[']'] = StandardCharCode.bracketright; - ansi_generic['^'] = StandardCharCode.asciicircum; - ansi_generic['_'] = StandardCharCode.underscore; - ansi_generic['`'] = StandardCharCode.quoteleft; - ansi_generic['a'] = StandardCharCode.a; - ansi_generic['b'] = StandardCharCode.b; - ansi_generic['c'] = StandardCharCode.c; - ansi_generic['d'] = StandardCharCode.d; - ansi_generic['e'] = StandardCharCode.e; - ansi_generic['f'] = StandardCharCode.f; - ansi_generic['g'] = StandardCharCode.g; - ansi_generic['h'] = StandardCharCode.h; - ansi_generic['i'] = StandardCharCode.i; - ansi_generic['j'] = StandardCharCode.j; - ansi_generic['k'] = StandardCharCode.k; - ansi_generic['l'] = StandardCharCode.l; - ansi_generic['m'] = StandardCharCode.m; - ansi_generic['n'] = StandardCharCode.n; - ansi_generic['o'] = StandardCharCode.o; - ansi_generic['p'] = StandardCharCode.p; - ansi_generic['q'] = StandardCharCode.q; - ansi_generic['r'] = StandardCharCode.r; - ansi_generic['s'] = StandardCharCode.s; - ansi_generic['t'] = StandardCharCode.t; - ansi_generic['u'] = StandardCharCode.u; - ansi_generic['v'] = StandardCharCode.v; - ansi_generic['w'] = StandardCharCode.w; - ansi_generic['x'] = StandardCharCode.x; - ansi_generic['y'] = StandardCharCode.y; - ansi_generic['z'] = StandardCharCode.z; - ansi_generic['{'] = StandardCharCode.braceleft; - ansi_generic['|'] = StandardCharCode.bar; - ansi_generic['}'] = StandardCharCode.braceright; - ansi_generic['~'] = StandardCharCode.asciitilde; - ansi_generic[0xa0] = StandardCharCode.nobrkspace; - ansi_generic[0xa1] = StandardCharCode.exclamdown; - ansi_generic[0xa2] = StandardCharCode.cent; - ansi_generic[0xa3] = StandardCharCode.sterling; - ansi_generic[0xa4] = StandardCharCode.currency; - ansi_generic[0xa5] = StandardCharCode.yen; - ansi_generic[0xa6] = StandardCharCode.brokenbar; - ansi_generic[0xa7] = StandardCharCode.section; - ansi_generic[0xa8] = StandardCharCode.dieresis; - ansi_generic[0xa9] = StandardCharCode.copyright; - ansi_generic[0xaa] = StandardCharCode.ordfeminine; - ansi_generic[0xab] = StandardCharCode.guillemotleft; - ansi_generic[0xac] = StandardCharCode.logicalnot; - ansi_generic[0xad] = StandardCharCode.opthyphen; - ansi_generic[0xae] = StandardCharCode.registered; - ansi_generic[0xaf] = StandardCharCode.macron; - ansi_generic[0xb0] = StandardCharCode.degree; - ansi_generic[0xb1] = StandardCharCode.plusminus; - ansi_generic[0xb2] = StandardCharCode.twosuperior; - ansi_generic[0xb3] = StandardCharCode.threesuperior; - ansi_generic[0xb4] = StandardCharCode.acute; - ansi_generic[0xb5] = StandardCharCode.mu; - ansi_generic[0xb6] = StandardCharCode.paragraph; - ansi_generic[0xb7] = StandardCharCode.periodcentered; - ansi_generic[0xb8] = StandardCharCode.cedilla; - ansi_generic[0xb9] = StandardCharCode.onesuperior; - ansi_generic[0xba] = StandardCharCode.ordmasculine; - ansi_generic[0xbb] = StandardCharCode.guillemotright; - ansi_generic[0xbc] = StandardCharCode.onequarter; - ansi_generic[0xbd] = StandardCharCode.onehalf; - ansi_generic[0xbe] = StandardCharCode.threequarters; - ansi_generic[0xbf] = StandardCharCode.questiondown; - ansi_generic[0xc0] = StandardCharCode.Agrave; - ansi_generic[0xc1] = StandardCharCode.Aacute; - ansi_generic[0xc2] = StandardCharCode.Acircumflex; - ansi_generic[0xc3] = StandardCharCode.Atilde; - ansi_generic[0xc4] = StandardCharCode.Adieresis; - ansi_generic[0xc5] = StandardCharCode.Aring; - ansi_generic[0xc6] = StandardCharCode.AE; - ansi_generic[0xc7] = StandardCharCode.Ccedilla; - ansi_generic[0xc8] = StandardCharCode.Egrave; - ansi_generic[0xc9] = StandardCharCode.Eacute; - ansi_generic[0xca] = StandardCharCode.Ecircumflex; - ansi_generic[0xcb] = StandardCharCode.Edieresis; - ansi_generic[0xcc] = StandardCharCode.Igrave; - ansi_generic[0xcd] = StandardCharCode.Iacute; - ansi_generic[0xce] = StandardCharCode.Icircumflex; - ansi_generic[0xcf] = StandardCharCode.Idieresis; - ansi_generic[0xd0] = StandardCharCode.Eth; - ansi_generic[0xd1] = StandardCharCode.Ntilde; - ansi_generic[0xd2] = StandardCharCode.Ograve; - ansi_generic[0xd3] = StandardCharCode.Oacute; - ansi_generic[0xd4] = StandardCharCode.Ocircumflex; - ansi_generic[0xd5] = StandardCharCode.Otilde; - ansi_generic[0xd6] = StandardCharCode.Odieresis; - ansi_generic[0xd7] = StandardCharCode.multiply; - ansi_generic[0xd8] = StandardCharCode.Oslash; - ansi_generic[0xd9] = StandardCharCode.Ugrave; - ansi_generic[0xda] = StandardCharCode.Uacute; - ansi_generic[0xdb] = StandardCharCode.Ucircumflex; - ansi_generic[0xdc] = StandardCharCode.Udieresis; - ansi_generic[0xdd] = StandardCharCode.Yacute; - ansi_generic[0xde] = StandardCharCode.Thorn; - ansi_generic[0xdf] = StandardCharCode.germandbls; - ansi_generic[0xe0] = StandardCharCode.agrave; - ansi_generic[0xe1] = StandardCharCode.aacute; - ansi_generic[0xe2] = StandardCharCode.acircumflex; - ansi_generic[0xe3] = StandardCharCode.atilde; - ansi_generic[0xe4] = StandardCharCode.adieresis; - ansi_generic[0xe5] = StandardCharCode.aring; - ansi_generic[0xe6] = StandardCharCode.ae; - ansi_generic[0xe7] = StandardCharCode.ccedilla; - ansi_generic[0xe8] = StandardCharCode.egrave; - ansi_generic[0xe9] = StandardCharCode.eacute; - ansi_generic[0xea] = StandardCharCode.ecircumflex; - ansi_generic[0xeb] = StandardCharCode.edieresis; - ansi_generic[0xec] = StandardCharCode.igrave; - ansi_generic[0xed] = StandardCharCode.iacute; - ansi_generic[0xee] = StandardCharCode.icircumflex; - ansi_generic[0xef] = StandardCharCode.idieresis; - ansi_generic[0xf0] = StandardCharCode.eth; - ansi_generic[0xf1] = StandardCharCode.ntilde; - ansi_generic[0xf2] = StandardCharCode.ograve; - ansi_generic[0xf3] = StandardCharCode.oacute; - ansi_generic[0xf4] = StandardCharCode.ocircumflex; - ansi_generic[0xf5] = StandardCharCode.otilde; - ansi_generic[0xf6] = StandardCharCode.odieresis; - ansi_generic[0xf7] = StandardCharCode.divide; - ansi_generic[0xf8] = StandardCharCode.oslash; - ansi_generic[0xf9] = StandardCharCode.ugrave; - ansi_generic[0xfa] = StandardCharCode.uacute; - ansi_generic[0xfb] = StandardCharCode.ucircumflex; - ansi_generic[0xfc] = StandardCharCode.udieresis; - ansi_generic[0xfd] = StandardCharCode.yacute; - ansi_generic[0xfe] = StandardCharCode.thorn; - ansi_generic[0xff] = StandardCharCode.ydieresis; - - return ansi_generic; - } - } - - public static Charcode AnsiSymbol { - get { - Charcode code = new Charcode(256); - - code[0x06] = StandardCharCode.formula; - code[0x1e] = StandardCharCode.nobrkhyphen; - code[0x1f] = StandardCharCode.opthyphen; - code[' '] = StandardCharCode.space; - code['!'] = StandardCharCode.exclam; - code['"'] = StandardCharCode.universal; - code['#'] = StandardCharCode.mathnumbersign; - code['$'] = StandardCharCode.existential; - code['%'] = StandardCharCode.percent; - code['&'] = StandardCharCode.ampersand; - code['\\'] = StandardCharCode.suchthat; - code['('] = StandardCharCode.parenleft; - code[')'] = StandardCharCode.parenright; - code['*'] = StandardCharCode.mathasterisk; - code['+'] = StandardCharCode.mathplus; - code[','] = StandardCharCode.comma; - code['-'] = StandardCharCode.mathminus; - code['.'] = StandardCharCode.period; - code['/'] = StandardCharCode.slash; - code['0'] = StandardCharCode.zero; - code['1'] = StandardCharCode.one; - code['2'] = StandardCharCode.two; - code['3'] = StandardCharCode.three; - code['4'] = StandardCharCode.four; - code['5'] = StandardCharCode.five; - code['6'] = StandardCharCode.six; - code['7'] = StandardCharCode.seven; - code['8'] = StandardCharCode.eight; - code['9'] = StandardCharCode.nine; - code[':'] = StandardCharCode.colon; - code[';'] = StandardCharCode.semicolon; - code['<'] = StandardCharCode.less; - code['='] = StandardCharCode.mathequal; - code['>'] = StandardCharCode.greater; - code['?'] = StandardCharCode.question; - code['@'] = StandardCharCode.congruent; - code['A'] = StandardCharCode.Alpha; - code['B'] = StandardCharCode.Beta; - code['C'] = StandardCharCode.Chi; - code['D'] = StandardCharCode.Delta; - code['E'] = StandardCharCode.Epsilon; - code['F'] = StandardCharCode.Phi; - code['G'] = StandardCharCode.Gamma; - code['H'] = StandardCharCode.Eta; - code['I'] = StandardCharCode.Iota; - code['K'] = StandardCharCode.Kappa; - code['L'] = StandardCharCode.Lambda; - code['M'] = StandardCharCode.Mu; - code['N'] = StandardCharCode.Nu; - code['O'] = StandardCharCode.Omicron; - code['P'] = StandardCharCode.Pi; - code['Q'] = StandardCharCode.Theta; - code['R'] = StandardCharCode.Rho; - code['S'] = StandardCharCode.Sigma; - code['T'] = StandardCharCode.Tau; - code['U'] = StandardCharCode.Upsilon; - code['V'] = StandardCharCode.varsigma; - code['W'] = StandardCharCode.Omega; - code['X'] = StandardCharCode.Xi; - code['Y'] = StandardCharCode.Psi; - code['Z'] = StandardCharCode.Zeta; - code['['] = StandardCharCode.bracketleft; - code['\\'] = StandardCharCode.backslash; - code[']'] = StandardCharCode.bracketright; - code['^'] = StandardCharCode.asciicircum; - code['_'] = StandardCharCode.underscore; - code['`'] = StandardCharCode.quoteleft; - code['a'] = StandardCharCode.alpha; - code['b'] = StandardCharCode.beta; - code['c'] = StandardCharCode.chi; - code['d'] = StandardCharCode.delta; - code['e'] = StandardCharCode.epsilon; - code['f'] = StandardCharCode.phi; - code['g'] = StandardCharCode.gamma; - code['h'] = StandardCharCode.eta; - code['i'] = StandardCharCode.iota; - code['k'] = StandardCharCode.kappa; - code['l'] = StandardCharCode.lambda; - code['m'] = StandardCharCode.mu; - code['n'] = StandardCharCode.nu; - code['o'] = StandardCharCode.omicron; - code['p'] = StandardCharCode.pi; - code['q'] = StandardCharCode.theta; - code['r'] = StandardCharCode.rho; - code['s'] = StandardCharCode.sigma; - code['t'] = StandardCharCode.tau; - code['u'] = StandardCharCode.upsilon; - code['w'] = StandardCharCode.omega; - code['x'] = StandardCharCode.xi; - code['y'] = StandardCharCode.psi; - code['z'] = StandardCharCode.zeta; - code['{'] = StandardCharCode.braceleft; - code['|'] = StandardCharCode.bar; - code['}'] = StandardCharCode.braceright; - code['~'] = StandardCharCode.mathtilde; - - return code; - } - } - #endregion // Public Static Methods - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charset.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charset.cs deleted file mode 100644 index cba57819595..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Charset.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -using System; - -// COMPLETE - -namespace System.Windows.Forms.RTF { - -#if RTF_LIB - public -#else - internal -#endif - class Charset { - #region Local Variables - private CharsetType id; - private CharsetFlags flags; - private Charcode code; - private string file; - #endregion // Local Variables - - #region Public Constructors - public Charset() { - flags = CharsetFlags.Read | CharsetFlags.Switch; - id = CharsetType.General; - file = string.Empty; - this.ReadMap(); - } - #endregion // Public Constructors - - #region Public Instance Properties - public Charcode Code { - get { - return code; - } - - set { - code = value; - } - } - - public CharsetFlags Flags { - get { - return flags; - } - - set { - flags = value; - } - } - - public CharsetType ID { - get { - return id; - } - - set { - switch(value) { - case CharsetType.Symbol: { - id = CharsetType.Symbol; - return; - } - - default: - case CharsetType.General: { - id = CharsetType.General; - return; - } - } - } - } - - public string File { - get { - return file; - } - - set { - if (file != value) { - file = value; - } - } - } - - public StandardCharCode this[int c] { - get { - return code[c]; - } - } - - #endregion // Public Instance Properties - - #region Public Instance Methods - public bool ReadMap() { - switch (id) { - case CharsetType.General: { - if (file == string.Empty) { - code = Charcode.AnsiGeneric; - return true; - } - // FIXME - implement reading charmap from file... - return true; - } - - case CharsetType.Symbol: { - if (file == string.Empty) { - code = Charcode.AnsiSymbol; - return true; - } - - // FIXME - implement reading charmap from file... - return true; - } - - default: { - return false; - } - } - } - - public char StdCharCode(string name) { - // FIXME - finish this - return ' '; - - } - - public string StdCharName(char code) { - // FIXME - finish this - return String.Empty; - } - #endregion // Public Instance Methods - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetFlags.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetFlags.cs deleted file mode 100644 index 7cfcb8c6539..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetFlags.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// COMPLETE - -namespace System.Windows.Forms.RTF { - [Flags] -#if RTF_LIB - public -#else - internal -#endif - enum CharsetFlags { - None = 0x00, - Read = 0x01, - Switch = 0x02 - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetToCodepage.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetToCodepage.cs new file mode 100644 index 00000000000..783c6351007 --- /dev/null +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetToCodepage.cs @@ -0,0 +1,79 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2020 Karl Scowen +// +// Authors: +// Karl Scowen <contact@scowencomputers.co.nz> +// +// + + +namespace System.Windows.Forms.RTF { + internal static class CharsetToCodepage { + public static int Translate(CharsetType charset) + { + switch (charset) { + case CharsetType.General: + case CharsetType.Arabic_Traditional: + case CharsetType.Arabic_user: + case CharsetType.Hebrew_user: + case CharsetType.Mac: // Technically wrong, because "mac" should actually be quite a few with their own code pages... + default: + return System.Text.Encoding.Default.CodePage; + case CharsetType.ANSI: + return 1252; + case CharsetType.Symbol: + return 42; + case CharsetType.Shift_Jis: + return 932; + case CharsetType.Hangul: + return 949; + case CharsetType.Johab: + return 1361; + case CharsetType.GB2312: + return 936; + case CharsetType.Big5: + return 950; + case CharsetType.Greek: + return 1253; + case CharsetType.Turkish: + return 1254; + case CharsetType.Vietnamese: + return 1258; + case CharsetType.Hebrew: + return 1255; + case CharsetType.Arabic: + return 1256; + case CharsetType.Baltic: + return 1257; + case CharsetType.Russian: + return 1251; + case CharsetType.Thai: + return 874; + case CharsetType.Eastern_European: + return 1250; + case CharsetType.PC_437: + return 437; + case CharsetType.OEM: + return 850; + } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetType.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetType.cs index a934dc82869..4dbb3d94897 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetType.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/CharsetType.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok (pbartok@novell.com) +// Karl Scowen (contact@scowencomputers.co.nz) // // @@ -33,8 +34,29 @@ namespace System.Windows.Forms.RTF { #else internal #endif - enum CharsetType { - General = 0, - Symbol = 1, + enum CharsetType : byte { + ANSI = 0, + General = 1, + Symbol = 2, + Mac = 77, + Shift_Jis = 128, + Hangul = 129, + Johab = 130, + GB2312 = 134, + Big5 = 136, + Greek = 161, + Turkish = 162, + Vietnamese = 163, + Hebrew = 177, + Arabic = 178, + Arabic_Traditional = 179, + Arabic_user = 180, + Hebrew_user = 181, + Baltic = 186, + Russian = 204, + Thai = 222, + Eastern_European = 238, + PC_437 = 254, + OEM = 255 } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/KeysInit.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/KeysInit.cs index 72188e6daa7..5ff3ff426c6 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/KeysInit.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/KeysInit.cs @@ -366,10 +366,12 @@ namespace System.Windows.Forms.RTF { new KeyStruct(Major.StyleAttr, Minor.Next, "snext"), new KeyStruct(Major.PictAttr, Minor.MacQD, "macpict"), new KeyStruct(Major.PictAttr, Minor.PMMetafile, "pmmetafile"), + new KeyStruct(Major.PictAttr, Minor.EnhancedMetafile, "emfblip"), new KeyStruct(Major.PictAttr, Minor.WinMetafile, "wmetafile"), new KeyStruct(Major.PictAttr, Minor.DevIndBitmap, "dibitmap"), new KeyStruct(Major.PictAttr, Minor.WinBitmap, "wbitmap"), new KeyStruct(Major.PictAttr, Minor.PngBlip, "pngblip"), + new KeyStruct(Major.PictAttr, Minor.JpegBlip, "jpgblip"), new KeyStruct(Major.PictAttr, Minor.PixelBits, "wbmbitspixel"), new KeyStruct(Major.PictAttr, Minor.BitmapPlanes, "wbmplanes"), new KeyStruct(Major.PictAttr, Minor.BitmapWid, "wbmwidthbytes"), @@ -393,6 +395,7 @@ namespace System.Windows.Forms.RTF { new KeyStruct(Major.NeXTGrAttr, Minor.NeXTGHeight, "height"), new KeyStruct(Major.Destination, Minor.OptDest, "*"), new KeyStruct(Major.Destination, Minor.FontTbl, "fonttbl"), + new KeyStruct(Major.Destination, Minor.FontName, "fname"), new KeyStruct(Major.Destination, Minor.FontAltName, "falt"), new KeyStruct(Major.Destination, Minor.EmbeddedFont, "fonteb"), new KeyStruct(Major.Destination, Minor.FontFile, "fontfile"), diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Minor.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Minor.cs index 8b0f1bc6f8d..4033f5bbf24 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Minor.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Minor.cs @@ -41,6 +41,7 @@ namespace System.Windows.Forms.RTF { // Major.Destinan FontTbl, + FontName, FontAltName, EmbeddedFont, FontFile, @@ -520,10 +521,12 @@ namespace System.Windows.Forms.RTF { // Major.PictAttr MacQD, PMMetafile, + EnhancedMetafile, WinMetafile, DevIndBitmap, WinBitmap, PngBlip, + JpegBlip, PixelBits, BitmapPlanes, BitmapWid, diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Picture.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Picture.cs index 244bcd9adff..35845b20aff 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Picture.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/Picture.cs @@ -66,7 +66,7 @@ namespace System.Windows.Forms.RTF { public float Width { get { float w = width; - if (w == -1) { + if (w < 0) { if (image == null) image = ToImage (); w = image.Width; @@ -79,7 +79,7 @@ namespace System.Windows.Forms.RTF { public float Height { get { float h = height; - if (h == -1) { + if (h < 0) { if (image == null) image = ToImage (); h = image.Height; @@ -113,7 +113,9 @@ namespace System.Windows.Forms.RTF { return false; switch (image_type) { case Minor.PngBlip: + case Minor.JpegBlip: case Minor.WinMetafile: + case Minor.EnhancedMetafile: break; default: return false; @@ -126,15 +128,7 @@ namespace System.Windows.Forms.RTF { { if (image == null) image = ToImage (); - - float height = this.height; - float width = this.width; - - if (height == -1) - height = image.Height; - if (width == -1) - width = image.Width; - dc.DrawImage (image, x, y, width, height); + dc.DrawImage (image, x, y, Width, Height); } public Image ToImage () diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/RTF.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/RTF.cs index 3b02df81ffb..469c379ed2b 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/RTF.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/RTF.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok (pbartok@novell.com) +// Karl Scowen <contact@scowencomputers.co.nz> // // COMPLETE @@ -60,10 +61,6 @@ namespace System.Windows.Forms.RTF { private char prev_char; private bool bump_line; - - private Font font_list; - - private Charset cur_charset; private Stack charset_stack; private Style styles; @@ -101,10 +98,7 @@ namespace System.Windows.Forms.RTF { line_pos = 0; prev_char = unchecked((char)-1); bump_line = false; - font_list = null; - charset_stack = null; - - cur_charset = new Charset(); + charset_stack = new Stack(); destination_callbacks = new DestinationCallback(); class_callbacks = new ClassCallback(); @@ -369,49 +363,52 @@ SkipCRLF: GetToken2(); if (this.rtf_class == TokenClass.Text) { - this.minor = (Minor)this.cur_charset[(int)this.major]; - if (encoding == null) { + if (encoding == null) encoding = Encoding.GetEncoding (encoding_code_page); - } encoded_text = new String (encoding.GetChars (new byte [] { (byte) this.major })); - } - - if (this.cur_charset.Flags == CharsetFlags.None) { - return this.rtf_class; - } - - if (CheckCMM (TokenClass.Control, Major.Unicode, Minor.UnicodeAnsiCodepage)) { + } else if (CheckCMM (TokenClass.Control, Major.Unicode, Minor.UnicodeAnsiCodepage)) { encoding_code_page = param; // fallback to the default one in case we have an invalid value if (encoding_code_page < 0 || encoding_code_page > 65535) encoding_code_page = DefaultEncodingCodePage; - } - if (((this.cur_charset.Flags & CharsetFlags.Read) != 0) && CheckCM(TokenClass.Control, Major.CharSet)) { - this.cur_charset.ReadMap(); - } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) { + encoding = null; + } else if (CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) { Font fp; - fp = Font.GetFont(this.font_list, this.param); + fp = Font.GetFont(this.fonts, this.param); if (fp != null) { - if (fp.Name.StartsWith("Symbol")) { - this.cur_charset.ID = CharsetType.Symbol; + if (fp.Codepage != 0) { + if (fp.Codepage != encoding_code_page) { + encoding_code_page = fp.Codepage; + encoding = null; + } } else { - this.cur_charset.ID = CharsetType.General; - } - } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && (this.rtf_class == TokenClass.Group)) { - switch(this.major) { - case Major.BeginGroup: { - this.charset_stack.Push(this.cur_charset); - break; + var cp = CharsetToCodepage.Translate (fp.Charset); + if (cp != 0 && cp != encoding_code_page) { + encoding_code_page = cp; + encoding = null; } + } + } + } else if (this.rtf_class == TokenClass.Group) { + switch(this.major) { + case Major.BeginGroup: { + charset_stack.Push(encoding_code_page); + break; + } - case Major.EndGroup: { - this.cur_charset = (Charset)this.charset_stack.Pop(); - break; + case Major.EndGroup: { + if (charset_stack.Count > 0) { + encoding_code_page = (int)this.charset_stack.Pop(); + } else { + encoding_code_page = DefaultEncodingCodePage; } + if (encoding != null && encoding.CodePage != encoding_code_page) + encoding = null; + break; } } } @@ -677,7 +674,10 @@ SkipCRLF: font = new Font(rtf); - while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup))) { + int depth = 0; + string untaggedName = null; + + while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && depth >= 0) { if (rtf.rtf_class == TokenClass.Control) { switch(rtf.major) { case Major.FontFamily: { @@ -734,6 +734,26 @@ SkipCRLF: break; } + case Major.Destination: { + switch (rtf.minor) { + case Minor.FontName: + untaggedName = ReadFontName (rtf); + break; + + case Minor.FontAltName: + font.AltName = ReadFontName (rtf); + break; + + default: { + #if RTF_DEBUG + Console.WriteLine ("Got unhandled Control.Destination.Minor: " + rtf.minor); + #endif + break; + } + } + break; + } + default: { #if RTF_DEBUG Console.WriteLine("ReadFontTbl: Unknown Control token " + rtf.major); @@ -742,22 +762,12 @@ SkipCRLF: } } } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { - rtf.SkipGroup(); - } else if (rtf.rtf_class == TokenClass.Text) { - StringBuilder sb; - - sb = new StringBuilder(); - - while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) && (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup))) { - sb.Append((char)rtf.major); - rtf.GetToken(); - } - - if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { - rtf.UngetToken(); - } - - font.Name = sb.ToString(); + depth++; + } else if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { + depth--; + } else if (rtf.rtf_class == TokenClass.Text) + { + font.Name = ReadFontName (rtf); continue; #if RTF_DEBUG } else { @@ -768,6 +778,9 @@ SkipCRLF: rtf.GetToken(); } + if (untaggedName != null) + font.Name = untaggedName; + if (old == 0) { rtf.GetToken(); @@ -788,6 +801,26 @@ SkipCRLF: rtf.RouteToken(); } + private static String ReadFontName(RTF rtf) + { + StringBuilder sb = new StringBuilder (); + + while (rtf.rtf_class != TokenClass.EOF && rtf.rtf_class != TokenClass.Text) + rtf.GetToken (); + + while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM (TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) && + (!rtf.CheckCM (TokenClass.Group, Major.BeginGroup))) { + sb.Append ((char)rtf.major); + rtf.GetToken (); + } + + if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) { + rtf.UngetToken(); + } + + return sb.ToString (); + } + private void ReadColorTbl(RTF rtf) { Color color; int num; @@ -943,20 +976,25 @@ SkipCRLF: private void ReadPictGroup(RTF rtf) { bool read_image_data = false; - + int groupDepth = 0; Picture picture = new Picture (); while (true) { rtf.GetToken (); + if (rtf.CheckCM (TokenClass.Group, Major.BeginGroup)) + groupDepth++; + if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) + groupDepth--; + + if (groupDepth < 0) break; switch (minor) { case Minor.PngBlip: - picture.ImageType = minor; - read_image_data = true; - break; + case Minor.JpegBlip: case Minor.WinMetafile: + case Minor.EnhancedMetafile: picture.ImageType = minor; read_image_data = true; continue; @@ -1047,10 +1085,33 @@ SkipCRLF: } } - private void ReadObjGroup(RTF rtf) { - rtf.SkipGroup(); - rtf.RouteToken(); + private void ReadObjGroup (RTF rtf) + { + int level; + + level = 1; + + while (GetToken () != TokenClass.EOF && this.minor != Minor.ObjResult) { + if (rtf_class == TokenClass.Group) { + if (this.major == Major.BeginGroup) { + level++; + } else if (this.major == Major.EndGroup) { + level--; + if (level < 1) { + break; + } + } + } + } + + if (level >= 1) { + GetToken (); + + if (rtf_class == TokenClass.Group) + GetToken (); + rtf.RouteToken (); + } } #endregion // Default Delegates } -} + } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharCode.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharCode.cs deleted file mode 100644 index 906735ba181..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharCode.cs +++ /dev/null @@ -1,392 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// COMPLETE - -namespace System.Windows.Forms.RTF { - -#if RTF_LIB - public -#else - internal -#endif - enum StandardCharCode { - nothing = 0, - space = 1, - exclam = 2, - quotedbl = 3, - numbersign = 4, - dollar = 5, - percent = 6, - ampersand = 7, - quoteright = 8, - parenleft = 9, - parenright = 10, - asterisk = 11, - plus = 12, - comma = 13, - hyphen = 14, - period = 15, - slash = 16, - zero = 17, - one = 18, - two = 19, - three = 20, - four = 21, - five = 22, - six = 23, - seven = 24, - eight = 25, - nine = 26, - colon = 27, - semicolon = 28, - less = 29, - equal = 30, - greater = 31, - question = 32, - at = 33, - A = 34, - B = 35, - C = 36, - D = 37, - E = 38, - F = 39, - G = 40, - H = 41, - I = 42, - J = 43, - K = 44, - L = 45, - M = 46, - N = 47, - O = 48, - P = 49, - Q = 50, - R = 51, - S = 52, - T = 53, - U = 54, - V = 55, - W = 56, - X = 57, - Y = 58, - Z = 59, - bracketleft = 60, - backslash = 61, - bracketright = 62, - asciicircum = 63, - underscore = 64, - quoteleft = 65, - a = 66, - b = 67, - c = 68, - d = 69, - e = 70, - f = 71, - g = 72, - h = 73, - i = 74, - j = 75, - k = 76, - l = 77, - m = 78, - n = 79, - o = 80, - p = 81, - q = 82, - r = 83, - s = 84, - t = 85, - u = 86, - v = 87, - w = 88, - x = 89, - y = 90, - z = 91, - braceleft = 92, - bar = 93, - braceright = 94, - asciitilde = 95, - exclamdown = 96, - cent = 97, - sterling = 98, - fraction = 99, - yen = 100, - florin = 101, - section = 102, - currency = 103, - quotedblleft = 104, - guillemotleft = 105, - guilsinglleft = 106, - guilsinglright = 107, - fi = 108, - fl = 109, - endash = 110, - dagger = 111, - daggerdbl = 112, - periodcentered = 113, - paragraph = 114, - bullet = 115, - quotesinglbase = 116, - quotedblbase = 117, - quotedblright = 118, - guillemotright = 119, - ellipsis = 120, - perthousand = 121, - questiondown = 122, - grave = 123, - acute = 124, - circumflex = 125, - tilde = 126, - macron = 127, - breve = 128, - dotaccent = 129, - dieresis = 130, - ring = 131, - cedilla = 132, - hungarumlaut = 133, - ogonek = 134, - caron = 135, - emdash = 136, - AE = 137, - ordfeminine = 138, - Lslash = 139, - Oslash = 140, - OE = 141, - ordmasculine = 142, - ae = 143, - dotlessi = 144, - lslash = 145, - oslash = 146, - oe = 147, - germandbls = 148, - Aacute = 149, - Acircumflex = 150, - Adieresis = 151, - Agrave = 152, - Aring = 153, - Atilde = 154, - Ccedilla = 155, - Eacute = 156, - Ecircumflex = 157, - Edieresis = 158, - Egrave = 159, - Eth = 160, - Iacute = 161, - Icircumflex = 162, - Idieresis = 163, - Igrave = 164, - Ntilde = 165, - Oacute = 166, - Ocircumflex = 167, - Odieresis = 168, - Ograve = 169, - Otilde = 170, - Scaron = 171, - Thorn = 172, - Uacute = 173, - Ucircumflex = 174, - Udieresis = 175, - Ugrave = 176, - Yacute = 177, - Ydieresis = 178, - aacute = 179, - acircumflex = 180, - adieresis = 181, - agrave = 182, - aring = 183, - atilde = 184, - brokenbar = 185, - ccedilla = 186, - copyright = 187, - degree = 188, - divide = 189, - eacute = 190, - ecircumflex = 191, - edieresis = 192, - egrave = 193, - eth = 194, - iacute = 195, - icircumflex = 196, - idieresis = 197, - igrave = 198, - logicalnot = 199, - minus = 200, - multiply = 201, - ntilde = 202, - oacute = 203, - ocircumflex = 204, - odieresis = 205, - ograve = 206, - onehalf = 207, - onequarter = 208, - onesuperior = 209, - otilde = 210, - plusminus = 211, - registered = 212, - thorn = 213, - threequarters = 214, - threesuperior = 215, - trademark = 216, - twosuperior = 217, - uacute = 218, - ucircumflex = 219, - udieresis = 220, - ugrave = 221, - yacute = 222, - ydieresis = 223, - Alpha = 224, - Beta = 225, - Chi = 226, - Delta = 227, - Epsilon = 228, - Phi = 229, - Gamma = 230, - Eta = 231, - Iota = 232, - Kappa = 233, - Lambda = 234, - Mu = 235, - Nu = 236, - Omicron = 237, - Pi = 238, - Theta = 239, - Rho = 240, - Sigma = 241, - Tau = 242, - Upsilon = 243, - varUpsilon = 244, - Omega = 245, - Xi = 246, - Psi = 247, - Zeta = 248, - alpha = 249, - beta = 250, - chi = 251, - delta = 252, - epsilon = 253, - phi = 254, - varphi = 255, - gamma = 256, - eta = 257, - iota = 258, - kappa = 259, - lambda = 260, - mu = 261, - nu = 262, - omicron = 263, - pi = 264, - varpi = 265, - theta = 266, - vartheta = 267, - rho = 268, - sigma = 269, - varsigma = 270, - tau = 271, - upsilon = 272, - omega = 273, - xi = 274, - psi = 275, - zeta = 276, - nobrkspace = 277, - nobrkhyphen = 278, - lessequal = 279, - greaterequal = 280, - infinity = 281, - integral = 282, - notequal = 283, - radical = 284, - radicalex = 285, - approxequal = 286, - apple = 287, - partialdiff = 288, - opthyphen = 289, - formula = 290, - lozenge = 291, - universal = 292, - existential = 293, - suchthat = 294, - congruent = 295, - therefore = 296, - perpendicular = 297, - minute = 298, - club = 299, - diamond = 300, - heart = 301, - spade = 302, - arrowboth = 303, - arrowleft = 304, - arrowup = 305, - arrowright = 306, - arrowdown = 307, - second = 308, - proportional = 309, - equivalence = 310, - arrowvertex = 311, - arrowhorizex = 312, - carriagereturn = 313, - aleph = 314, - Ifraktur = 315, - Rfraktur = 316, - weierstrass = 317, - circlemultiply = 318, - circleplus = 319, - emptyset = 320, - intersection = 321, - union = 322, - propersuperset = 323, - reflexsuperset = 324, - notsubset = 325, - propersubset = 326, - reflexsubset = 327, - element = 328, - notelement = 329, - angle = 330, - gradient = 331, - product = 332, - logicaland = 333, - logicalor = 334, - arrowdblboth = 335, - arrowdblleft = 336, - arrowdblup = 337, - arrowdblright = 338, - arrowdbldown = 339, - angleleft = 340, - registersans = 341, - copyrightsans = 342, - trademarksans = 343, - angleright = 344, - mathplus = 345, - mathminus = 346, - mathasterisk = 347, - mathnumbersign = 348, - dotmath = 349, - mathequal = 350, - mathtilde = 351, - - MaxChar = 352 - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharName.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharName.cs deleted file mode 100644 index 0190b798cf2..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/StandardCharName.cs +++ /dev/null @@ -1,411 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// COMPLETE - -namespace System.Windows.Forms.RTF { - -#if RTF_LIB - public -#else - internal -#endif - class StandardCharName { - public static string[] Names = { - "nothing", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "endash", - "dagger", - "daggerdbl", - "periodcentered", - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - "questiondown", - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "emdash", - "AE", - "ordfeminine", - "Lslash", - "Oslash", - "OE", - "ordmasculine", - "ae", - "dotlessi", - "lslash", - "oslash", - "oe", - "germandbls", - "Aacute", - "Acircumflex", - "Adieresis", - "Agrave", - "Aring", - "Atilde", - "Ccedilla", - "Eacute", - "Ecircumflex", - "Edieresis", - "Egrave", - "Eth", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Ntilde", - "Oacute", - "Ocircumflex", - "Odieresis", - "Ograve", - "Otilde", - "Scaron", - "Thorn", - "Uacute", - "Ucircumflex", - "Udieresis", - "Ugrave", - "Yacute", - "Ydieresis", - "aacute", - "acircumflex", - "adieresis", - "agrave", - "aring", - "atilde", - "brokenbar", - "ccedilla", - "copyright", - "degree", - "divide", - "eacute", - "ecircumflex", - "edieresis", - "egrave", - "eth", - "iacute", - "icircumflex", - "idieresis", - "igrave", - "logicalnot", - "minus", - "multiply", - "ntilde", - "oacute", - "ocircumflex", - "odieresis", - "ograve", - "onehalf", - "onequarter", - "onesuperior", - "otilde", - "plusminus", - "registered", - "thorn", - "threequarters", - "threesuperior", - "trademark", - "twosuperior", - "uacute", - "ucircumflex", - "udieresis", - "ugrave", - "yacute", - "ydieresis", - "Alpha", - "Beta", - "Chi", - "Delta", - "Epsilon", - "Phi", - "Gamma", - "Eta", - "Iota", - "Kappa", - "Lambda", - "Mu", - "Nu", - "Omicron", - "Pi", - "Theta", - "Rho", - "Sigma", - "Tau", - "Upsilon", - "varUpsilon", - "Omega", - "Xi", - "Psi", - "Zeta", - "alpha", - "beta", - "chi", - "delta", - "epsilon", - "phi", - "varphi", - "gamma", - "eta", - "iota", - "kappa", - "lambda", - "mu", - "nu", - "omicron", - "pi", - "varpi", - "theta", - "vartheta", - "rho", - "sigma", - "varsigma", - "tau", - "upsilon", - "omega", - "xi", - "psi", - "zeta", - "nobrkspace", - "nobrkhyphen", - "lessequal", - "greaterequal", - "infinity", - "integral", - "notequal", - "radical", - "radicalex", - "approxequal", - "apple", - "partialdiff", - "opthyphen", - "formula", - "lozenge", - "universal", - "existential", - "suchthat", - "congruent", - "therefore", - "perpendicular", - "minute", - "club", - "diamond", - "heart", - "spade", - "arrowboth", - "arrowleft", - "arrowup", - "arrowright", - "arrowdown", - "second", - "proportional", - "equivalence", - "arrowvertex", - "arrowhorizex", - "carriagereturn", - "aleph", - "Ifraktur", - "Rfraktur", - "weierstrass", - "circlemultiply", - "circleplus", - "emptyset", - "intersection", - "union", - "propersuperset", - "reflexsuperset", - "notsubset", - "propersubset", - "reflexsubset", - "element", - "notelement", - "angle", - "gradient", - "product", - "logicaland", - "logicalor", - "arrowdblboth", - "arrowdblleft", - "arrowdblup", - "arrowdblright", - "arrowdbldown", - "angleleft", - "registersans", - "copyrightsans", - "trademarksans", - "angleright", - "mathplus", - "mathminus", - "mathasterisk", - "mathnumbersign", - "dotmath", - "mathequal", - "mathtilde" - }; - - /// <summary>Lookup name by ID</summary> - public static string Name(int index) { - if ((index < 0) || (index >= Names.Length)) { - return string.Empty; - } - - return Names[index]; - } - - /// <summary>Lookup ID by name (e.g. mathtilde)</summary> - public static int ID(string name) { - for (int i=0; i < Names.Length; i++) { - if (name.Equals(Names[i])) { - return i; - } - } - return 0; - } - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/TextMap.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/TextMap.cs deleted file mode 100644 index f4474b92627..00000000000 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.RTF/TextMap.cs +++ /dev/null @@ -1,440 +0,0 @@ -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// Copyright (c) 2005 Novell, Inc. (http://www.novell.com) -// -// Authors: -// Peter Bartok (pbartok@novell.com) -// -// - -// This map is for convencience only, any app can create/use it's own -// StdCharCode -> <text> table - -using System.Collections; - -namespace System.Windows.Forms.RTF { - -#if RTF_LIB - public -#else - internal -#endif - class TextMap { - #region Local Variables - private string[] table; - #endregion // Local Variables - - #region Public Constructors - public TextMap() { - table = new string[(int)StandardCharCode.MaxChar]; - - for (int i = 0; i < (int)StandardCharCode.MaxChar; i++) { - table[i] = string.Empty; - } - } - #endregion // Public Constructors - - #region Public Instance Properties - internal string this[StandardCharCode c] { // FIXME - this should be public, if the whole namespace was public (ie standalone RTF parser) - get { - return table[(int)c]; - } - - set { - table[(int)c] = value; - } - } - - public string[] Table { - get { - return table; - } - } - #endregion // Public Instance Properties - - #region Public Static Methods - public static void SetupStandardTable(string[] table) - { - /* - table[(int)StandardCharCode.space] = " "; - table[(int)StandardCharCode.exclam] = "!"; - table[(int)StandardCharCode.quotedbl] = "\""; - table[(int)StandardCharCode.numbersign] = "#"; - table[(int)StandardCharCode.dollar] = "$"; - table[(int)StandardCharCode.percent] = "%"; - table[(int)StandardCharCode.ampersand] = "&"; - table[(int)StandardCharCode.quoteright] = "'"; - table[(int)StandardCharCode.parenleft] = "("; - table[(int)StandardCharCode.parenright] = ")"; - table[(int)StandardCharCode.asterisk] = "*"; - table[(int)StandardCharCode.plus] = "+"; - table[(int)StandardCharCode.comma] = ","; - table[(int)StandardCharCode.hyphen] = "-"; - table[(int)StandardCharCode.period] = "."; - table[(int)StandardCharCode.slash] = "/"; - table[(int)StandardCharCode.zero] = "0"; - table[(int)StandardCharCode.one] = "1"; - table[(int)StandardCharCode.two] = "2"; - table[(int)StandardCharCode.three] = "3"; - table[(int)StandardCharCode.four] = "4"; - table[(int)StandardCharCode.five] = "5"; - table[(int)StandardCharCode.six] = "6"; - table[(int)StandardCharCode.seven] = "7"; - table[(int)StandardCharCode.eight] = "8"; - table[(int)StandardCharCode.nine] = "9"; - table[(int)StandardCharCode.colon] = ":"; - table[(int)StandardCharCode.semicolon] = ";"; - table[(int)StandardCharCode.less] = "<"; - table[(int)StandardCharCode.equal] = "="; - table[(int)StandardCharCode.greater] = ">"; - table[(int)StandardCharCode.question] = "?"; - table[(int)StandardCharCode.at] = "@"; - table[(int)StandardCharCode.A] = "A"; - table[(int)StandardCharCode.B] = "B"; - table[(int)StandardCharCode.C] = "C"; - table[(int)StandardCharCode.D] = "D"; - table[(int)StandardCharCode.E] = "E"; - table[(int)StandardCharCode.F] = "F"; - table[(int)StandardCharCode.G] = "G"; - table[(int)StandardCharCode.H] = "H"; - table[(int)StandardCharCode.I] = "I"; - table[(int)StandardCharCode.J] = "J"; - table[(int)StandardCharCode.K] = "K"; - table[(int)StandardCharCode.L] = "L"; - table[(int)StandardCharCode.M] = "M"; - table[(int)StandardCharCode.N] = "N"; - table[(int)StandardCharCode.O] = "O"; - table[(int)StandardCharCode.P] = "P"; - table[(int)StandardCharCode.Q] = "Q"; - table[(int)StandardCharCode.R] = "R"; - table[(int)StandardCharCode.S] = "S"; - table[(int)StandardCharCode.T] = "T"; - table[(int)StandardCharCode.U] = "U"; - table[(int)StandardCharCode.V] = "V"; - table[(int)StandardCharCode.W] = "W"; - table[(int)StandardCharCode.X] = "X"; - table[(int)StandardCharCode.Y] = "Y"; - table[(int)StandardCharCode.Z] = "Z"; - table[(int)StandardCharCode.bracketleft] = "["; - table[(int)StandardCharCode.backslash] = "\\"; - table[(int)StandardCharCode.bracketright] = "]"; - table[(int)StandardCharCode.asciicircum] = "^"; - table[(int)StandardCharCode.underscore] = "_"; - table[(int)StandardCharCode.quoteleft] = "`"; - table[(int)StandardCharCode.a] = "a"; - table[(int)StandardCharCode.b] = "b"; - table[(int)StandardCharCode.c] = "c"; - table[(int)StandardCharCode.d] = "d"; - table[(int)StandardCharCode.e] = "e"; - table[(int)StandardCharCode.f] = "f"; - table[(int)StandardCharCode.g] = "g"; - table[(int)StandardCharCode.h] = "h"; - table[(int)StandardCharCode.i] = "i"; - table[(int)StandardCharCode.j] = "j"; - table[(int)StandardCharCode.k] = "k"; - table[(int)StandardCharCode.l] = "l"; - table[(int)StandardCharCode.m] = "m"; - table[(int)StandardCharCode.n] = "n"; - table[(int)StandardCharCode.o] = "o"; - table[(int)StandardCharCode.p] = "p"; - table[(int)StandardCharCode.q] = "q"; - table[(int)StandardCharCode.r] = "r"; - table[(int)StandardCharCode.s] = "s"; - table[(int)StandardCharCode.t] = "t"; - table[(int)StandardCharCode.u] = "u"; - table[(int)StandardCharCode.v] = "v"; - table[(int)StandardCharCode.w] = "w"; - table[(int)StandardCharCode.x] = "x"; - table[(int)StandardCharCode.y] = "y"; - table[(int)StandardCharCode.z] = "z"; - table[(int)StandardCharCode.braceleft] = "{"; - table[(int)StandardCharCode.bar] = "|"; - table[(int)StandardCharCode.braceright] = "}"; - table[(int)StandardCharCode.asciitilde] = "~"; - table[(int)StandardCharCode.AE] = "AE"; - table[(int)StandardCharCode.OE] = "OE"; - table[(int)StandardCharCode.acute] = "'"; - table[(int)StandardCharCode.ae] = "ae"; - table[(int)StandardCharCode.angleleft] = "<"; - table[(int)StandardCharCode.angleright] = ">"; - table[(int)StandardCharCode.arrowboth] = "<->"; - table[(int)StandardCharCode.arrowdblboth] = "<=>"; - table[(int)StandardCharCode.arrowdblleft] = "<="; - table[(int)StandardCharCode.arrowdblright] = "=>"; - table[(int)StandardCharCode.arrowleft] = "<-"; - table[(int)StandardCharCode.arrowright] = "->"; - table[(int)StandardCharCode.bullet] = "o"; - table[(int)StandardCharCode.cent] = "cent"; - table[(int)StandardCharCode.circumflex] = "^"; - table[(int)StandardCharCode.copyright] = "(c)"; - table[(int)StandardCharCode.copyrightsans] = "(c)"; - table[(int)StandardCharCode.degree] = "deg."; - table[(int)StandardCharCode.divide] = "/"; - table[(int)StandardCharCode.dotlessi] = "i"; - table[(int)StandardCharCode.ellipsis] = "..."; - table[(int)StandardCharCode.emdash] = "--"; - table[(int)StandardCharCode.endash] = "-"; - table[(int)StandardCharCode.fi] = "fi"; - table[(int)StandardCharCode.fl] = "fl"; - table[(int)StandardCharCode.fraction] = "/"; - table[(int)StandardCharCode.germandbls] = "ss"; - table[(int)StandardCharCode.grave] = "`"; - table[(int)StandardCharCode.greaterequal] = ">="; - table[(int)StandardCharCode.guillemotleft] = "<<"; - table[(int)StandardCharCode.guillemotright] = ">>"; - table[(int)StandardCharCode.guilsinglleft] = "<"; - table[(int)StandardCharCode.guilsinglright] = ">"; - table[(int)StandardCharCode.lessequal] = "<="; - table[(int)StandardCharCode.logicalnot] = "~"; - table[(int)StandardCharCode.mathasterisk] = "*"; - table[(int)StandardCharCode.mathequal] = "="; - table[(int)StandardCharCode.mathminus] = "-"; - table[(int)StandardCharCode.mathnumbersign] = "#"; - table[(int)StandardCharCode.mathplus] = "+"; - table[(int)StandardCharCode.mathtilde] = "~"; - table[(int)StandardCharCode.minus] = "-"; - table[(int)StandardCharCode.mu] = "u"; - table[(int)StandardCharCode.multiply] = "x"; - table[(int)StandardCharCode.nobrkhyphen] = "-"; - table[(int)StandardCharCode.nobrkspace] = ""; - table[(int)StandardCharCode.notequal] = "!="; - table[(int)StandardCharCode.oe] = "oe"; - table[(int)StandardCharCode.onehalf] = "1/2"; - table[(int)StandardCharCode.onequarter] = "1/4"; - table[(int)StandardCharCode.periodcentered] = "."; - table[(int)StandardCharCode.plusminus] = "+/-"; - table[(int)StandardCharCode.quotedblbase] = ",,"; - table[(int)StandardCharCode.quotedblleft] = "\""; - table[(int)StandardCharCode.quotedblright] = "\""; - table[(int)StandardCharCode.quotesinglbase] = ","; - table[(int)StandardCharCode.registered] = "reg."; - table[(int)StandardCharCode.registersans] = "reg."; - table[(int)StandardCharCode.threequarters] = "3/4"; - table[(int)StandardCharCode.tilde] = "~"; - table[(int)StandardCharCode.trademark] = "(TM)"; - table[(int)StandardCharCode.trademarksans] = "(TM)"; - - table[(int)StandardCharCode.aacute] = "\xE0"; - table[(int)StandardCharCode.questiondown] = "\xBF"; - - table[(int)StandardCharCode.udieresis] = "\xFC"; - table[(int)StandardCharCode.Udieresis] = "\xDC"; - table[(int)StandardCharCode.odieresis] = "\xF6"; - table[(int)StandardCharCode.Odieresis] = "\xD6"; - */ - - table [(int) StandardCharCode.formula] = "\x6"; - table [(int) StandardCharCode.nobrkhyphen] = "\x1e"; - table [(int) StandardCharCode.opthyphen] = "\x1f"; - table [(int) StandardCharCode.space] = " "; - table [(int) StandardCharCode.exclam] = "!"; - table [(int) StandardCharCode.quotedbl] = "\""; - table [(int) StandardCharCode.numbersign] = "#"; - table [(int) StandardCharCode.dollar] = "$"; - table [(int) StandardCharCode.percent] = "%"; - table [(int) StandardCharCode.ampersand] = "&"; - table [(int) StandardCharCode.parenleft] = "("; - table [(int) StandardCharCode.parenright] = ")"; - table [(int) StandardCharCode.asterisk] = "*"; - table [(int) StandardCharCode.plus] = "+"; - table [(int) StandardCharCode.comma] = ","; - table [(int) StandardCharCode.hyphen] = "-"; - table [(int) StandardCharCode.period] = "."; - table [(int) StandardCharCode.slash] = "/"; - table [(int) StandardCharCode.zero] = "0"; - table [(int) StandardCharCode.one] = "1"; - table [(int) StandardCharCode.two] = "2"; - table [(int) StandardCharCode.three] = "3"; - table [(int) StandardCharCode.four] = "4"; - table [(int) StandardCharCode.five] = "5"; - table [(int) StandardCharCode.six] = "6"; - table [(int) StandardCharCode.seven] = "7"; - table [(int) StandardCharCode.eight] = "8"; - table [(int) StandardCharCode.nine] = "9"; - table [(int) StandardCharCode.colon] = ":"; - table [(int) StandardCharCode.semicolon] = ";"; - table [(int) StandardCharCode.less] = "<"; - table [(int) StandardCharCode.equal] = "="; - table [(int) StandardCharCode.greater] = ">"; - table [(int) StandardCharCode.question] = "?"; - table [(int) StandardCharCode.at] = "@"; - table [(int) StandardCharCode.A] = "A"; - table [(int) StandardCharCode.B] = "B"; - table [(int) StandardCharCode.C] = "C"; - table [(int) StandardCharCode.D] = "D"; - table [(int) StandardCharCode.E] = "E"; - table [(int) StandardCharCode.F] = "F"; - table [(int) StandardCharCode.G] = "G"; - table [(int) StandardCharCode.H] = "H"; - table [(int) StandardCharCode.I] = "I"; - table [(int) StandardCharCode.J] = "J"; - table [(int) StandardCharCode.K] = "K"; - table [(int) StandardCharCode.L] = "L"; - table [(int) StandardCharCode.M] = "M"; - table [(int) StandardCharCode.N] = "N"; - table [(int) StandardCharCode.O] = "O"; - table [(int) StandardCharCode.P] = "P"; - table [(int) StandardCharCode.Q] = "Q"; - table [(int) StandardCharCode.R] = "R"; - table [(int) StandardCharCode.S] = "S"; - table [(int) StandardCharCode.T] = "T"; - table [(int) StandardCharCode.U] = "U"; - table [(int) StandardCharCode.V] = "V"; - table [(int) StandardCharCode.W] = "W"; - table [(int) StandardCharCode.X] = "X"; - table [(int) StandardCharCode.Y] = "Y"; - table [(int) StandardCharCode.Z] = "Z"; - table [(int) StandardCharCode.bracketleft] = "["; - table [(int) StandardCharCode.backslash] = "\\"; - table [(int) StandardCharCode.bracketright] = "]"; - table [(int) StandardCharCode.asciicircum] = "^"; - table [(int) StandardCharCode.underscore] = "_"; - table [(int) StandardCharCode.quoteleft] = "`"; - table [(int) StandardCharCode.a] = "a"; - table [(int) StandardCharCode.b] = "b"; - table [(int) StandardCharCode.c] = "c"; - table [(int) StandardCharCode.d] = "d"; - table [(int) StandardCharCode.e] = "e"; - table [(int) StandardCharCode.f] = "f"; - table [(int) StandardCharCode.g] = "g"; - table [(int) StandardCharCode.h] = "h"; - table [(int) StandardCharCode.i] = "i"; - table [(int) StandardCharCode.j] = "j"; - table [(int) StandardCharCode.k] = "k"; - table [(int) StandardCharCode.l] = "l"; - table [(int) StandardCharCode.m] = "m"; - table [(int) StandardCharCode.n] = "n"; - table [(int) StandardCharCode.o] = "o"; - table [(int) StandardCharCode.p] = "p"; - table [(int) StandardCharCode.q] = "q"; - table [(int) StandardCharCode.r] = "r"; - table [(int) StandardCharCode.s] = "s"; - table [(int) StandardCharCode.t] = "t"; - table [(int) StandardCharCode.u] = "u"; - table [(int) StandardCharCode.v] = "v"; - table [(int) StandardCharCode.w] = "w"; - table [(int) StandardCharCode.x] = "x"; - table [(int) StandardCharCode.y] = "y"; - table [(int) StandardCharCode.z] = "z"; - table [(int) StandardCharCode.braceleft] = "{"; - table [(int) StandardCharCode.bar] = "|"; - table [(int) StandardCharCode.braceright] = "}"; - table [(int) StandardCharCode.asciitilde] = "~"; - table [(int) StandardCharCode.nobrkspace] = "\xa0"; - table [(int) StandardCharCode.exclamdown] = "\xa1"; - table [(int) StandardCharCode.cent] = "\xa2"; - table [(int) StandardCharCode.sterling] = "\xa3"; - table [(int) StandardCharCode.currency] = "\xa4"; - table [(int) StandardCharCode.yen] = "\xa5"; - table [(int) StandardCharCode.brokenbar] = "\xa6"; - table [(int) StandardCharCode.section] = "\xa7"; - table [(int) StandardCharCode.dieresis] = "\xa8"; - table [(int) StandardCharCode.copyright] = "\xa9"; - table [(int) StandardCharCode.ordfeminine] = "\xaa"; - table [(int) StandardCharCode.guillemotleft] = "\xab"; - table [(int) StandardCharCode.logicalnot] = "\xac"; - table [(int) StandardCharCode.opthyphen] = "\xad"; - table [(int) StandardCharCode.registered] = "\xae"; - table [(int) StandardCharCode.macron] = "\xaf"; - table [(int) StandardCharCode.degree] = "\xb0"; - table [(int) StandardCharCode.plusminus] = "\xb1"; - table [(int) StandardCharCode.twosuperior] = "\xb2"; - table [(int) StandardCharCode.threesuperior] = "\xb3"; - table [(int) StandardCharCode.acute] = "\xb4"; - table [(int) StandardCharCode.mu] = "\xb5"; - table [(int) StandardCharCode.paragraph] = "\xb6"; - table [(int) StandardCharCode.periodcentered] = "\xb7"; - table [(int) StandardCharCode.cedilla] = "\xb8"; - table [(int) StandardCharCode.onesuperior] = "\xb9"; - table [(int) StandardCharCode.ordmasculine] = "\xba"; - table [(int) StandardCharCode.guillemotright] = "\xbb"; - table [(int) StandardCharCode.onequarter] = "\xbc"; - table [(int) StandardCharCode.onehalf] = "\xbd"; - table [(int) StandardCharCode.threequarters] = "\xbe"; - table [(int) StandardCharCode.questiondown] = "\xbf"; - table [(int) StandardCharCode.Agrave] = "\xc0"; - table [(int) StandardCharCode.Aacute] = "\xc1"; - table [(int) StandardCharCode.Acircumflex] = "\xc2"; - table [(int) StandardCharCode.Atilde] = "\xc3"; - table [(int) StandardCharCode.Adieresis] = "\xc4"; - table [(int) StandardCharCode.Aring] = "\xc5"; - table [(int) StandardCharCode.AE] = "\xc6"; - table [(int) StandardCharCode.Ccedilla] = "\xc7"; - table [(int) StandardCharCode.Egrave] = "\xc8"; - table [(int) StandardCharCode.Eacute] = "\xc9"; - table [(int) StandardCharCode.Ecircumflex] = "\xca"; - table [(int) StandardCharCode.Edieresis] = "\xcb"; - table [(int) StandardCharCode.Igrave] = "\xcc"; - table [(int) StandardCharCode.Iacute] = "\xcd"; - table [(int) StandardCharCode.Icircumflex] = "\xce"; - table [(int) StandardCharCode.Idieresis] = "\xcf"; - table [(int) StandardCharCode.Eth] = "\xd0"; - table [(int) StandardCharCode.Ntilde] = "\xd1"; - table [(int) StandardCharCode.Ograve] = "\xd2"; - table [(int) StandardCharCode.Oacute] = "\xd3"; - table [(int) StandardCharCode.Ocircumflex] = "\xd4"; - table [(int) StandardCharCode.Otilde] = "\xd5"; - table [(int) StandardCharCode.Odieresis] = "\xd6"; - table [(int) StandardCharCode.multiply] = "\xd7"; - table [(int) StandardCharCode.Oslash] = "\xd8"; - table [(int) StandardCharCode.Ugrave] = "\xd9"; - table [(int) StandardCharCode.Uacute] = "\xda"; - table [(int) StandardCharCode.Ucircumflex] = "\xdb"; - table [(int) StandardCharCode.Udieresis] = "\xdc"; - table [(int) StandardCharCode.Yacute] = "\xdd"; - table [(int) StandardCharCode.Thorn] = "\xde"; - table [(int) StandardCharCode.germandbls] = "\xdf"; - table [(int) StandardCharCode.agrave] = "\xe0"; - table [(int) StandardCharCode.aacute] = "\xe1"; - table [(int) StandardCharCode.acircumflex] = "\xe2"; - table [(int) StandardCharCode.atilde] = "\xe3"; - table [(int) StandardCharCode.adieresis] = "\xe4"; - table [(int) StandardCharCode.aring] = "\xe5"; - table [(int) StandardCharCode.ae] = "\xe6"; - table [(int) StandardCharCode.ccedilla] = "\xe7"; - table [(int) StandardCharCode.egrave] = "\xe8"; - table [(int) StandardCharCode.eacute] = "\xe9"; - table [(int) StandardCharCode.ecircumflex] = "\xea"; - table [(int) StandardCharCode.edieresis] = "\xeb"; - table [(int) StandardCharCode.igrave] = "\xec"; - table [(int) StandardCharCode.iacute] = "\xed"; - table [(int) StandardCharCode.icircumflex] = "\xee"; - table [(int) StandardCharCode.idieresis] = "\xef"; - table [(int) StandardCharCode.eth] = "\xf0"; - table [(int) StandardCharCode.ntilde] = "\xf1"; - table [(int) StandardCharCode.ograve] = "\xf2"; - table [(int) StandardCharCode.oacute] = "\xf3"; - table [(int) StandardCharCode.ocircumflex] = "\xf4"; - table [(int) StandardCharCode.otilde] = "\xf5"; - table [(int) StandardCharCode.odieresis] = "\xf6"; - table [(int) StandardCharCode.divide] = "\xf7"; - table [(int) StandardCharCode.oslash] = "\xf8"; - table [(int) StandardCharCode.ugrave] = "\xf9"; - table [(int) StandardCharCode.uacute] = "\xfa"; - table [(int) StandardCharCode.ucircumflex] = "\xfb"; - table [(int) StandardCharCode.udieresis] = "\xfc"; - table [(int) StandardCharCode.yacute] = "\xfd"; - table [(int) StandardCharCode.thorn] = "\xfe"; - table [(int) StandardCharCode.ydieresis] = "\xff"; - - } - #endregion // Public Static Methods - } -} diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.csproj b/mcs/class/System.Windows.Forms/System.Windows.Forms.csproj index fb32cde820b..f94733d9e20 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.csproj +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.csproj @@ -100,9 +100,7 @@ <Compile Include="System.Windows.Forms.Layout\TableLayout.cs" /> <Compile Include="System.Windows.Forms.Layout\TableLayoutSettingsTypeConverter.cs" /> <Compile Include="System.Windows.Forms.PropertyGridInternal\PropertiesTab.cs" /> - <Compile Include="System.Windows.Forms.RTF\Charcode.cs" /> - <Compile Include="System.Windows.Forms.RTF\Charset.cs" /> - <Compile Include="System.Windows.Forms.RTF\CharsetFlags.cs" /> + <Compile Include="System.Windows.Forms.RTF\CharsetToCodepage.cs" /> <Compile Include="System.Windows.Forms.RTF\CharsetType.cs" /> <Compile Include="System.Windows.Forms.RTF\ClassDelegate.cs" /> <Compile Include="System.Windows.Forms.RTF\Color.cs" /> @@ -115,12 +113,9 @@ <Compile Include="System.Windows.Forms.RTF\Picture.cs" /> <Compile Include="System.Windows.Forms.RTF\RTF.cs" /> <Compile Include="System.Windows.Forms.RTF\RTFException.cs" /> - <Compile Include="System.Windows.Forms.RTF\StandardCharCode.cs" /> - <Compile Include="System.Windows.Forms.RTF\StandardCharName.cs" /> <Compile Include="System.Windows.Forms.RTF\Style.cs" /> <Compile Include="System.Windows.Forms.RTF\StyleElement.cs" /> <Compile Include="System.Windows.Forms.RTF\StyleType.cs" /> - <Compile Include="System.Windows.Forms.RTF\TextMap.cs" /> <Compile Include="System.Windows.Forms.RTF\TokenClass.cs" /> <Compile Include="System.Windows.Forms.Theming\Default\ButtonPainter.cs" /> <Compile Include="System.Windows.Forms.Theming\Default\CheckBoxPainter.cs" /> @@ -787,6 +782,7 @@ <Compile Include="System.Windows.Forms\TabPage.cs" /> <Compile Include="System.Windows.Forms\TabRenderer.cs" /> <Compile Include="System.Windows.Forms\TabSizeMode.cs" /> + <Compile Include="System.Windows.Forms\TabStops.cs" /> <Compile Include="System.Windows.Forms\TableLayoutCellPaintEventArgs.cs" /> <Compile Include="System.Windows.Forms\TableLayoutCellPaintEventHandler.cs" /> <Compile Include="System.Windows.Forms\TableLayoutColumnStyleCollection.cs" /> diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources b/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources index 0655e691273..235dd61bed4 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms.dll.sources @@ -29,9 +29,7 @@ System.Windows.Forms.Design/WindowsFormsComponentEditor.cs System.Windows.Forms.Internal/Accessor.cs System.Windows.Forms.Internal/DebugHelper.cs System.Windows.Forms.PropertyGridInternal/PropertiesTab.cs -System.Windows.Forms.RTF/Charcode.cs -System.Windows.Forms.RTF/Charset.cs -System.Windows.Forms.RTF/CharsetFlags.cs +System.Windows.Forms.RTF/CharsetToCodepage.cs System.Windows.Forms.RTF/CharsetType.cs System.Windows.Forms.RTF/ClassDelegate.cs System.Windows.Forms.RTF/Color.cs @@ -44,12 +42,9 @@ System.Windows.Forms.RTF/Minor.cs System.Windows.Forms.RTF/Picture.cs System.Windows.Forms.RTF/RTF.cs System.Windows.Forms.RTF/RTFException.cs -System.Windows.Forms.RTF/StandardCharCode.cs -System.Windows.Forms.RTF/StandardCharName.cs System.Windows.Forms.RTF/Style.cs System.Windows.Forms.RTF/StyleElement.cs System.Windows.Forms.RTF/StyleType.cs -System.Windows.Forms.RTF/TextMap.cs System.Windows.Forms.RTF/TokenClass.cs System.Windows.Forms.Theming/Default/LabelPainter.cs System.Windows.Forms.Theming/Default/LinkLabelPainter.cs @@ -657,6 +652,7 @@ System.Windows.Forms/TableLayoutRowStyleCollection.cs System.Windows.Forms/TableLayoutSettings.cs System.Windows.Forms/TableLayoutStyle.cs System.Windows.Forms/TableLayoutStyleCollection.cs +System.Windows.Forms/TabStops.cs System.Windows.Forms/TextBox.cs System.Windows.Forms/TextBoxBase.cs System.Windows.Forms/TextBoxRenderer.cs diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs index d169d9adfd2..f7f063a8b70 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/Line.cs @@ -21,6 +21,7 @@ //
// Authors:
// Peter Bartok pbartok@novell.com
+// Karl Scowen <contact@scowencomputers.co.nz>
//
//
@@ -44,14 +45,20 @@ namespace System.Windows.Forms internal int line_no; // Line number
internal LineTag tags; // Tags describing the text
internal int offset; // Baseline can be on the X or Y axis depending if we are in multiline mode or not
- internal int height; // Height of the line (height of tallest tag)
- internal int ascent; // Ascent of the line (ascent of the tallest tag)
+ internal int height; // Total height of the line, including TotalParagraphSpacing and LineSpacing
+ private int textHeight; // Height of the line without spacing.
+ internal int ascent; // Ascent of the line (highest distance above the baseline, including character offset)
internal HorizontalAlignment alignment; // Alignment of the line
internal int align_shift; // Pixel shift caused by the alignment
- internal int indent; // Left indent for the first line
- internal int hanging_indent; // Hanging indent (left indent for all but the first line)
- internal int right_indent; // Right indent for all lines
+ internal float indent; // Left indent for the first line
+ internal float hanging_indent; // Hanging indent (difference between first line indent and other lines)
+ internal float right_indent; // Right indent for all lines
internal LineEnding ending;
+ internal float spacing_before;
+ internal float spacing_after;
+ internal float line_spacing;
+ internal bool line_spacing_multiple;
+ internal TabStopCollection tab_stops; // Custom tabstops for this paragraph.
// Stuff that's important for the tree
internal Line parent; // Our parent line
@@ -86,10 +93,11 @@ namespace System.Windows.Forms text = new StringBuilder (Text, space);
line_no = LineNo;
this.ending = ending;
+ tab_stops = new TabStopCollection();
widths = new float[space + 1];
-
+
tags = new LineTag(this, 1);
tags.Font = font;
tags.Color = color;
@@ -103,6 +111,7 @@ namespace System.Windows.Forms line_no = LineNo;
this.ending = ending;
alignment = align;
+ tab_stops = new TabStopCollection();
widths = new float[space + 1];
@@ -112,6 +121,38 @@ namespace System.Windows.Forms tags.Color = color;
}
+ internal Line (Document document, int LineNo, string Text, HorizontalAlignment align, Font font, Color color,
+ Color back_color, TextPositioning text_position, float char_offset, float left_indent, float hanging_indent,
+ float right_indent, float spacing_before, float spacing_after, float line_spacing, bool line_spacing_multiple,
+ TabStopCollection tab_stops, bool visible, LineEnding ending) : this(document, ending)
+ {
+ space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
+
+ text = new StringBuilder (Text, space);
+ line_no = LineNo;
+ this.ending = ending;
+ alignment = align;
+ indent = left_indent;
+ HangingIndent = hanging_indent;
+ this.right_indent = right_indent;
+ this.spacing_before = spacing_before;
+ this.spacing_after = spacing_after;
+ this.tab_stops = tab_stops;
+ this.line_spacing = line_spacing;
+ this.line_spacing_multiple = line_spacing_multiple;
+
+ widths = new float[space + 1];
+
+
+ tags = new LineTag(this, 1);
+ tags.Font = font;
+ tags.Color = color;
+ tags.BackColor = back_color;
+ tags.TextPosition = text_position;
+ tags.CharOffset = char_offset;
+ tags.Visible = visible;
+ }
+
internal Line (Document document, int LineNo, string Text, LineTag tag, LineEnding ending) : this(document, ending)
{
space = Text.Length > DEFAULT_TEXT_LEN ? Text.Length+1 : DEFAULT_TEXT_LEN;
@@ -137,10 +178,10 @@ namespace System.Windows.Forms }
}
- internal int HangingIndent {
+ internal float HangingIndent {
get { return hanging_indent; }
set {
- hanging_indent = value;
+ this.hanging_indent = value;
recalc = true;
}
}
@@ -151,7 +192,63 @@ namespace System.Windows.Forms set { height = value; }
}
- internal int Indent {
+ internal int TextHeight {
+ get {
+ return textHeight;
+ }
+ }
+
+ internal TabStopCollection TabStops {
+ get { return tab_stops; }
+ set { tab_stops = value; }
+ }
+
+ internal float TotalParagraphSpacing {
+ get {
+ return SpacingBefore + SpacingAfter;
+ }
+ }
+
+ internal float LineSpacing {
+ get {
+ if (textHeight == 0) {
+ throw new InvalidOperationException("Can't get LineSpacing when the line height isn't calculated!");
+ }
+ if (line_spacing < 0) {
+ return -line_spacing;
+ } else if (line_spacing_multiple) {
+ return line_spacing * textHeight * 6f / document.Dpi;
+ } else {
+ return Math.Max(line_spacing, textHeight);
+ }
+ }
+ }
+
+ internal float SpacingBefore {
+ get {
+ bool has_spacing = true;
+ if (line_no > 1) {
+ Line previous_line = document.GetLine(line_no - 1);
+ if (previous_line != null && (previous_line.ending == LineEnding.Wrap || previous_line.ending == LineEnding.None))
+ has_spacing = false;
+ }
+ if (has_spacing)
+ return spacing_before;
+ else
+ return 0;
+ }
+ }
+
+ internal float SpacingAfter {
+ get {
+ if (ending == LineEnding.Wrap)
+ return 0;
+ else
+ return spacing_after;
+ }
+ }
+
+ internal float Indent {
get { return indent; }
set {
indent = value;
@@ -164,7 +261,7 @@ namespace System.Windows.Forms set { line_no = value; }
}
- internal int RightIndent {
+ internal float RightIndent {
get { return right_indent; }
set {
right_indent = value;
@@ -254,7 +351,7 @@ namespace System.Windows.Forms return;
// Find the first tag that we are deleting from
- tag = FindTag (pos + 1);
+ tag = FindTag (pos);
// Remove the characters from the line
text.Remove (pos, count);
@@ -271,10 +368,10 @@ namespace System.Windows.Forms left = count;
left -= tag.Start + tag.Length - pos - 1;
- tag = tag.Next;
// Update the start of each tag
- while ((tag != null) && (left > 0)) {
+ while ((tag.Next != null) && (left > 0)) {
+ tag = tag.Next;
// Cache tag.Length as is will be indireclty modified
// by changes to tag.Start
int tag_length = tag.Length;
@@ -284,7 +381,6 @@ namespace System.Windows.Forms left = 0;
} else {
left -= tag_length;
- tag = tag.Next;
}
}
@@ -295,15 +391,7 @@ namespace System.Windows.Forms streamline = true;
}
- // Delete empty orphaned tags at the end
LineTag walk = tag;
- while (walk != null && walk.Next != null && walk.Next.Length == 0) {
- LineTag t = walk;
- walk.Next = walk.Next.Next;
- if (walk.Next != null)
- walk.Next.Previous = t;
- walk = walk.Next;
- }
// Adjust the start point of any tags following
if (tag != null) {
@@ -314,6 +402,15 @@ namespace System.Windows.Forms }
}
+ // Delete empty orphaned tags at the end. Do this after adjusting their starts, otherwise we might delete tags that acutally do have content.
+ while (walk != null && walk.Next != null && walk.Next.Length == 0) {
+ LineTag t = walk;
+ walk.Next = walk.Next.Next;
+ if (walk.Next != null)
+ walk.Next.Previous = t;
+ walk = walk.Next;
+ }
+
recalc = true;
if (streamline)
@@ -361,7 +458,7 @@ namespace System.Windows.Forms pos = text.Length - 1;
while (tag != null) {
- if (((tag.Start - 1) <= pos) && (pos <= (tag.Start + tag.Length - 1)))
+ if (((tag.Start - 1) <= pos) && (pos < (tag.Start + tag.Length - 1)))
return LineTag.GetFinalTag (tag);
tag = tag.Next;
@@ -434,6 +531,33 @@ namespace System.Windows.Forms // Insert the text into the StringBuilder
text.Insert (pos, s);
+ // Check that tag is still in use in the line. If not, then we choose the last tag at that position.
+ LineTag t = tags;
+ while (t != null) {
+ if (((t.Start - 1) <= pos) && (pos < (t.End - 1) || (pos == t.End - 1 && t.Length == 0))) {
+ // found the location
+ bool foundTag = false;
+ while (pos < (t.Start + t.Length - 1)) {
+ if (t == tag) {
+ foundTag = true;
+ break;
+ }
+ if (t.Next == null)
+ break;
+ t = t.Next;
+ }
+ if (!foundTag) {
+ if (pos < (t.Start + t.Length - 1)) {
+ tag = t.Previous;
+ } else {
+ tag = t;
+ }
+ }
+ break;
+ }
+ t = t.Next;
+ }
+
// Update the start position of every tag after this one
tag = tag.Next;
@@ -455,55 +579,94 @@ namespace System.Windows.Forms /// </summary>
internal bool RecalculateLine (Graphics g, Document doc)
{
- return RecalculateLine (g, doc, kerning_fonts.ContainsKey (tags.Font.GetHashCode ()));
- }
-
- private bool RecalculateLine (Graphics g, Document doc, bool handleKerning)
- {
LineTag tag;
int pos;
int len;
+ Font currentFont;
+ int currentFontStart;
SizeF size;
float w;
int prev_offset;
bool retval;
bool wrapped;
+ bool first_in_para;
Line line;
int wrap_pos;
+ int prev_wrap_pos;
int prev_height;
int prev_ascent;
- float add_width;
+ float prev_spacing_before;
+ int max_above_baseline;
+ int max_below_baseline;
+ int total_ascent;
+ int total_descent;
+ TabStop lastTab;
+ int lastTabPos;
+ char c;
+ bool handleKerning;
+ float right_indent;
pos = 0;
len = this.text.Length;
+ currentFont = tags.FontToDisplay;
+ currentFontStart = 0;
tag = this.tags;
prev_offset = this.offset; // For drawing optimization calculations
prev_height = this.height;
prev_ascent = this.ascent;
+ prev_spacing_before = this.SpacingBefore;
+ max_above_baseline = 0;
+ max_below_baseline = 0;
+ total_ascent = 0;
+ total_descent = 0;
+ lastTab = null;
+ lastTabPos = 0;
this.height = 0; // Reset line height
this.ascent = 0; // Reset the ascent for the line
tag.Shift = 0; // Reset shift (which should be stored as pixels, not as points)
+ right_indent = Math.Max(this.right_indent, 0); // Ignore any negative right indent.
- if (ending == LineEnding.Wrap)
- widths[0] = document.left_margin + hanging_indent;
+ if (line_no > 0) {
+ line = doc.GetLine (LineNo - 1);
+ first_in_para = line != null && line.ending != LineEnding.Wrap;
+ } else {
+ first_in_para = true;
+ }
+
+ if (first_in_para)
+ widths [0] = indent;
else
- widths[0] = document.left_margin + indent;
+ widths [0] = indent + hanging_indent;
+
+ if (widths [0] < 0)
+ widths [0] = 0; // Don't allow a negative indent to take the line to a negative position.
+
+ widths [0] += document.left_margin;
this.recalc = false;
retval = false;
wrapped = false;
wrap_pos = 0;
- add_width = 0;
+ prev_wrap_pos = 0;
- while (pos < len) {
+ handleKerning = kerning_fonts.ContainsKey (currentFont.GetHashCode ());
+ while (pos < len) {
while (tag.Length == 0) { // We should always have tags after a tag.length==0 unless len==0
//tag.Ascent = 0;
- tag.Shift = (tag.Line.ascent - tag.Ascent) / 72;
+ tag.Shift = (tag.Line.ascent - tag.Ascent); // / 72;
tag = tag.Next;
+ if (tag.Length != 0 && tag.FontToDisplay != currentFont) {
+ CheckKerning (g, currentFont, currentFontStart, pos - currentFontStart);
+ currentFont = tag.FontToDisplay;
+ currentFontStart = pos;
+ handleKerning = kerning_fonts.ContainsKey (currentFont.GetHashCode ());
+ }
}
+ c = text [pos];
+
// kerning is a problem. The original code in this method assumed that the
// width of a string equals the sum of the widths of its characters. This is
// not true when kerning takes place during the display process. Since it's
@@ -520,44 +683,103 @@ namespace System.Windows.Forms // MeasureText doesn't measure trailing spaces, so we do the best we can for those
// in the else branch.
// It doesn't measure /t characters either, we need to add it manually with add_width.
- size = TextBoxTextRenderer.MeasureText (g, text.ToString (0, pos + 1), tag.Font);
- newWidth = widths[0] + size.Width + add_width;
+ size = TextBoxTextRenderer.MeasureText (g, text.ToString (currentFontStart, pos + 1 - currentFontStart), currentFont);
+ newWidth = widths [currentFontStart] + size.Width;
}
- else
- {
+ else if (c != '\t') {
size = tag.SizeOfPosition (g, pos);
w = size.Width;
newWidth = widths[pos] + w;
- if (text[pos] == '\t') add_width += w;
+ } else {
+ CheckKerning (g, currentFont, currentFontStart, pos - currentFontStart);
+ currentFontStart = pos + 1; // Don't try handling the tab along with kerned text.
+
+ if (lastTab != null) {
+ ProcessLastTab (lastTab, lastTabPos, pos);
+ lastTab = null;
+ }
+
+ float l = widths [pos];
+ w = -1;
+ for (int i = 0; i < tab_stops.Count; i++) {
+ if (tab_stops [i].Position > l) {
+ lastTab = tab_stops [i];
+ lastTabPos = pos;
+ w = lastTab.GetInitialWidth (this, pos);
+ break;
+ }
+ }
+
+ if (w < 0) {
+ w = tag.SizeOfPosition (g, pos).Width;
+ }
+
+ newWidth = widths [pos] + w;
}
- if (Char.IsWhiteSpace (text[pos]))
- wrap_pos = pos + 1;
-
- if (doc.wrap) {
- if ((wrap_pos > 0) && (wrap_pos != len) && (newWidth + 5) > (doc.viewport_width - this.right_indent)) {
- // Make sure to set the last width of the line before wrapping
- widths[pos + 1] = newWidth;
-
- pos = wrap_pos;
- len = text.Length;
- doc.Split (this, tag, pos);
- ending = LineEnding.Wrap;
- len = this.text.Length;
-
- retval = true;
- wrapped = true;
- } else if (pos > 1 && newWidth > (doc.viewport_width - this.right_indent)) {
- // No suitable wrap position was found so break right in the middle of a word
-
- // Make sure to set the last width of the line before wrapping
- widths[pos + 1] = newWidth;
-
- doc.Split (this, tag, pos);
- ending = LineEnding.Wrap;
- len = this.text.Length;
- retval = true;
- wrapped = true;
+ if (doc.Wrap) {
+ // FIXME: Technically there are multiple no-break spaces, not just the main one.
+ if ((Char.IsWhiteSpace (c) && c != '\u00A0') || c == '-' || c == '\u2013' || c == '\u2014') {
+ // Primarily break on dashes or whitespace other than a no-break space.
+ prev_wrap_pos = wrap_pos;
+ if (c == '\t') {
+ wrap_pos = pos; // Wrap before tabs for some reason.
+ } else {
+ wrap_pos = pos + 1;
+ }
+ }
+
+ if (newWidth > (doc.viewport_width - this.right_indent)) {
+ LineTag split_tag = null;
+ if (wrap_pos > 0) {
+ // Make sure to set the last width of the line before wrapping
+ widths [pos + 1] = newWidth;
+
+ if (Char.IsWhiteSpace (c)) {
+ if (wrap_pos > pos) {
+ while (wrap_pos < text.Length && Char.IsWhiteSpace (text [wrap_pos]) && text [wrap_pos] != '\t') {
+ wrap_pos++;
+ }
+ pos++;
+ wrapped = true;
+ // don't try pulling more into this line, but keep looping to deal with the rest of the widths and tags
+ }
+ } else {
+ if (wrap_pos > pos && pos > 0) {
+ // We're at a dash (otherwise we'd be above), but don't have room to fit it in.
+ // Wrap at the previous wrap point if possible.
+ wrap_pos = prev_wrap_pos > 0 ? prev_wrap_pos : pos;
+ }
+ split_tag = tag;
+ pos = wrap_pos;
+ }
+ } else if (pos > 0) {
+ // No suitable wrap position was found so break right in the middle of a word
+
+ // Make sure to set the last width of the line before wrapping
+ widths [pos + 1] = newWidth;
+
+ split_tag = tag;
+ } // Else don't wrap -- pos == 0, so we'd infinite loop adding blank lines before this.
+
+ if (split_tag != null) {
+ if (lastTab != null) {
+ ProcessLastTab (lastTab, lastTabPos, pos);
+ lastTab = null;
+ }
+
+ while (pos < split_tag.Start)
+ split_tag = split_tag.Previous;
+ // We have to pass Split the correct tag, and that can change if pos
+ // is set somewhere before the tag change (e.g. by wrap_pos).
+
+ doc.Split (this, split_tag, pos);
+ ending = LineEnding.Wrap;
+ len = this.text.Length;
+
+ retval = true;
+ wrapped = true;
+ }
}
}
@@ -569,12 +791,23 @@ namespace System.Windows.Forms if (pos == len) {
line = doc.GetLine (this.line_no + 1);
- if ((line != null) && (ending == LineEnding.Wrap || ending == LineEnding.None)) {
- // Pull the two lines together
- doc.Combine (this.line_no, this.line_no + 1);
- len = this.text.Length;
- retval = true;
- }
+ do {
+ if ((line != null) && (ending == LineEnding.Wrap || ending == LineEnding.None) &&
+ (widths[pos] < (doc.viewport_width - this.right_indent) || line.text.Length == 0)) {
+ // Pull the two lines together
+ // Only do this if the line isn't already full, or the next line is empty.
+ var h = this.height; // Back up h, because Combine sets it to zero.
+ doc.Combine (this, line);
+ this.height = h; // And restore it. There's no point starting at the start again.
+ // Document.Combine() called Line.Streamline(), so it is possible tag points a tag that got removed.
+ tag = FindTag (pos - 1); // So make sure we've got the correct tag.
+ len = this.text.Length;
+ line = doc.GetLine (this.line_no + 1);
+ retval = true;
+ }
+ } while ((ending == LineEnding.Wrap || ending == LineEnding.None) && line != null && line.text.Length == 0);
+ // If the next line is empty, do it again (if possible).
+ // The amount of room on this line doesn't matter when there's no text being added...
}
}
@@ -582,54 +815,63 @@ namespace System.Windows.Forms // We just found the end of our current tag
tag.Height = tag.MaxHeight ();
- // Check if we're the tallest on the line (so far)
- if (tag.Height > this.height)
- this.height = tag.Height; // Yep; make sure the line knows
-
- if (tag.Ascent > this.ascent) {
- LineTag t;
-
- // We have a tag that has a taller ascent than the line;
- t = tags;
+ /* line.ascent is the highest point above the baseline.
+ * total_ascent will equal the maximum distance of the tag above the baseline.
+ * total_descent is needed to calculate the line height.
+ * tag.Shift does not include tag.CharOffset, because Shift puts the tag
+ * on the baseline, while CharOffset moves the baseline.
+ * However, we move the normal baseline when CharOffset is trying to push
+ * stuff off the top.
+ */
+ total_ascent = tag.Ascent + (int)tag.CharOffset;
+ total_descent = tag.Descent - (int)tag.CharOffset; // gets bigger as CharOffset gets smaller
+ if (total_ascent > max_above_baseline) {
+ int moveBy = total_ascent - max_above_baseline;
+ max_above_baseline = total_ascent;
+
+ LineTag t = tags;
while (t != null && t != tag) {
- t.Shift = (tag.Ascent - t.Ascent) / 72;
+ t.Shift += moveBy;
t = t.Next;
}
- // Save on our line
- this.ascent = tag.Ascent;
+ tag.Shift = (int)tag.CharOffset;
+ this.ascent = max_above_baseline;
} else {
- tag.Shift = (this.ascent - tag.Ascent) / 72;
+ tag.Shift = (this.ascent - tag.Ascent);
}
+ if (total_descent > max_below_baseline)
+ max_below_baseline = total_descent;
+
+ if (this.height < max_above_baseline + max_below_baseline + tag.Height - tag.Ascent - tag.Descent)
+ this.height = max_above_baseline + max_below_baseline + tag.Height - tag.Ascent - tag.Descent;
+
tag = tag.Next;
if (tag != null) {
+ if (tag.Length != 0 && tag.FontToDisplay != currentFont) {
+ CheckKerning (g, currentFont, currentFontStart, pos - currentFontStart);
+ currentFont = tag.FontToDisplay;
+ currentFontStart = pos;
+ handleKerning = kerning_fonts.ContainsKey (currentFont.GetHashCode ());
+ }
tag.Shift = 0;
- wrap_pos = pos;
+ // We can't just wrap on tag boundaries -- e.g. if the first letter of the word has a different colour / font.
}
}
}
- var fullText = text.ToString();
- if (!handleKerning && fullText.Length > 1 && !wrapped)
- {
- // Check whether kerning takes place for this string and font.
- var realSize = TextBoxTextRenderer.MeasureText(g, fullText, tags.Font);
- float realWidth = realSize.Width + widths[0];
- // MeasureText ignores trailing whitespace, so we will too at this point.
- int length = fullText.TrimEnd().Length;
- float sumWidth = widths[length];
- if (realWidth != sumWidth)
- {
- kerning_fonts.Add(tags.Font.GetHashCode (), true);
- // Using a slightly incorrect width this time around isn't that bad. All that happens
- // is that the cursor is a pixel or two off until the next character is typed. It's
- // the accumulation of pixel after pixel that causes display problems.
- }
+ if (pos != currentFontStart) {
+ CheckKerning (g, currentFont, currentFontStart, pos - currentFontStart);
}
- while (tag != null) {
- tag.Shift = (tag.Line.ascent - tag.Ascent) / 72;
+ if (lastTab != null) {
+ ProcessLastTab (lastTab, lastTabPos, pos);
+ lastTab = null;
+ }
+
+ while (tag != null) {
+ tag.Shift = (tag.Line.ascent - tag.Ascent); // / 72;
tag = tag.Next;
}
@@ -639,12 +881,49 @@ namespace System.Windows.Forms tags.Shift = 0;
}
- if (prev_offset != offset || prev_height != this.height || prev_ascent != this.ascent)
+ this.textHeight = this.height;
+ this.height = (int)(this.LineSpacing + this.TotalParagraphSpacing);
+
+ if (prev_offset != offset || prev_height != this.height || prev_ascent != this.ascent ||
+ Math.Abs (prev_spacing_before - this.SpacingBefore) > document.Dpi / 1440f)
retval = true;
return retval;
}
+ private void ProcessLastTab (TabStop tab, int tab_pos, int pos)
+ {
+ float prevTabRight = widths[tab_pos + 1];
+ float tabRight = tab.CalculateRight (this, tab_pos);
+ float change = tabRight - prevTabRight;
+
+ for (int i = tab_pos + 1; i <= pos; i++) {
+ widths[i] += change;
+ }
+ }
+
+ private void CheckKerning (Graphics g, Font font, int start, int length)
+ {
+ if (length > 1) {
+ if (!kerning_fonts.ContainsKey (font.GetHashCode ())) {
+ // Check whether kerning takes place for this string and font.
+ var partText = text.ToString(start, length);
+ var realSize = TextBoxTextRenderer.MeasureText(g, partText, font);
+ float realWidth = realSize.Width + widths[start + 1];
+ // MeasureText ignores trailing whitespace, so we will too at this point.
+ int textLength = partText.TrimEnd().Length;
+ float sumWidth = widths[textLength + start + 1];
+ if (realWidth != sumWidth)
+ {
+ kerning_fonts.Add(font.GetHashCode (), true);
+ // Using a slightly incorrect width this time around isn't that bad. All that happens
+ // is that the cursor is a pixel or two off until the next character is typed. It's
+ // the accumulation of pixel after pixel that causes display problems.
+ }
+ }
+ }
+ }
+
/// <summary>
/// Recalculate a single line using the same char for every character in the line
/// </summary>
@@ -667,13 +946,14 @@ namespace System.Windows.Forms w = TextBoxTextRenderer.MeasureText (g, doc.password_char, tags.Font).Width;
- if (this.height != (int)tag.Font.Height)
+ if (this.textHeight != (int)tag.Font.Height)
ret = true;
else
ret = false;
- this.height = (int)tag.Font.Height;
- tag.Height = this.height;
+ this.textHeight = (int)tag.Font.Height;
+ tag.Height = this.textHeight;
+ this.height = (int)(this.textHeight + this.LineSpacing + this.TotalParagraphSpacing);
this.ascent = tag.Ascent;
@@ -684,7 +964,42 @@ namespace System.Windows.Forms return ret;
}
-
+
+ internal void CalculateAlignment ()
+ {
+ var alignmentWidth = document.ViewPortWidth - document.left_margin - document.right_margin;
+ var alignmentLineWidth = GetAlignmentLineWidth ();
+
+ switch (alignment) {
+ case HorizontalAlignment.Left:
+ align_shift = 0;
+ break;
+ case HorizontalAlignment.Center:
+ align_shift = (alignmentWidth - alignmentLineWidth) / 2;
+ break;
+ case HorizontalAlignment.Right:
+ align_shift = alignmentWidth - alignmentLineWidth;
+ break;
+ }
+
+ align_shift = Math.Max (align_shift, 0); // Don't allow negative shifts.
+ }
+
+ private int GetAlignmentLineWidth ()
+ {
+ int last = text.Length - 1;
+ if (last < 0)
+ return 0;
+
+ char c = text [last];
+ while (last > 0 && Char.IsWhiteSpace (c) && c != '\t' && c != '\u00A0') {
+ c = text [--last];
+ }
+ // widths[0] has both the left margin and the left indents.
+ // Remove the margin (it is part of the viewport) and add the right indents (part of the line width, for alignment purposes).
+ return (int)(widths [last + 1] - document.left_margin + Math.Max (right_indent, 0));
+ }
+
internal void Streamline (int lines)
{
LineTag current;
@@ -711,7 +1026,7 @@ namespace System.Windows.Forms return;
while (next != null) {
- // Take out 0 length tags unless it's the last tag in the document
+ // Take out 0 length tags unless it's the last tag in the document.
if (current.IsTextTag && next.Length == 0 && next.IsTextTag) {
if ((next.Next != null) || (line_no != lines)) {
current.Next = next.Next;
diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/LineTag.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/LineTag.cs index a551e813de9..38e5bb58dd5 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/LineTag.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/LineTag.cs @@ -21,6 +21,7 @@ //
// Authors:
// Peter Bartok pbartok@novell.com
+// Karl Scowen <contact@scowencomputers.co.nz>
//
//
@@ -44,6 +45,10 @@ namespace System.Windows.Forms private string link_text; // The full link text e.g. this might be
// word-wrapped to "w" but this would be
// "www.example.com"
+ private bool visible;
+ private TextPositioning text_position; // Normal / superscript / subscript
+ private Font small_font; // Cached font for superscript / subscript
+ private float char_offset; // Shift the text baseline up or down
// Payload; text
private int start; // start, in chars; index into Line.text
@@ -53,7 +58,8 @@ namespace System.Windows.Forms private int height; // Height in pixels of the text this tag describes
private int ascent; // Ascent of the font for this tag
private int descent; // Descent of the font for this tag
- private int shift; // Shift down for this tag, to stay on baseline
+ private int shift; // Shift down for this tag, to stay on baseline.
+ // Measured from top of line to top of tag.
// Administrative
private Line line; // The line we're on
@@ -69,6 +75,7 @@ namespace System.Windows.Forms link_font = null;
is_link = false;
link_text = null;
+ visible = true;
}
#endregion // Constructors
@@ -113,6 +120,16 @@ namespace System.Windows.Forms return link_font;
}
+ if (TextPosition != TextPositioning.Normal) {
+ if (small_font == null)
+ small_font = new Font (font.FontFamily, font.Size * 0.583F, font.Style);
+
+ if (IsLink)
+ return new Font (small_font, font.Style | FontStyle.Underline);
+ else
+ return small_font;
+ }
+
return font;
}
}
@@ -122,20 +139,43 @@ namespace System.Windows.Forms set {
if (font != value) {
link_font = null;
+ small_font = null;
font = value;
height = Font.Height;
XplatUI.GetFontMetrics (Hwnd.GraphicsContext, Font, out ascent, out descent);
+ float scale_factor = font.GetHeight () / font.FontFamily.GetLineSpacing (font.Style);
+ ascent = (int) Math.Ceiling (ascent * scale_factor);
+ descent = (int) Math.Ceiling (descent * scale_factor);
line.recalc = true;
}
}
}
+ public TextPositioning TextPosition {
+ get { return text_position; }
+ set { text_position = value; }
+ }
+
+ public float CharOffset {
+ get { return char_offset; }
+ set { char_offset = value; }
+ }
+
public int Height {
get { return height; }
set { height = value; }
}
+ public int DrawnHeight {
+ get {
+ if (text_position != TextPositioning.Normal)
+ return (int) (height * 0.583F);
+
+ return height;
+ }
+ }
+
public virtual bool IsTextTag {
get { return true; }
}
@@ -186,7 +226,7 @@ namespace System.Windows.Forms throw new Exception("New tag makes an insane tag");
}
#endif
- start = value;
+ start = value;
}
}
@@ -206,9 +246,14 @@ namespace System.Windows.Forms }
}
+ public bool Visible {
+ get { return visible; }
+ set { visible = value; }
+ }
+
public float Width {
get {
- if (Length == 0)
+ if (Length == 0 || !visible)
return 0;
return line.widths [start + Length - 1] - (start != 0 ? line.widths [start - 1] : 0);
}
@@ -222,6 +267,15 @@ namespace System.Windows.Forms }
}
+ public int OffsetY {
+ get {
+ if (text_position == TextPositioning.Subscript)
+ return (int) (height * 0.45F);
+
+ return 0;
+ }
+ }
+
public bool IsLink {
get { return is_link; }
set { is_link = value; }
@@ -253,8 +307,8 @@ namespace System.Windows.Forms new_tag = new LineTag(line, pos);
new_tag.CopyFormattingFrom (this);
- new_tag.next = this.next;
- this.next = new_tag;
+ new_tag.Next = this.next;
+ this.Next = new_tag;
new_tag.previous = this;
if (new_tag.next != null)
@@ -269,7 +323,7 @@ namespace System.Windows.Forms if (!this.Equals (other))
return false;
- this.next = other.next;
+ this.Next = other.next;
if (this.next != null)
this.next.previous = this;
@@ -282,6 +336,9 @@ namespace System.Windows.Forms Font = other.font;
color = other.color;
back_color = other.back_color;
+ TextPosition = other.text_position;
+ CharOffset = other.CharOffset;
+ Visible = other.Visible;
}
public void Delete ()
@@ -312,6 +369,8 @@ namespace System.Windows.Forms public virtual void Draw (Graphics dc, Color color, float x, float y, int start, int end)
{
+ if (text_position == TextPositioning.Subscript)
+ y += OffsetY;
TextBoxTextRenderer.DrawText (dc, line.text.ToString (start, end).Replace ("\r", string.Empty), FontToDisplay, color, x, y, false);
}
@@ -328,6 +387,14 @@ namespace System.Windows.Forms public virtual void Draw (Graphics dc, Color color, float xoff, float y, int drawStart, int drawEnd,
string text, out Rectangle measuredText, bool measureText)
{
+ if (!visible) {
+ measuredText = new Rectangle ();
+ return;
+ }
+
+ if (text_position == TextPositioning.Subscript)
+ y += OffsetY;
+
if (measureText) {
int xstart = (int)line.widths [drawStart] + (int)xoff;
int xend = (int)line.widths [drawEnd] - (int)line.widths [drawStart];
@@ -342,7 +409,7 @@ namespace System.Windows.Forms while (drawStart < drawEnd) {
int tab_index = text.IndexOf ("\t", drawStart);
- if (tab_index == -1)
+ if (tab_index == -1 || tab_index > drawEnd)
tab_index = drawEnd;
TextBoxTextRenderer.DrawText (dc, text.Substring (drawStart, tab_index - drawStart).Replace ("\r", string.Empty), FontToDisplay, color, xoff + line.widths [drawStart], y, false);
@@ -380,7 +447,16 @@ namespace System.Windows.Forms if (this.LinkText != other.LinkText)
return false;
- if (this.font.Equals (other.font) && this.color.Equals (other.color))
+ if (this.TextPosition != other.TextPosition)
+ return false;
+
+ if (this.CharOffset != other.CharOffset)
+ return false;
+
+ if (this.Visible != other.Visible)
+ return false;
+
+ if (this.font.Equals (other.font) && this.color.Equals (other.color) && this.back_color.Equals (other.back_color))
return true;
return false;
@@ -409,11 +485,17 @@ namespace System.Windows.Forms return null;
}
+ public static bool FormatText (Line line, int formatStart, int length, Font font, Color color, Color backColor, FormatSpecified specified)
+ {
+ return FormatText (line, formatStart, length, font, color, backColor, TextPositioning.Normal, 0, true, specified);
+ }
+
/// <summary>Applies 'font' and 'brush' to characters starting at 'start' for 'length' chars;
/// Removes any previous tags overlapping the same area;
/// returns true if lineheight has changed</summary>
/// <param name="formatStart">1-based character position on line</param>
- public static bool FormatText (Line line, int formatStart, int length, Font font, Color color, Color backColor, FormatSpecified specified)
+ public static bool FormatText (Line line, int formatStart, int length, Font font, Color color, Color backColor,
+ TextPositioning text_position, float char_offset, bool visible, FormatSpecified specified)
{
LineTag tag;
LineTag start_tag;
@@ -422,7 +504,7 @@ namespace System.Windows.Forms bool retval = false; // Assume line-height doesn't change
// Too simple?
- if (((FormatSpecified.Font & specified) == FormatSpecified.Font) && font.Height != line.height)
+ if (((FormatSpecified.Font & specified) == FormatSpecified.Font) && font.Height != line.TextHeight)
retval = true;
line.recalc = true; // This forces recalculation of the line in RecalculateDocument
@@ -436,7 +518,7 @@ namespace System.Windows.Forms // Common special case
if ((formatStart == 1) && (length == tag.Length)) {
- SetFormat (tag, font, color, backColor, specified);
+ SetFormat (tag, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
@@ -444,7 +526,7 @@ namespace System.Windows.Forms // we only need one new tag
if (formatStart == 1 && length == 0) {
line.tags.Break (1);
- SetFormat (line.tags, font, color, backColor, specified);
+ SetFormat (line.tags, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
@@ -455,7 +537,7 @@ namespace System.Windows.Forms // Find Tag will return tag 0 at position 3, but we should just
// use the empty tag after..
if (start_tag.End == formatStart && length == 0 && start_tag.Next != null && start_tag.Next.Length == 0) {
- SetFormat (start_tag.Next, font, color, backColor, specified);
+ SetFormat (start_tag.Next, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
@@ -463,13 +545,22 @@ namespace System.Windows.Forms while (start_tag.End == formatStart && start_tag.Next != null)
start_tag = start_tag.Next;
- tag = start_tag.Break (formatStart);
+ if (start_tag.Start == formatStart && start_tag.Length == length) {
+ SetFormat (start_tag, font, color, backColor, text_position, char_offset, visible, specified);
+ return retval;
+ }
+
+ // Break the tag if needed -- we don't need to break for the start if we're starting at its start.
+ if (start_tag.Start != formatStart)
+ tag = start_tag.Break (formatStart);
+ else
+ tag = start_tag;
// empty selection style at end of line - its the only situation
// where the rest of the tag would be empty, since we moved to the
// begining of next non empty tag
if (tag.Length == 0) {
- SetFormat (tag, font, color, backColor, specified);
+ SetFormat (tag, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
@@ -477,25 +568,27 @@ namespace System.Windows.Forms // after our new (now) empty one..
if (length == 0) {
tag.Break (formatStart);
- SetFormat (tag, font, color, backColor, specified);
+ SetFormat (tag, font, color, backColor, text_position, char_offset, visible, specified);
return retval;
}
+ bool atEnd = false;
while (tag != null && tag.End <= end) {
- SetFormat (tag, font, color, backColor, specified);
+ SetFormat (tag, font, color, backColor, text_position, char_offset, visible, specified);
+ atEnd |= tag.End == end;
tag = tag.next;
}
// did the last tag conveniently fit?
- if (tag != null && tag.End == end)
+ if (atEnd || (tag != null && tag.End == end))
return retval;
- /// Now do the last tag
+ // Now do the last tag
end_tag = FindTag (line, end-1);
if (end_tag != null) {
end_tag.Break (end);
- SetFormat (end_tag, font, color, backColor, specified);
+ SetFormat (end_tag, font, color, backColor, text_position, char_offset, visible, specified);
}
return retval;
@@ -509,6 +602,7 @@ namespace System.Windows.Forms int low = start;
int high = low + Length;
int length_no_ending = line.TextLengthWithoutEnding ();
+ float char_mid;
if (Length == 0)
return low-1;
@@ -517,7 +611,8 @@ namespace System.Windows.Forms return 0;
if (x < line.widths [low]) {
- if (low == 1 && x > (line.widths [1] / 2))
+ char_mid = (line.widths [1] + line.widths [0]) / 2;
+ if (low == 1 && x >= char_mid)
return low;
return low - 1;
}
@@ -535,9 +630,9 @@ namespace System.Windows.Forms high = mid;
}
- float char_width = line.widths[high] - line.widths[low];
+ char_mid = (line.widths [high] + line.widths [low]) / 2;
- if ((x - line.widths[low]) >= (char_width / 2))
+ if (x >= char_mid)
return high;
else
return low;
@@ -569,6 +664,12 @@ namespace System.Windows.Forms private static void SetFormat (LineTag tag, Font font, Color color, Color back_color, FormatSpecified specified)
{
+ SetFormat (tag, font, color, back_color, TextPositioning.Normal, 0, true, specified);
+ }
+
+ private static void SetFormat (LineTag tag, Font font, Color color, Color back_color, TextPositioning text_position,
+ float char_offset, bool visible, FormatSpecified specified)
+ {
if ((FormatSpecified.Font & specified) == FormatSpecified.Font) {
tag.Font = font;
}
@@ -577,28 +678,52 @@ namespace System.Windows.Forms if ((FormatSpecified.BackColor & specified) == FormatSpecified.BackColor) {
tag.back_color = back_color;
}
+ if ((FormatSpecified.TextPosition & specified) == FormatSpecified.TextPosition)
+ tag.TextPosition = text_position;
+ if ((FormatSpecified.CharOffset & specified) == FormatSpecified.CharOffset)
+ tag.CharOffset = char_offset;
+ if ((FormatSpecified.Visibility & specified) == FormatSpecified.Visibility)
+ tag.Visible = visible;
// Console.WriteLine ("setting format: {0} {1} new color {2}", color.Color, specified, tag.color.Color);
}
public virtual SizeF SizeOfPosition (Graphics dc, int pos)
{
- if (pos >= line.TextLengthWithoutEnding () && line.document.multiline)
+ if ((pos >= line.TextLengthWithoutEnding () && line.document.multiline) || !visible)
return SizeF.Empty;
string text = line.text.ToString (pos, 1);
- switch ((int) text [0]) {
+ switch ((int)text [0]) {
case '\t':
if (!line.document.multiline)
goto case 10;
- SizeF res = TextBoxTextRenderer.MeasureText (dc, " ", font);
- res.Width *= 8.0F;
+ SizeF res = TextBoxTextRenderer.MeasureText (dc, " ", FontToDisplay); // This way we get the height, not that it is ever used...
+ float left = line.widths [pos];
+ float right = -1;
+ TabStopCollection stops = line.tab_stops;
+ float tabPos;
+ for (int i = 0; i < stops.Count; i++) {
+ tabPos = stops [i].Position;
+ if (tabPos >= left) {
+ if (tabPos <= line.document.viewport_width - line.RightIndent)
+ break; // Can't use tabs that are past the end of the line.
+
+ right = stops [i].CalculateRight (line, pos);
+ break;
+ }
+ }
+ if (right < 0) {
+ float maxWidth = dc.DpiX / 2; // tab stops are 1/2"
+ right = (float)(Math.Floor (left / maxWidth) + 1) * maxWidth;
+ }
+ res.Width = right - left;
return res;
case 10:
case 13:
- return TextBoxTextRenderer.MeasureText (dc, "\u000D", font);
+ return TextBoxTextRenderer.MeasureText (dc, "\u000D", FontToDisplay);
}
-
- return TextBoxTextRenderer.MeasureText (dc, text, font);
+
+ return TextBoxTextRenderer.MeasureText (dc, text, FontToDisplay);
}
public virtual string Text ()
diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs index 9073f2c10c4..1b5f9513a23 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/RichTextBox.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok <pbartok@novell.com> +// Karl Scowen <contact@scowencomputers.co.nz> // // @@ -28,6 +29,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; @@ -55,7 +57,9 @@ namespace System.Windows.Forms { // properties so we can revert private Stack rtf_section_stack; - private RTF.TextMap rtf_text_map; + bool fire_contents_resized; + Size existing_contents_size; + private int rtf_skip_count; private int rtf_cursor_x; private int rtf_cursor_y; @@ -64,7 +68,7 @@ namespace System.Windows.Forms { private bool enable_auto_drag_drop; private RichTextBoxLanguageOptions language_option; private bool rich_text_shortcuts_enabled; - private Color selection_back_color; + #endregion // Local Variables #region Public Constructors @@ -85,15 +89,17 @@ namespace System.Windows.Forms { rtf_style = new RtfSectionStyle (); rtf_section_stack = null; + fire_contents_resized = true; + scrollbars = RichTextBoxScrollBars.Both; alignment = HorizontalAlignment.Left; + document.SizeChanged += new EventHandler<Document.SizeChangedEventArgs> (ContentSizeChanged); LostFocus += new EventHandler(RichTextBox_LostFocus); GotFocus += new EventHandler(RichTextBox_GotFocus); BackColor = ThemeEngine.Current.ColorWindow; backcolor_set = false; language_option = RichTextBoxLanguageOptions.AutoFontSizeAdjust; rich_text_shortcuts_enabled = true; - selection_back_color = DefaultBackColor; ForeColor = ThemeEngine.Current.ColorWindowText; base.HScrolled += new EventHandler(RichTextBox_HScrolled); @@ -133,6 +139,29 @@ namespace System.Windows.Forms { private void RichTextBox_GotFocus(object sender, EventArgs e) { Invalidate(); } + + private void ContentSizeChanged (object sender, Document.SizeChangedEventArgs e) + { + ContentSizeChanged (); + } + + private void ContentSizeChanged () + { + if (fire_contents_resized && (existing_contents_size.IsEmpty || + existing_contents_size.Height != document.Height || existing_contents_size.Width != document.Width)) { + int width; + int height = document.Height + document.top_margin * 2 + Height - ClientRectangle.Height; + + if (Multiline) { + width = Width; // yes, this is the insanity that is the traditional .Net implementation... + } else { + width = document.Width + document.left_margin + document.right_margin + Width - ClientRectangle.Width; + } + + ContentsResizedEventArgs args = new ContentsResizedEventArgs (new Rectangle (Left, Top, width, height)); + OnContentsResized (args); + } + } #endregion // Private & Internal Methods #region Public Instance Properties @@ -324,14 +353,25 @@ namespace System.Windows.Forms { set { MemoryStream data; + fire_contents_resized = false; + existing_contents_size = new Size (document.Width, document.Height); + document.Empty(); data = new MemoryStream(Encoding.ASCII.GetBytes(value), false); InsertRTFFromStream(data, 0, 1); + Line line = document.GetLine (1); + document.SetSelection (line, 0); + document.PositionCaret (line, 0); + data.Close(); Invalidate(); + + fire_contents_resized = true; + ContentSizeChanged (); + existing_contents_size = Size.Empty; } } @@ -371,6 +411,9 @@ namespace System.Windows.Forms { Line line; LineTag tag; + fire_contents_resized = false; + existing_contents_size = new Size (document.Width, document.Height); + document.SuspendRecalc (); if (document.selection_visible) { document.ReplaceSelection("", false); } @@ -393,14 +436,19 @@ namespace System.Windows.Forms { int nl_length = document.LineEndingLength (XplatUI.RunningOnUnix ? LineEnding.Rich : LineEnding.Hard); document.CharIndexToLineTag(sel_start + chars + (y - document.selection_start.line.line_no) * nl_length, out line, out tag, out sel_start); - if (sel_start >= line.text.Length) - sel_start = line.text.Length -1; + if (sel_start > line.text.Length) + sel_start = line.text.Length; //zero-based, but we want to go after the last character rather than before. document.SetSelection(line, sel_start); document.PositionCaret(line, sel_start); + document.ResumeRecalc(true); document.DisplayCaret(); ScrollToCaret(); OnTextChanged(EventArgs.Empty); + + fire_contents_resized = true; + ContentSizeChanged(); + existing_contents_size = Size.Empty; } } @@ -473,12 +521,56 @@ namespace System.Windows.Forms { } } - [MonoTODO ("Stub, does nothing")] [Browsable (false)] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public Color SelectionBackColor { - get { return selection_back_color; } - set { selection_back_color = value; } + get { + Color back_colour; + LineTag start; + LineTag end; + LineTag tag; + + start = document.selection_start.line.FindTag (document.selection_start.pos); + + if (SelectionLength > 0) { + end = document.selection_start.line.FindTag (document.selection_end.pos - 1); + } else { + end = start; + } + + back_colour = start.BackColor; + + tag = start; + while (tag != null) { + if (back_colour != tag.BackColor) + return Color.Empty; + + if (tag == end) + break; + + tag = document.NextTag (tag); + } + + return back_colour; + } + set { + int sel_start; + int sel_end; + + sel_start = document.LineTagToCharIndex (document.selection_start.line, document.selection_start.pos); + sel_end = document.LineTagToCharIndex (document.selection_end.line, document.selection_end.pos); + + document.FormatText (document.selection_start.line, document.selection_start.pos + 1, + document.selection_end.line, document.selection_end.pos + 1, null, + Color.Empty, value, FormatSpecified.BackColor); + + document.CharIndexToLineTag (sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos); + document.CharIndexToLineTag (sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos); + + document.UpdateView (document.selection_start.line, 0); + //Re-Align the caret in case its changed size or position + Document.AlignCaret (false); + } } [Browsable(false)] @@ -497,13 +589,54 @@ namespace System.Windows.Forms { [Browsable(false)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int SelectionCharOffset { get { - return 0; + float char_offset; + LineTag start; + LineTag end; + LineTag tag; + + start = document.selection_start.line.FindTag (document.selection_start.pos); + + if (SelectionLength > 0) { + end = document.selection_start.line.FindTag (document.selection_end.pos - 1); + } else { + end = start; + } + + char_offset = start.CharOffset; + + tag = start; + while (tag != null) { + if (Math.Abs(char_offset - tag.CharOffset) > 0.01) + return 0; + + if (tag == end) + break; + + tag = document.NextTag (tag); + } + + return (int)char_offset; } set { + int sel_start; + int sel_end; + + sel_start = document.LineTagToCharIndex (document.selection_start.line, document.selection_start.pos); + sel_end = document.LineTagToCharIndex (document.selection_end.line, document.selection_end.pos); + + document.FormatText (document.selection_start.line, document.selection_start.pos + 1, + document.selection_end.line, document.selection_end.pos + 1, null, + Color.Empty, Color.Empty, TextPositioning.Normal, value, true, FormatSpecified.CharOffset); + + document.CharIndexToLineTag (sel_start, out document.selection_start.line, out document.selection_start.tag, out document.selection_start.pos); + document.CharIndexToLineTag (sel_end, out document.selection_end.line, out document.selection_end.tag, out document.selection_end.pos); + + document.UpdateView (document.selection_start.line, 0); + //Re-Align the caret in case its changed size or position -- probably not necessary + Document.AlignCaret (false); } } @@ -516,11 +649,11 @@ namespace System.Windows.Forms { LineTag end; LineTag tag; - if (selection_length > 0) { - start = document.selection_start.line.FindTag (document.selection_start.pos + 1); - end = document.selection_start.line.FindTag (document.selection_end.pos); + start = document.selection_start.line.FindTag (document.selection_start.pos); + + if (SelectionLength > 0) { + end = document.selection_start.line.FindTag (document.selection_end.pos - 1); } else { - start = document.selection_start.line.FindTag (document.selection_start.pos); end = start; } @@ -575,17 +708,16 @@ namespace System.Windows.Forms { LineTag end; LineTag tag; - if (selection_length > 0) { - start = document.selection_start.line.FindTag (document.selection_start.pos + 1); - end = document.selection_start.line.FindTag (document.selection_end.pos); + start = document.selection_start.line.FindTag (document.selection_start.pos); + if (SelectionLength > 0) { + end = document.selection_start.line.FindTag (document.selection_end.pos - 1); } else { - start = document.selection_start.line.FindTag (document.selection_start.pos); end = start; } font = start.Font; - if (selection_length > 1) { + if (SelectionLength > 1) { tag = start; while (tag != null) { @@ -626,26 +758,106 @@ namespace System.Windows.Forms { [Browsable(false)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int SelectionHangingIndent { get { - return 0; + int indent; + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + indent = (int)start.hanging_indent; + + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + if ((int)line.hanging_indent != indent) { + return 0; + } + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + + return indent; } set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + line.HangingIndent = value; + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + this.CalculateDocument (); } } [Browsable(false)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int SelectionIndent { get { - return 0; + int indent; + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + indent = (int)start.indent; + + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + if ((int)line.indent != indent) { + return 0; + } + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + + return indent; } set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + line.Indent = value; + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + this.CalculateDocument (); } } @@ -677,25 +889,105 @@ namespace System.Windows.Forms { [Browsable(false)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int SelectionRightIndent { get { - return 0; + int indent; + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + indent = (int)start.right_indent; + + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + if ((int)line.right_indent != indent) { + return 0; + } + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + + return indent; } set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + line.RightIndent = value; + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + this.CalculateDocument (); } } [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [MonoTODO ("Stub, does nothing")] public int[] SelectionTabs { get { - return new int[0]; + TabStopCollection tabs; + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + tabs = start.TabStops; + + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + if (!line.TabStops.Equals (tabs)) + return new int[0]; + + if (line == end) + break; + line = document.GetLine (line.line_no + 1); + } + + return tabs.ToPosArray (); } set { + Line start; + Line end; + Line line; + + start = document.ParagraphStart (document.selection_start.line); + end = document.ParagraphEnd (document.selection_end.line); + + line = start; + + while (true) { + line.TabStops.Clear (); + foreach (int val in value) + line.TabStops.Add (new LeftTabStop (val)); + + if (line == end) { + break; + } + line = document.GetLine (line.line_no + 1); + } + this.CalculateDocument (); } } @@ -1308,26 +1600,47 @@ namespace System.Windows.Forms { private class RtfSectionStyle : ICloneable { internal Color rtf_color; + internal Color rtf_back_color; internal RTF.Font rtf_rtffont; - internal int rtf_rtffont_size; + internal float rtf_rtffont_size; internal FontStyle rtf_rtfstyle; - internal HorizontalAlignment rtf_rtfalign; - internal int rtf_par_line_left_indent; + internal HorizontalAlignment rtf_par_align; + internal float rtf_par_line_left_indent; + internal float rtf_par_first_line_indent; + internal float rtf_par_line_right_indent; internal bool rtf_visible; internal int rtf_skip_width; + internal float rtf_par_spacing_after; + internal float rtf_par_spacing_before; + internal float rtf_par_line_spacing; + internal bool rtf_par_line_spacing_multiple; + internal TextPositioning rtf_text_position; + internal float rtf_char_offset; + internal TabStop rtf_par_next_tab_stop = null; + internal TabStopCollection rtf_par_tab_stops = new TabStopCollection (); public object Clone () { RtfSectionStyle new_style = new RtfSectionStyle (); new_style.rtf_color = rtf_color; + new_style.rtf_back_color = rtf_back_color; new_style.rtf_par_line_left_indent = rtf_par_line_left_indent; - new_style.rtf_rtfalign = rtf_rtfalign; + new_style.rtf_par_first_line_indent = rtf_par_first_line_indent; + new_style.rtf_par_line_right_indent = rtf_par_line_right_indent; + new_style.rtf_par_align = rtf_par_align; new_style.rtf_rtffont = rtf_rtffont; new_style.rtf_rtffont_size = rtf_rtffont_size; new_style.rtf_rtfstyle = rtf_rtfstyle; new_style.rtf_visible = rtf_visible; new_style.rtf_skip_width = rtf_skip_width; + new_style.rtf_par_spacing_after = rtf_par_spacing_after; + new_style.rtf_par_spacing_before = rtf_par_spacing_before; + new_style.rtf_par_line_spacing = rtf_par_line_spacing; + new_style.rtf_par_line_spacing_multiple = rtf_par_line_spacing_multiple; + new_style.rtf_text_position = rtf_text_position; + new_style.rtf_char_offset = rtf_char_offset; + new_style.rtf_par_tab_stops = rtf_par_tab_stops.Clone (); return new_style; } @@ -1385,11 +1698,9 @@ namespace System.Windows.Forms { case RTF.Major.PictAttr: if (rtf.Picture != null && rtf.Picture.IsValid ()) { + FlushText (rtf, false, true); Line line = document.GetLine (rtf_cursor_y); - document.InsertPicture (line, 0, rtf.Picture); - rtf_cursor_x++; - - FlushText (rtf, true); + document.InsertPicture (line, rtf_cursor_x++, rtf.Picture); rtf.Picture = null; } break; @@ -1399,14 +1710,31 @@ namespace System.Windows.Forms { case RTF.Minor.ForeColor: { System.Windows.Forms.RTF.Color color; + color = System.Windows.Forms.RTF.Color.GetColor (rtf, rtf.Param); + + if (color != null) { + FlushText (rtf, false); + if (color.Red == -1 && color.Green == -1 && color.Blue == -1) { + this.rtf_style.rtf_color = ForeColor; + } else { + this.rtf_style.rtf_color = Color.FromArgb (color.Red, color.Green, color.Blue); + } + FlushText (rtf, false); + } + break; + } + + case RTF.Minor.BackColor: { + System.Windows.Forms.RTF.Color color; + color = System.Windows.Forms.RTF.Color.GetColor(rtf, rtf.Param); - + if (color != null) { FlushText(rtf, false); if (color.Red == -1 && color.Green == -1 && color.Blue == -1) { - this.rtf_style.rtf_color = ForeColor; + this.rtf_style.rtf_back_color = BackColor; } else { - this.rtf_style.rtf_color = Color.FromArgb(color.Red, color.Green, color.Blue); + this.rtf_style.rtf_back_color = Color.FromArgb(color.Red, color.Green, color.Blue); } FlushText (rtf, false); } @@ -1415,7 +1743,7 @@ namespace System.Windows.Forms { case RTF.Minor.FontSize: { FlushText(rtf, false); - this.rtf_style.rtf_rtffont_size = rtf.Param / 2; + this.rtf_style.rtf_rtffont_size = rtf.Param / 2f; break; } @@ -1478,7 +1806,7 @@ namespace System.Windows.Forms { case RTF.Minor.Invisible: { FlushText (rtf, false); - rtf_style.rtf_visible = false; + rtf_style.rtf_visible = (rtf.Param != RTF.RTF.NoParam); break; } @@ -1487,6 +1815,36 @@ namespace System.Windows.Forms { rtf_style.rtf_rtfstyle &= ~FontStyle.Underline; break; } + + case RTF.Minor.SuperScrShrink: { + FlushText (rtf, false); + rtf_style.rtf_text_position = TextPositioning.Superscript; + break; + } + + case RTF.Minor.SubScrShrink: { + FlushText (rtf, false); + rtf_style.rtf_text_position = TextPositioning.Subscript; + break; + } + + case RTF.Minor.NoSuperSub: { + FlushText (rtf, false); + rtf_style.rtf_text_position = TextPositioning.Normal; + break; + } + + case RTF.Minor.SuperScript: { + FlushText (rtf, false); + rtf_style.rtf_char_offset = ((float) rtf.Param / 144.0F) * document.Dpi; + break; + } + + case RTF.Minor.SubScript: { + FlushText (rtf, false); + rtf_style.rtf_char_offset = -((float) rtf.Param / 144.0F) * document.Dpi; + break; + } } break; } @@ -1497,32 +1855,90 @@ namespace System.Windows.Forms { case RTF.Minor.ParDef: FlushText (rtf, false); rtf_style.rtf_par_line_left_indent = 0; - rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + rtf_style.rtf_par_first_line_indent = 0; + rtf_style.rtf_par_line_right_indent = 0; + rtf_style.rtf_par_spacing_after = 0; + rtf_style.rtf_par_spacing_before = 0; + rtf_style.rtf_par_line_spacing = 0; + rtf_style.rtf_par_line_spacing_multiple = false; + rtf_style.rtf_par_align = HorizontalAlignment.Left; + rtf_style.rtf_par_next_tab_stop = null; + rtf_style.rtf_par_tab_stops.Clear (); + break; + + case RTF.Minor.TabLeft: + rtf_style.rtf_par_next_tab_stop = new LeftTabStop (); + break; + + case RTF.Minor.TabCenter: + rtf_style.rtf_par_next_tab_stop = new CentredTabStop (); + break; + + case RTF.Minor.TabRight: + rtf_style.rtf_par_next_tab_stop = new RightTabStop (); + break; + + case RTF.Minor.TabDecimal: + rtf_style.rtf_par_next_tab_stop = new DecimalTabStop (); + break; + + case RTF.Minor.TabPos: + float tabPos = ((float)rtf.Param / 1440.0F) * document.Dpi; + if (rtf_style.rtf_par_next_tab_stop != null) { + rtf_style.rtf_par_next_tab_stop.Position = tabPos; + rtf_style.rtf_par_tab_stops.Add (rtf_style.rtf_par_next_tab_stop); + rtf_style.rtf_par_next_tab_stop = null; + } else { + rtf_style.rtf_par_tab_stops.Add (new LeftTabStop (tabPos)); + } break; case RTF.Minor.LeftIndent: - using (Graphics g = CreateGraphics ()) - rtf_style.rtf_par_line_left_indent = (int) (((float) rtf.Param / 1440.0F) * g.DpiX + 0.5F); + rtf_style.rtf_par_line_left_indent = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.FirstIndent: + rtf_style.rtf_par_first_line_indent = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.RightIndent: + rtf_style.rtf_par_line_right_indent = ((float) rtf.Param / 1440.0F) * document.Dpi; break; case RTF.Minor.QuadCenter: FlushText (rtf, false); - rtf_style.rtf_rtfalign = HorizontalAlignment.Center; + rtf_style.rtf_par_align = HorizontalAlignment.Center; break; case RTF.Minor.QuadJust: FlushText (rtf, false); - rtf_style.rtf_rtfalign = HorizontalAlignment.Center; + rtf_style.rtf_par_align = HorizontalAlignment.Left; break; case RTF.Minor.QuadLeft: FlushText (rtf, false); - rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + rtf_style.rtf_par_align = HorizontalAlignment.Left; break; case RTF.Minor.QuadRight: FlushText (rtf, false); - rtf_style.rtf_rtfalign = HorizontalAlignment.Right; + rtf_style.rtf_par_align = HorizontalAlignment.Right; + break; + + case RTF.Minor.SpaceAfter: + rtf_style.rtf_par_spacing_after = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.SpaceBefore: + rtf_style.rtf_par_spacing_before = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.SpaceBetween: + rtf_style.rtf_par_line_spacing = ((float) rtf.Param / 1440.0F) * document.Dpi; + break; + + case RTF.Minor.SpaceMultiply: + rtf_style.rtf_par_line_spacing_multiple = (rtf.Param == 1); break; } break; @@ -1543,7 +1959,8 @@ namespace System.Windows.Forms { case RTF.Minor.Row: case RTF.Minor.Line: case RTF.Minor.Par: { - FlushText(rtf, true); + if (Multiline) + FlushText (rtf, true); break; } @@ -1575,8 +1992,8 @@ namespace System.Windows.Forms { break; } - case RTF.Minor.WidowCtrl: - break; + case RTF.Minor.WidowCtrl: + break; case RTF.Minor.EmDash: { rtf_line.Append ("\u2014"); @@ -1587,7 +2004,7 @@ namespace System.Windows.Forms { rtf_line.Append ("\u2013"); break; } -/* + case RTF.Minor.LQuote: { Console.Write("\u2018"); break; @@ -1607,7 +2024,7 @@ namespace System.Windows.Forms { Console.Write("\u201D"); break; } -*/ + default: { // Console.WriteLine ("skipped special char: {0}", rtf.Minor); // rtf.SkipGroup(); @@ -1640,16 +2057,21 @@ namespace System.Windows.Forms { } */ - if (rtf_style.rtf_visible) - rtf_line.Append (str); + rtf_line.Append (str); } private void FlushText(RTF.RTF rtf, bool newline) { + FlushText (rtf, newline, false); + } + + private void FlushText(RTF.RTF rtf, bool newline, bool force) { int length; + float hanging_indent; + float left_indent; Font font; length = rtf_line.Length; - if (!newline && (length == 0)) { + if (!newline && (length == 0) && !force) { return; } @@ -1659,7 +2081,12 @@ namespace System.Windows.Forms { } font = new Font (rtf_style.rtf_rtffont.Name, rtf_style.rtf_rtffont_size, rtf_style.rtf_rtfstyle); + if (font.Name != rtf_style.rtf_rtffont.Name && !string.IsNullOrEmpty (rtf_style.rtf_rtffont.AltName)) + font = new Font (rtf_style.rtf_rtffont.AltName, rtf_style.rtf_rtffont_size, rtf_style.rtf_rtfstyle); + hanging_indent = -rtf_style.rtf_par_first_line_indent; + left_indent = rtf_style.rtf_par_line_left_indent - hanging_indent; + if (rtf_style.rtf_color == Color.Empty) { System.Windows.Forms.RTF.Color color; @@ -1682,30 +2109,40 @@ namespace System.Windows.Forms { if (newline && rtf_line.ToString ().EndsWith (Environment.NewLine) == false) rtf_line.Append (Environment.NewLine); - document.Add (rtf_cursor_y, rtf_line.ToString (), rtf_style.rtf_rtfalign, font, rtf_style.rtf_color, - newline ? LineEnding.Rich : LineEnding.Wrap); - if (rtf_style.rtf_par_line_left_indent != 0) { - Line line = document.GetLine (rtf_cursor_y); - line.indent = rtf_style.rtf_par_line_left_indent; - } + document.Add (rtf_cursor_y, rtf_line.ToString (), rtf_style.rtf_par_align, font, rtf_style.rtf_color, + rtf_style.rtf_back_color, rtf_style.rtf_text_position, rtf_style.rtf_char_offset, left_indent, hanging_indent, + rtf_style.rtf_par_line_right_indent, rtf_style.rtf_par_spacing_before, rtf_style.rtf_par_spacing_after, + rtf_style.rtf_par_line_spacing, rtf_style.rtf_par_line_spacing_multiple, + rtf_style.rtf_par_tab_stops.Clone() , rtf_style.rtf_visible, + newline ? LineEnding.Rich : LineEnding.None); } else { - Line line; + Line line = document.GetLine (rtf_cursor_y); + + if (newline) { + if (rtf_cursor_x < line.text.Length) + document.Split(line, rtf_cursor_x); + line.ending = LineEnding.Rich; + } + + line.indent = left_indent; + line.HangingIndent = hanging_indent; + line.right_indent = rtf_style.rtf_par_line_right_indent; + line.spacing_after = rtf_style.rtf_par_spacing_after; + line.spacing_before = rtf_style.rtf_par_spacing_before; + line.line_spacing = rtf_style.rtf_par_line_spacing; + line.line_spacing_multiple = rtf_style.rtf_par_line_spacing_multiple; + line.alignment = rtf_style.rtf_par_align; - line = document.GetLine (rtf_cursor_y); - line.indent = rtf_style.rtf_par_line_left_indent; if (rtf_line.Length > 0) { document.InsertString (line, rtf_cursor_x, rtf_line.ToString ()); document.FormatText (line, rtf_cursor_x + 1, line, rtf_cursor_x + 1 + length, - font, rtf_style.rtf_color, Color.Empty, - FormatSpecified.Font | FormatSpecified.Color); + font, rtf_style.rtf_color, rtf_style.rtf_back_color, rtf_style.rtf_text_position, rtf_style.rtf_char_offset, + rtf_style.rtf_visible, FormatSpecified.Font | FormatSpecified.Color | FormatSpecified.BackColor | + FormatSpecified.TextPosition | FormatSpecified.CharOffset | FormatSpecified.Visibility); } - if (newline) { - line = document.GetLine (rtf_cursor_y); - line.ending = LineEnding.Rich; - if (line.Text.EndsWith (Environment.NewLine) == false) - line.Text += Environment.NewLine; - } + if (newline && line.Text.EndsWith (Environment.NewLine) == false) + line.Text += Environment.NewLine; reuse_line = false; // sanity assignment - in this case we have already re-used one line. } @@ -1740,9 +2177,20 @@ namespace System.Windows.Forms { rtf_skip_count = 0; rtf_line = new StringBuilder(); rtf_style.rtf_color = Color.Empty; + rtf_style.rtf_back_color = Color.Empty; rtf_style.rtf_rtffont_size = (int)this.Font.Size; - rtf_style.rtf_rtfalign = HorizontalAlignment.Left; + rtf_style.rtf_par_align = HorizontalAlignment.Left; rtf_style.rtf_rtfstyle = FontStyle.Regular; + rtf_style.rtf_text_position = TextPositioning.Normal; + rtf_style.rtf_par_spacing_after = 0; + rtf_style.rtf_par_spacing_before = 0; + rtf_style.rtf_par_line_spacing = 0; + rtf_style.rtf_par_line_spacing_multiple = false; + rtf_style.rtf_par_line_left_indent = 0; + rtf_style.rtf_par_first_line_indent = 0; + rtf_style.rtf_par_line_right_indent = 0; + rtf_style.rtf_par_tab_stops.Clear (); + rtf_style.rtf_char_offset = 0; rtf_style.rtf_rtffont = null; rtf_style.rtf_visible = true; rtf_style.rtf_skip_width = 1; @@ -1751,15 +2199,18 @@ namespace System.Windows.Forms { rtf_chars = 0; rtf.DefaultFont(this.Font.Name); - rtf_text_map = new RTF.TextMap(); - RTF.TextMap.SetupStandardTable(rtf_text_map.Table); - document.SuspendRecalc (); try { rtf.Read(); // That's it FlushText(rtf, false); + if (document.Lines > 1) { + Line last_line = document.GetLine (document.Lines); + if (last_line.text.Length == 0) { + document.Delete (last_line); + } + } } @@ -1780,10 +2231,11 @@ namespace System.Windows.Forms { rtf_section_stack.Clear(); if (IsHandleCreated) { + CalculateScrollBars (); using (var graphics = CreateGraphics()) document.RecalculateDocument(graphics, cursor_y, document.Lines, false); document.ResumeRecalc (true); - document.Invalidate (document.GetLine(cursor_y), 0, document.GetLine(document.Lines), -1); + document.InvalidateLinesAfter(document.GetLine(cursor_y)); } else { document.ResumeRecalc (false); } @@ -1822,7 +2274,7 @@ namespace System.Windows.Forms { rtf.Append(String.Format("\\f{0}", font_index)); // Font table entry } - if ((prev_font == null) || (prev_font.Size != font.Size)) { + if ((prev_font == null) || (Math.Abs (prev_font.Size - font.Size) > 0.01)) { rtf.Append(String.Format("\\fs{0}", (int)(font.Size * 2))); // Font size } @@ -1873,19 +2325,20 @@ namespace System.Windows.Forms { int start = rtf.Length; int count = text.Length; - // First emit simple unicode chars as escaped - EmitEscapedUnicode (rtf, text); - // This method emits user text *only*, so it's safe to escape any reserved rtf chars // Escape '\' first, since it is used later to escape the other chars if (text.IndexOfAny (ReservedRTFChars) > -1) { - rtf.Replace ("\\", "\\\\", start, count); - rtf.Replace ("{", "\\{", start, count); - rtf.Replace ("}", "\\}", start, count); + StringBuilder sb = new StringBuilder(text); // Would it be better to just use text = text.Replace for this? + sb.Replace ("\\", "\\\\"); + sb.Replace ("{", "\\{"); + sb.Replace ("}", "\\}"); + text = sb.ToString (); } + + // Then actually emit the text, and also escape any Unicode + EmitEscapedUnicode (rtf, text); } - // The chars to be escaped use "\'" + its hexadecimal value. private void EmitEscapedUnicode (StringBuilder sb, string text) { int pos; @@ -1894,9 +2347,10 @@ namespace System.Windows.Forms { while ((pos = IndexOfNonAscii (text, start)) > -1) { sb.Append (text, start, pos - start); - int n = (int)text [pos]; - sb.Append ("\\'"); - sb.Append (n.ToString ("X")); + short n = (short)text [pos]; + sb.Append ("\\u"); + sb.Append (n.ToString ()); + sb.Append ("?"); start = pos + 1; } @@ -1918,24 +2372,182 @@ namespace System.Windows.Forms { return -1; } + static char[] GetHexChars (byte[] bytes, int length) + { + if (length > bytes.Length) + throw new ArgumentOutOfRangeException ("length"); + + var chars = new char [length * 2]; + int n; + for (int i = 0; i < length; i++) { + n = bytes [i] >> 4; + chars [i * 2] = (char)('A' - 10 + n + (((n - 10) >> 31) & ('0' - 55))); + n = bytes [i] & 0x0F; + chars [i * 2 + 1] = (char)('A' - 10 + n + (((n - 10) >> 31) & ('0' - 55))); + } + return chars; + } + + void EmitRtfPicture (PictureTag picture, StringBuilder sb) + { + if (!picture.picture.IsValid ()) { + return; + } + + int width = (int)((float)picture.picture.Width / document.Dpi * 1440f); + int height = (int)((float)picture.picture.Height / document.Dpi * 1440f); + string type = ""; + switch (picture.picture.ImageType) { + case RTF.Minor.WinMetafile: + type = "wmetafile1"; // The number should actually vary, but I don't see how it is used here at all. + break; + case RTF.Minor.EnhancedMetafile: + type = "emfblip"; + break; + case RTF.Minor.PngBlip: + type = "pngblip"; + break; + case RTF.Minor.JpegBlip: + type = "jpegblip"; + break; + } + sb.AppendFormat ("{{\\pict\\{0}\\picwgoal{1}\\pichgoal{2} ", type, width, height); + + var data = picture.picture.Data; + data.Position = 0; + if (sb.Capacity - sb.Length < data.Length) { + sb.Capacity += (int)data.Length * 2; + } + var buffer = new byte [39]; + int length; + while ((length = data.Read (buffer, 0, buffer.Length)) > 0) { + sb.AppendLine ().Append (GetHexChars (buffer, length)); + } + sb.Append ("}"); + } + + void EmitTabStops (StringBuilder sb, TabStopCollection tabs) + { + foreach (var tab in tabs) { + if (tab is DecimalTabStop) { + sb.Append ("\\tqdec"); + } else if (tab is CentredTabStop) { + sb.Append ("\\tqc"); + } else if (tab is RightTabStop) { + sb.Append ("\\tqr"); + } + sb.Append ("\\tx"); + sb.Append (Int (tab.Position / document.Dpi * 1440f)); + } + } + + void EmitPard (StringBuilder sb, ArrayList fonts, Line line, LineTag tag, TabStopCollection tabs, float ppt) + { + var first_line_indent = -line.HangingIndent; + var left_indent = line.Indent - first_line_indent; + var right_indent = line.RightIndent; + + sb.Append ("\\pard"); + // Reset to default paragraph properties + switch (line.alignment) { + case HorizontalAlignment.Left: + sb.Append ("\\ql"); + break; + case HorizontalAlignment.Center: + sb.Append ("\\qc"); + break; + case HorizontalAlignment.Right: + sb.Append ("\\qr"); + break; + } + if (Math.Abs (line.spacing_after) > ppt) { + sb.Append ("\\sa"); + sb.Append (Int (line.spacing_after / ppt)); + } + if (Math.Abs (line.spacing_before) > ppt) { + sb.Append ("\\sb"); + sb.Append (Int (line.spacing_before / ppt)); + } + if (Math.Abs (line.line_spacing) > ppt) { + sb.Append ("\\sl"); + sb.Append (Int (line.line_spacing / ppt)); + sb.Append ("\\slmult"); + sb.Append (line.line_spacing_multiple ? "1" : "0"); + } + if (Math.Abs (left_indent) > ppt) { + sb.Append ("\\li"); + sb.Append (Int (left_indent / ppt)); + } + if (Math.Abs (first_line_indent) > ppt) { + sb.Append ("\\fi"); + sb.Append (Int (first_line_indent / ppt)); + } + if (Math.Abs (right_indent) > ppt) { + sb.Append ("\\ri"); + sb.Append (Int (right_indent / ppt)); + } + if (tabs.Count > 0) { + EmitTabStops (sb, tabs); + } + } + + static void LoadParaSettings (Line line, out HorizontalAlignment line_alignment, out float spacing_after, out float spacing_before, out float line_spacing, + out bool line_spacing_multiple, out float left_indent, out float prev_left_indent, out float first_line_indent, + out float prev_first_line_indent, out float right_indent, out TabStopCollection tabs) + { + spacing_after = line.spacing_after; + spacing_before = line.spacing_before; + line_spacing = line.line_spacing; + line_spacing_multiple = line.line_spacing_multiple; + line_alignment = line.alignment; + first_line_indent = -line.HangingIndent; + left_indent = line.Indent - first_line_indent; + prev_first_line_indent = first_line_indent; + prev_left_indent = left_indent; + right_indent = line.RightIndent; + tabs = line.TabStops; + } + // start_pos and end_pos are 0-based private StringBuilder GenerateRTF(Line start_line, int start_pos, Line end_line, int end_pos) { StringBuilder sb; ArrayList fonts; ArrayList colors; Color color; + Color back_color; Font font; Line line; LineTag tag; + TextPositioning text_position; + HorizontalAlignment line_alignment; + float spacing_after; + float spacing_before; + float line_spacing; + bool line_spacing_multiple; + float left_indent; + float prev_left_indent; + float first_line_indent; + float prev_first_line_indent; + float right_indent; + TabStopCollection tabs; + TabStopCollection tabDiff; + bool emit_defaults; + float char_offset; + bool visible; int pos; int line_no; int line_len; - int i; + int i, j; int length; + float ppt; // pixels per twip + + ppt = document.Dpi / 1440f; // 1 twip = 1/20 point, 1 point = 1/72 inch, thus 1440 twips = 1 inch. + emit_defaults = false; sb = new StringBuilder(); fonts = new ArrayList(10); colors = new ArrayList(10); + tabDiff = new TabStopCollection (); // Two runs, first we parse to determine tables; // and unlike most of our processing here we work on tags @@ -1949,6 +2561,7 @@ namespace System.Windows.Forms { tag = LineTag.FindTag(start_line, pos); font = tag.Font; color = tag.Color; + back_color = Color.Empty; fonts.Add(font.Name); colors.Add(color); @@ -1972,11 +2585,18 @@ namespace System.Windows.Forms { if (tag.Color != color) { color = tag.Color; - if (!colors.Contains(color)) { + if (color != Color.Empty && !colors.Contains (color)) { colors.Add(color); } } + if (tag.BackColor != back_color) { + back_color = tag.BackColor; + if (back_color != Color.Empty && !colors.Contains (back_color)) { + colors.Add (back_color); + } + } + pos = tag.Start + tag.Length - 1; tag = tag.Next; } @@ -2008,7 +2628,7 @@ namespace System.Windows.Forms { // Emit the color table (if needed) if ((colors.Count > 1) || ((((Color)colors[0]).R != this.ForeColor.R) || (((Color)colors[0]).G != this.ForeColor.G) || (((Color)colors[0]).B != this.ForeColor.B))) { - sb.Append("{\\colortbl "); // Header and NO! default color + sb.Append("{\\colortbl;"); // Header and default color (default is needed) for (i = 0; i < colors.Count; i++) { sb.Append(String.Format("\\red{0}", ((Color)colors[i]).R)); sb.Append(String.Format("\\green{0}", ((Color)colors[i]).G)); @@ -2020,17 +2640,24 @@ namespace System.Windows.Forms { } sb.Append("{\\*\\generator Mono RichTextBox;}"); - // Emit initial paragraph settings - tag = LineTag.FindTag(start_line, start_pos); - sb.Append("\\pard"); // Reset to default paragraph properties - EmitRTFFontProperties(sb, -1, fonts.IndexOf(tag.Font.Name), null, tag.Font); // Font properties - sb.Append(" "); // Space separator + tag = LineTag.FindTag (start_line, start_pos); font = tag.Font; - color = (Color)colors[0]; + color = Color.Empty; + back_color = Color.Empty; + text_position = TextPositioning.Normal; + char_offset = 0; + visible = true; line = start_line; line_no = start_line.line_no; pos = start_pos; + LoadParaSettings (line, out line_alignment, out spacing_after, out spacing_before, out line_spacing, + out line_spacing_multiple, out left_indent, out prev_left_indent, out first_line_indent, + out prev_first_line_indent, out right_indent, out tabs); + + EmitPard (sb, fonts, line, tag, tabs, ppt); + EmitRTFFontProperties (sb, -1, fonts.IndexOf (tag.Font.Name), null, tag.Font); // Font properties + sb.Append(" "); // Space separator while (line_no <= end_line.line_no) { line = document.GetLine(line_no); @@ -2042,7 +2669,110 @@ namespace System.Windows.Forms { line_len = end_pos; } - while (pos < line_len) { + i = 0; + j = 0; + tabDiff.Clear (); + emit_defaults = line.TabStops.Count < tabs.Count; // If there are less tabs on the new line, we've got to start over. + while (!emit_defaults && i < tabs.Count && j < line.TabStops.Count) { + if (tabs [i].Equals (line.TabStops [j])) { + i++; + j++; + } else if (tabs [i].Position - ppt > line.TabStops [j].Position) { + // The current tabstop is after the new line's one, so we need to add one in between. + tabDiff.Add (line.TabStops [j]); + j++; + } else { + // Either the tabs are at the same position and are of different types, or this line is missing at least one. + // This in turn means we must start the line with a \pard, and re-emit all other paragraph properties. + emit_defaults = true; + } + } + if (i < tabs.Count) // We didn't reach the end of the existing tabstops, so the rest have to be removed. + emit_defaults = true; + while (!emit_defaults && j < line.TabStops.Count) { // Any new ones have to be added on the end too. + tabDiff.Add (line.TabStops[j]); + j++; + } + tabs = line.TabStops; + + if (!emit_defaults) { + length = sb.Length; + if (line.Alignment != line_alignment) { + line_alignment = line.Alignment; + switch (line_alignment) { + case HorizontalAlignment.Left: + sb.Append("\\ql"); + break; + case HorizontalAlignment.Center: + sb.Append("\\qc"); + break; + case HorizontalAlignment.Right: + sb.Append("\\qr"); + break; + } + } + + if (Math.Abs(line.spacing_after - spacing_after) > ppt) { + spacing_after = line.spacing_after; + sb.Append("\\sa"); + sb.Append(Int(spacing_after / ppt)); + } + + if (Math.Abs(line.spacing_before - spacing_before) > ppt) { + spacing_before = line.spacing_before; + sb.Append("\\sb"); + sb.Append(Int(spacing_before / ppt)); + } + + if (Math.Abs(line.line_spacing - line_spacing) > ppt) { + line_spacing = line.line_spacing; + sb.Append("\\sl"); + sb.Append(Int(line.line_spacing / ppt)); + } + + if (line.line_spacing_multiple != line_spacing_multiple) { + line_spacing_multiple = line.line_spacing_multiple; + sb.Append("\\slmult"); + sb.Append(line.line_spacing_multiple ? "1" : "0"); + } + + first_line_indent = -line.HangingIndent; + left_indent = line.Indent - first_line_indent; + + if (Math.Abs(prev_left_indent - left_indent) > ppt) { + prev_left_indent = left_indent; + sb.Append("\\li"); + sb.Append(Int(left_indent / ppt)); + } + + if (Math.Abs(prev_first_line_indent - first_line_indent) > ppt) { + prev_first_line_indent = first_line_indent; + sb.Append("\\fi"); + sb.Append(Int(first_line_indent / ppt)); + } + + if (Math.Abs(line.right_indent - right_indent) > ppt) { + right_indent = line.right_indent; + sb.Append("\\ri"); + sb.Append(Int(right_indent / ppt)); + } + + if (tabDiff.Count > 0) { + EmitTabStops(sb, tabDiff); + } + + if (length != sb.Length) { + sb.Append(" "); + } + } else { + EmitPard (sb, fonts, line, tag, tabs, ppt); + sb.Append(" "); + LoadParaSettings (line, out line_alignment, out spacing_after, out spacing_before, out line_spacing, + out line_spacing_multiple, out left_indent, out prev_left_indent, out first_line_indent, + out prev_first_line_indent, out right_indent, out tabs); + } + + while (pos < line_len && tag != null) { length = sb.Length; if (tag.Font != font) { @@ -2052,14 +2782,65 @@ namespace System.Windows.Forms { if (tag.Color != color) { color = tag.Color; - sb.Append(String.Format("\\cf{0}", colors.IndexOf(color))); + if (color != Color.Empty) + sb.Append(String.Format("\\cf{0}", colors.IndexOf(color) + 1)); + else + sb.Append("\\cf0"); + } + + if (tag.BackColor != back_color) { + back_color = tag.BackColor; + if (back_color != Color.Empty) + sb.Append(String.Format("\\cb{0}", colors.IndexOf(back_color) + 1)); + else + sb.Append("\\cb0"); + } + + if (tag.TextPosition != text_position) { + if (text_position != TextPositioning.Normal && tag.TextPosition != TextPositioning.Normal) + sb.Append("\\nosupersub"); + // Technically it is possible to have subscripts in superscript and vise versa. But that's not what we've got. + text_position = tag.TextPosition; + switch (tag.TextPosition) { + case TextPositioning.Normal: + sb.Append("\\nosupersub"); + break; + case TextPositioning.Subscript: + sb.Append("\\sub"); + break; + case TextPositioning.Superscript: + sb.Append("\\super"); + break; + } + } + + if (tag.CharOffset != char_offset) { + char_offset = tag.CharOffset; + if (char_offset >= 0) { + sb.Append("\\up"); + sb.Append(Int((char_offset / document.Dpi) * 144)); + } else { + sb.Append("\\dn"); + sb.Append(-Int((char_offset / document.Dpi) * 144)); + } + } + + if (tag.Visible != visible) { + visible = tag.Visible; + if (visible) + sb.Append("\\v0"); + else + sb.Append("\\v"); } + if (length != sb.Length) { sb.Append(" "); // Emit space to separate keywords from text } // Emit the string itself - if (line_no != end_line.line_no) { + if (tag is PictureTag) { + EmitRtfPicture((PictureTag)tag, sb); + } else if (line_no != end_line.line_no) { EmitRTFText(sb, tag.Line.text.ToString(pos, tag.Start + tag.Length - pos - 1)); } else { if (end_pos < (tag.Start + tag.Length - 1)) { @@ -2071,11 +2852,16 @@ namespace System.Windows.Forms { } pos = tag.Start + tag.Length - 1; - tag = tag.Next; + do { + tag = tag.Next; + } while (tag != null && tag.IsTextTag && tag.Length == 0); } if (pos >= line.text.Length) { if (line.ending != LineEnding.Wrap) { - sb.Append("\\par"); + // pos is incremented by the tag length, so it can be after where we want to finish. + // If we're on the last line we don't want to output \par when we're stopping before the end of the line. + if (!(line_no == end_line.line_no && pos > end_pos)) + sb.Append("\\par"); sb.Append(Environment.NewLine); } } @@ -2088,6 +2874,11 @@ namespace System.Windows.Forms { return sb; } + + int Int (float f) + { + return (int)(f + 0.5f); + } #endregion // Private Methods } } diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TabStops.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TabStops.cs new file mode 100644 index 00000000000..6226024cdc1 --- /dev/null +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TabStops.cs @@ -0,0 +1,258 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2015 Karl Scowen +// +// Authors: +// Karl Scowen <contact@scowencomputers.co.nz> +// +// + +using System; +using System.Collections.Generic; + +namespace System.Windows.Forms { + abstract class TabStop : IComparable<TabStop> { + float _pos = -1; + + internal float Position { + get { + return _pos; + } + + set { + if (_pos >= 0) + throw new InvalidOperationException ("Can't change Position once it has been set!"); + + _pos = value; + } + } + + internal virtual float GetInitialWidth (Line line, int pos) + { + return 0; + } + + internal abstract float CalculateRight (Line line, int pos); + + public override bool Equals (object obj) + { + return obj.GetType () == this.GetType () && Math.Abs (((TabStop)obj).Position - Position) < 0.01; + } + + public override int GetHashCode () + { + return this.GetType ().GetHashCode () ^ Position.GetHashCode (); + } + + public override string ToString () + { + return string.Format ("[{0}: Position {1}]", this.GetType().Name, Position); + } + + #region IComparable implementation + public int CompareTo (TabStop other) + { + return Position.CompareTo (other.Position); + } + + #endregion + } + + class LeftTabStop : TabStop { + internal LeftTabStop () + { + } + internal LeftTabStop (float position) + { + Position = position; + } + + internal override float GetInitialWidth (Line line, int pos) + { + return Position - line.widths[pos]; + } + + internal override float CalculateRight (Line line, int pos) + { + return Position; + } + } + + class CentredTabStop : TabStop { + internal override float CalculateRight (Line line, int pos) + { + int endIndex = line.Text.IndexOfAny (new [] {'\t', '\n', '\r'}, pos + 1); // pos is this tab's index, so look after that. + if (endIndex < 0) + endIndex = line.text.Length; + float textWidth = line.widths [endIndex] - line.widths [pos + 1]; // We use the position after this tabstop, hence pos + 1. + return Math.Max (Position - textWidth / 2f, line.widths [pos]); // We want the width until the start of the text, which is before Position, but we can't go below zero. + } + } + + internal class RightTabStop : TabStop { + internal override float CalculateRight (Line line, int pos) + { + int endIndex = line.Text.IndexOfAny (new [] {'\t', '\n', '\r'}, pos + 1); // pos is this tab's index, so look after that. + return calcWidth (line, pos, endIndex); + } + + protected float calcWidth (Line line, int pos, int endIndex) + { + if (endIndex < 0) + endIndex = line.text.Length; + float textWidth = line.widths [endIndex] - line.widths [pos + 1]; // We use the position after this tabstop, hence pos + 1. + return Math.Max (Position - textWidth, line.widths [pos]); + } + } + + internal class DecimalTabStop : RightTabStop { + internal override float CalculateRight (Line line, int pos) + { + // This is simply a right-align tabstop that regards the decimal as the end. + int endIndex = line.Text.IndexOfAny (new [] {'\t', '\n', '\r', '.'}, pos + 1); // pos is this tab's index, so look after that. + return calcWidth (line, pos, endIndex); + } + } + + internal class TabStopCollection : IList<TabStop> { + SortedList<TabStop, TabStop> tabs = new SortedList<TabStop, TabStop> (); + + public TabStopCollection Clone () + { + var n = new TabStopCollection (); + foreach (var tab in tabs.Keys) { + n.tabs.Add (tab, null); + } + return n; + } + + public int IndexOf (TabStop tab) + { + return tabs.IndexOfKey (tab); + } + + public void Insert (int index, TabStop item) + { + throw new NotSupportedException ("Not relevant to sorted data!"); + } + + public void RemoveAt (int index) + { + tabs.RemoveAt (index); + } + + public TabStop this [int index] { + get { + return tabs.Keys [index]; + } + set { + throw new NotSupportedException ("Not relevant to sorted data!"); + } + } + + #region ICollection implementation + public void Add (TabStop tab) + { + tabs.Add (tab, null); + } + + public void Clear () + { + tabs.Clear (); + } + + public bool Contains (TabStop tab) + { + return tabs.ContainsKey (tab); + } + + public void CopyTo (TabStop[] array, int arrayIndex) + { + tabs.Keys.CopyTo (array, arrayIndex); + } + + public TabStop[] ToArray () + { + var arr = new TabStop [Count]; + CopyTo (arr, 0); + return arr; + } + + public int[] ToPosArray () + { + var arr = new int [Count]; + for (int i = 0; i < Count; i++) { + arr [i] = (int)this [i].Position; + } + return arr; + } + + public bool Remove (TabStop tab) + { + return tabs.Remove (tab); + } + + public int Count { + get { + return tabs.Count; + } + } + + bool ICollection<TabStop>.IsReadOnly { + get { + return false; + } + } + #endregion + + #region IEnumerable implementation + public IEnumerator<TabStop> GetEnumerator () + { + return tabs.Keys.GetEnumerator (); + } + #endregion + + #region IEnumerable implementation + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + return GetEnumerator (); + } + #endregion + + public override bool Equals (object obj) + { + var other = obj as TabStopCollection; + if (other == null || other.Count != this.Count) + return false; + + for (int i = 0; i < Count; i++) { + if (!tabs.Keys [i].Equals (other.tabs.Keys [i])) + return false; + } + return true; + } + + public override int GetHashCode () + { + // I don't like warnings, but I honestly don't care about the hash code. + return base.GetHashCode (); + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs index a2cc8560ffd..b4440143b76 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextBoxBase.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok pbartok@novell.com +// Karl Scowen <contact@scowencomputers.co.nz> // // @@ -116,8 +117,7 @@ namespace System.Windows.Forms current_link = null; show_caret_w_selection = (this is TextBox); document = new Document(this); - document.WidthChanged += new EventHandler(document_WidthChanged); - document.HeightChanged += new EventHandler(document_HeightChanged); + document.SizeChanged += new EventHandler<Document.SizeChangedEventArgs> (document_SizeChanged); //document.CaretMoved += new EventHandler(CaretMoved); document.Wrap = false; click_last = DateTime.Now; @@ -296,8 +296,7 @@ namespace System.Windows.Forms if (value == actual_border_style) return; - if (actual_border_style != BorderStyle.Fixed3D || value != BorderStyle.Fixed3D) - Invalidate (); + Invalidate (); actual_border_style = value; document.UpdateMargins (); @@ -617,7 +616,10 @@ namespace System.Windows.Forms Line line = null; for (int i = 1; i <= document.Lines; i++) { line = document.GetLine (i); - sb.Append(line.text.ToString ()); + if (i == document.Lines) + sb.Append(line.TextWithoutEnding ()); + else + sb.Append(line.text.ToString ()); } return sb.ToString(); @@ -2043,22 +2045,24 @@ namespace System.Windows.Forms Invalidate(); } - internal void CalculateScrollBars () + internal bool CalculateScrollBars () { - // FIXME - need separate calculations for center and right alignment + var old_canvas_width = canvas_width; + SizeControls (); - if (document.Width >= document.ViewPortWidth) { + if (document.Width > document.ViewPortWidth) { hscroll.SetValues (0, Math.Max (1, document.Width), -1, document.ViewPortWidth < 0 ? 0 : document.ViewPortWidth); if (document.multiline) hscroll.Enabled = true; } else { hscroll.Enabled = false; + hscroll.Value = hscroll.Minimum; hscroll.Maximum = document.ViewPortWidth; } - if (document.Height >= document.ViewPortHeight) { + if (document.Height > document.ViewPortHeight) { vscroll.SetValues (0, Math.Max (1, document.Height), -1, document.ViewPortHeight < 0 ? 0 : document.ViewPortHeight); if (document.multiline) @@ -2109,16 +2113,16 @@ namespace System.Windows.Forms PositionControls (); SizeControls (); //Update sizings now we've decided whats visible - } - private void document_WidthChanged (object sender, EventArgs e) - { - CalculateScrollBars(); + return (canvas_width != old_canvas_width); } - private void document_HeightChanged (object sender, EventArgs e) + private void document_SizeChanged (object sender, Document.SizeChangedEventArgs e) { - CalculateScrollBars(); + var canvas_width_changed = CalculateScrollBars (); + if (e.HeightChanged && canvas_width_changed) + CalculateDocument (); // Viewport has changed due to the document change, update the document. + // TODO: technically the opposite situation could happen too, where a document width change causes a change in canvas height. } private void ScrollLinks (int xChange, int yChange) @@ -2311,40 +2315,41 @@ namespace System.Windows.Forms // If the caret moves to the left outside the visible area, we jump the document into view, not just one // character, but 1/3 of the width of the document // If the caret moves to the right outside the visible area, we scroll just enough to keep the caret visible + // For comparison, in Windows 8.1 / .Net 4: + // Multiline: as above, but 1/4 + // Single line: either direction with the cursors jumps 1/4 + // Both are irrespective of alignment. // Handle horizontal scrolling - if (document.CaretLine.alignment == HorizontalAlignment.Left) { - // Check if we moved out of view to the left - if (pos.X < (document.ViewPortX)) { - do { - if ((hscroll.Value - document.ViewPortWidth / 3) >= hscroll.Minimum) { - hscroll.SafeValueSet (hscroll.Value - document.ViewPortWidth / 3); - } else { - hscroll.Value = hscroll.Minimum; - } - } while (hscroll.Value > pos.X); - } + // Check if we moved out of view to the left + if (pos.X < (document.ViewPortX)) { + do { + var newVal = hscroll.Value - document.ViewPortWidth / 3 - 1; // - 1 so that we're guaranteed to move, even if document.ViewPortWidth is < 3. + if (newVal >= hscroll.Minimum) { + hscroll.SafeValueSet (newVal); + } else { + hscroll.Value = hscroll.Minimum; + } + } while (hscroll.Value > pos.X); + } - // Check if we moved out of view to the right - if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) { - if ((pos.X - document.ViewPortWidth + 1) <= hscroll.Maximum) { - if (pos.X - document.ViewPortWidth >= 0) { - hscroll.SafeValueSet (pos.X - document.ViewPortWidth + 1); - } else { - hscroll.Value = 0; - } + // Check if we moved out of view to the right + if ((pos.X >= (document.ViewPortWidth + document.ViewPortX)) && (hscroll.Value != hscroll.Maximum)) { + int newVal; + if (Multiline) { + newVal = pos.X - document.ViewPortWidth + 1; + } else { + newVal = pos.X - document.ViewPortWidth * 2 / 3 + 1; + } + if (newVal <= hscroll.Maximum - document.ViewPortWidth + 1) { + if (newVal >= 0) { + hscroll.SafeValueSet (newVal); } else { - hscroll.Value = hscroll.Maximum; + hscroll.Value = 0; } + } else { + hscroll.Value = hscroll.Maximum - document.ViewPortWidth + 1; } - } else if (document.CaretLine.alignment == HorizontalAlignment.Right) { -// hscroll.Value = pos.X; - -// if ((pos.X > (this.canvas_width + document.ViewPortX)) && (hscroll.Enabled && (hscroll.Value != hscroll.Maximum))) { -// hscroll.Value = hscroll.Maximum; -// } - } else { - // FIXME - implement center cursor alignment } if (Text.Length > 0) @@ -2354,7 +2359,10 @@ namespace System.Windows.Forms return; // Handle vertical scrolling - height = document.CaretLine.Height + 1; + height = document.CaretLine.Height; + + if (document.CaretLine.line_no < document.Lines) + height += 1; // Add a bit of room on the bottom if there are more lines - but don't scroll past the bottom when ther aren't. if (pos.Y < document.ViewPortY) vscroll.SafeValueSet (pos.Y); diff --git a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs index 24859dbf3fb..cf65c990cbf 100644 --- a/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs +++ b/mcs/class/System.Windows.Forms/System.Windows.Forms/TextControl.cs @@ -21,6 +21,7 @@ // // Authors: // Peter Bartok pbartok@novell.com +// Karl Scowen <contact@scowencomputers.co.nz> // // @@ -47,6 +48,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Drawing; using System.Drawing.Text; using System.Text; @@ -71,6 +73,17 @@ namespace System.Windows.Forms { BackColor = 2, Font = 4, Color = 8, + TextPosition = 16, + CharOffset = 32, + Visibility = 64, + + All = 126 + } + + internal enum TextPositioning { + Normal, + Superscript, + Subscript } internal enum CaretDirection { @@ -103,7 +116,7 @@ namespace System.Windows.Forms { None = 0 } - + internal class Document : ICloneable, IEnumerable { #region Structures // FIXME - go through code and check for places where @@ -224,7 +237,7 @@ namespace System.Windows.Forms { internal int viewport_x; internal int viewport_y; // The visible area of the document internal int offset_x; - internal int offset_y; + internal int offset_y; // Never assigned to except in constructor, and a property that is also never assigned to? internal int viewport_width; internal int viewport_height; @@ -240,6 +253,8 @@ namespace System.Windows.Forms { internal int left_margin = 2; // A left margin for all lines internal int top_margin = 2; internal int right_margin = 2; + + internal float dpi; #endregion // Local Variables #region Constructors @@ -301,6 +316,15 @@ namespace System.Windows.Forms { #endregion #region Internal Properties + + internal float Dpi { + get { + if (dpi > 0) + return dpi; + return TextRenderer.GetDpi ().Height; + } + } + internal Line Root { get { return document; @@ -400,7 +424,8 @@ namespace System.Windows.Forms { internal int Length { get { - return char_count + lines - 1; // Add \n for each line but the last + var lastLine = GetLine (lines); + return char_count - LineEndingLength (lastLine.ending); } } @@ -683,12 +708,8 @@ namespace System.Windows.Forms { } private void IncrementLines(int line_no) { - int current; - - current = this.lines; - while (current >= line_no) { - GetLine(current).line_no++; - current--; + foreach (var line in TransverseLines(this.lines, line_no)) { + line.line_no++; } return; } @@ -868,19 +889,27 @@ namespace System.Windows.Forms { return; } + var prev_line_pos = new Point(line.X, line.Y); + var prev_line_bottom = line.Y + line.Height; + var prev_pos_width = line.widths[pos]; + float prev_pos1_width = (line.widths.Length > pos + 1) ? line.widths[pos + 1] : prev_pos_width; + // Optimize invalidation based on Line alignment bool height_changed; using (var graphics = owner.CreateGraphics()) height_changed = RecalculateDocument(graphics, line.line_no, line.line_no, true); + var x = Math.Min(prev_line_pos.X, line.X); + var y = Math.Min(prev_line_pos.Y, line.Y); + var h = Math.Max(prev_line_bottom, line.Y + line.Height) - y; if (height_changed) { // Lineheight changed, invalidate the rest of the document - if ((line.Y - viewport_y) >=0 ) { + if ((y - viewport_y) >=0 ) { // We formatted something that's in view, only draw parts of the screen owner.Invalidate(new Rectangle( offset_x, - line.Y - viewport_y + offset_y, + y - viewport_y + offset_y, viewport_width, - owner.Height - (line.Y - viewport_y))); + owner.Height - (y - viewport_y))); } else { // The tag was above the visible area, draw everything owner.Invalidate(); @@ -889,28 +918,28 @@ namespace System.Windows.Forms { switch(line.alignment) { case HorizontalAlignment.Left: { owner.Invalidate(new Rectangle( - line.X + ((int)line.widths[pos] - viewport_x - 1) + offset_x, - line.Y - viewport_y + offset_y, + x + ((int)Math.Max(line.widths[pos], prev_pos_width) - viewport_x - 1) + offset_x, + y - viewport_y + offset_y, viewport_width, - line.height + 1)); + h + 1)); break; } case HorizontalAlignment.Center: { owner.Invalidate(new Rectangle( - line.X + offset_x, - line.Y - viewport_y + offset_y, + x + offset_x, + y - viewport_y + offset_y, viewport_width, - line.height + 1)); + h + 1)); break; } case HorizontalAlignment.Right: { owner.Invalidate(new Rectangle( - line.X + offset_x, - line.Y - viewport_y + offset_y, - (int)line.widths[pos + 1] - viewport_x + line.X, - line.height + 1)); + x + offset_x, + y - viewport_y + offset_y, + (int)Math.Max(line.widths[pos + ((line.widths.Length > pos + 1) ? 1 : 0)], prev_pos1_width) - viewport_x + line.X, + h + 1)); break; } } @@ -1248,6 +1277,14 @@ namespace System.Windows.Forms { internal void PositionCaret(Line line, int pos) { caret.tag = line.FindTag (pos); + if (pos == caret.tag.Start - 1 && caret.tag.Length != 0 && caret.tag.Previous != null) + caret.tag = caret.tag.Previous; + // When we're at a tag boundary we want the cursor in the previous (left) tag + // whereas FindTag(pos) gets the next (right) tag. LineTag.Start is 1-based. + + if (pos > line.TextLengthWithoutEnding()) + pos = line.TextLengthWithoutEnding(); + // We don't want the caret after the line ending. MoveCaretToTextTag (); @@ -1256,20 +1293,15 @@ namespace System.Windows.Forms { if (owner.IsHandleCreated) { if (owner.Focused) { - if (caret.height != caret.tag.Height) + if (caret.height != caret.tag.DrawnHeight) { + caret.height = caret.tag.DrawnHeight; XplatUI.CreateCaret (owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, - offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, - offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + } + SetCaretPos(); } if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); } - - // We set this at the end because we use the heights to determine whether or - // not we need to recreate the caret - caret.height = caret.tag.Height; - } internal void PositionCaret(int x, int y) { @@ -1278,17 +1310,20 @@ namespace System.Windows.Forms { } caret.tag = FindCursor(x, y, out caret.pos); + + if (caret.pos > caret.tag.Line.TextLengthWithoutEnding()) + caret.pos = caret.tag.Line.TextLengthWithoutEnding(); + // Don't allow the caret to be positioned after the line ending. + // This was happening with the up and down arrows due to how FindCursor works. MoveCaretToTextTag (); caret.line = caret.tag.Line; - caret.height = caret.tag.Height; + caret.height = caret.tag.DrawnHeight; if (owner.ShowSelection && (!selection_visible || owner.show_caret_w_selection)) { XplatUI.CreateCaret (owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, - (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x + offset_x, - offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + SetCaretPos(); } if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); @@ -1297,9 +1332,7 @@ namespace System.Windows.Forms { internal void CaretHasFocus() { if ((caret.tag != null) && owner.IsHandleCreated) { XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, - offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, - offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + SetCaretPos(); DisplayCaret (); } @@ -1337,17 +1370,15 @@ namespace System.Windows.Forms { // font is larger than the line (line recalculations // ignore empty tags) in which case we make it equal // the line height and then when text is entered - if (caret.tag.Height > caret.tag.Line.Height) { - caret.height = caret.line.height; + if (caret.tag.DrawnHeight > caret.tag.Line.TextHeight) { + caret.height = caret.line.TextHeight; } else { - caret.height = caret.tag.Height; + caret.height = caret.tag.DrawnHeight; } if (owner.Focused) { XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos (owner.Handle, - offset_x + (int) caret.tag.Line.widths [caret.pos] + caret.line.X - viewport_x, - offset_y + caret.line.Y + viewport_y + caret_shift); + SetCaretPos(); DisplayCaret (); } @@ -1361,23 +1392,30 @@ namespace System.Windows.Forms { MoveCaretToTextTag (); - if (caret.tag.Height != caret.height) { - caret.height = caret.tag.Height; + if (caret.tag.DrawnHeight != caret.height) { + caret.height = caret.tag.DrawnHeight; if (owner.Focused) { XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); } } if (owner.Focused) { - XplatUI.SetCaretPos(owner.Handle, - offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, - offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + SetCaretPos(); DisplayCaret (); } if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); } + void SetCaretPos () + { + XplatUI.SetCaretPos (owner.Handle, + (int)Math.Min(offset_x + caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, + viewport_width - caret.tag.Line.right_indent - caret_width), // Limit X, because whitespace can be outside this. + (int)(offset_y + caret.line.Y + caret.line.SpacingBefore + caret.tag.OffsetY - + caret.tag.CharOffset + caret.tag.Shift - viewport_y + caret_shift)); + } + internal void DisplayCaret() { if (!owner.IsHandleCreated) { return; @@ -1417,6 +1455,10 @@ namespace System.Windows.Forms { // FIXME should we use IsWordSeparator to detect whitespace, instead // of looking for actual spaces in the Word move cases? + Line currentLine = caret.line; + int currentPos = caret.pos; + LineTag currentTag = caret.tag; + bool nowrap = false; switch(direction) { case CaretDirection.CharForwardNoWrap: @@ -1444,7 +1486,7 @@ namespace System.Windows.Forms { } } UpdateCaret(); - return; + break; } case CaretDirection.CharBackNoWrap: @@ -1452,12 +1494,10 @@ namespace System.Windows.Forms { goto case CaretDirection.CharBack; case CaretDirection.CharBack: { if (caret.pos > 0) { - // caret.pos--; // folded into the if below + caret.pos--; - if (--caret.pos > 0) { - if (caret.tag.Start > caret.pos) { - caret.tag = caret.tag.Previous; - } + if (caret.tag.Start > caret.pos && caret.tag.Previous != null) { + caret.tag = caret.tag.Previous; } } else { if (caret.line.line_no > 1 && !nowrap) { @@ -1467,7 +1507,7 @@ namespace System.Windows.Forms { } } UpdateCaret(); - return; + break; } case CaretDirection.WordForward: { @@ -1493,7 +1533,7 @@ namespace System.Windows.Forms { } } UpdateCaret(); - return; + break; } case CaretDirection.WordBack: { @@ -1525,31 +1565,31 @@ namespace System.Windows.Forms { } } UpdateCaret(); - return; + break; } case CaretDirection.LineUp: { if (caret.line.line_no > 1) { int pixel; - pixel = (int)caret.line.widths[caret.pos]; + pixel = (int)caret.line.widths[caret.pos] + caret.line.align_shift; PositionCaret(pixel, GetLine(caret.line.line_no - 1).Y); DisplayCaret (); } - return; + break; } case CaretDirection.LineDown: { if (caret.line.line_no < lines) { int pixel; - pixel = (int)caret.line.widths[caret.pos]; + pixel = (int)caret.line.widths[caret.pos] + caret.line.align_shift; PositionCaret(pixel, GetLine(caret.line.line_no + 1).Y); DisplayCaret (); } - return; + break; } case CaretDirection.Home: { @@ -1558,7 +1598,7 @@ namespace System.Windows.Forms { caret.tag = caret.line.tags; UpdateCaret(); } - return; + break; } case CaretDirection.End: { @@ -1567,7 +1607,7 @@ namespace System.Windows.Forms { caret.tag = LineTag.FindTag(caret.line, caret.pos); UpdateCaret(); } - return; + break; } case CaretDirection.PgUp: { @@ -1576,17 +1616,20 @@ namespace System.Windows.Forms { owner.vscroll.Value = 0; Line line = GetLine (1); PositionCaret (line, 0); + break; } int y_offset = caret.line.Y + caret.line.height - 1 - viewport_y; + int expected_y = viewport_y - viewport_height; int index; - LineTag top = FindCursor ((int) caret.line.widths [caret.pos], - viewport_y - viewport_height, out index); + LineTag top = FindCursor ((int) caret.line.widths [caret.pos] + caret.line.align_shift, + expected_y, out index); owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height); - PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y); + PositionCaret ((int) caret.line.widths [caret.pos] + caret.line.align_shift, + (expected_y >= 0) ? y_offset + viewport_y : 0); - return; + break; } case CaretDirection.PgDn: { @@ -1595,23 +1638,26 @@ namespace System.Windows.Forms { owner.vscroll.Value = owner.vscroll.Maximum - viewport_height + 1; Line line = GetLine (lines); PositionCaret (line, line.TextLengthWithoutEnding()); + break; } int y_offset = caret.line.Y - viewport_y; + int expected_y = viewport_y + viewport_height; int index; - LineTag top = FindCursor ((int) caret.line.widths [caret.pos], - viewport_y + viewport_height, out index); + LineTag top = FindCursor ((int) caret.line.widths [caret.pos] + caret.line.align_shift, + expected_y, out index); owner.vscroll.Value = Math.Min (top.Line.Y, owner.vscroll.Maximum - viewport_height); - PositionCaret ((int) caret.line.widths [caret.pos], y_offset + viewport_y); + PositionCaret ((int) caret.line.widths [caret.pos] + caret.line.align_shift, + (expected_y <= document_y - viewport_height) ? y_offset + viewport_y : document_y); - return; + break; } case CaretDirection.CtrlPgUp: { PositionCaret(0, viewport_y); DisplayCaret (); - return; + break; } case CaretDirection.CtrlPgDn: { @@ -1627,7 +1673,7 @@ namespace System.Windows.Forms { } PositionCaret(line, line.Text.Length); DisplayCaret (); - return; + break; } case CaretDirection.CtrlHome: { @@ -1636,7 +1682,7 @@ namespace System.Windows.Forms { caret.tag = caret.line.tags; UpdateCaret(); - return; + break; } case CaretDirection.CtrlEnd: { @@ -1645,7 +1691,7 @@ namespace System.Windows.Forms { caret.tag = LineTag.FindTag(caret.line, caret.pos); UpdateCaret(); - return; + break; } case CaretDirection.SelectionStart: { @@ -1654,7 +1700,7 @@ namespace System.Windows.Forms { caret.tag = selection_start.tag; UpdateCaret(); - return; + break; } case CaretDirection.SelectionEnd: { @@ -1663,22 +1709,38 @@ namespace System.Windows.Forms { caret.tag = selection_end.tag; UpdateCaret(); - return; + break; } } + + if ((caret.pos != currentPos || caret.line != currentLine) && currentTag.Length == 0) { + // Remove the empty tag it was previously on. + if (currentTag.Previous != null) { + currentTag.Previous.Next = currentTag.Next; + } else if (currentTag.Next != null) { + // update line.tags, but don't set it to null! + currentLine.tags = currentTag.Next; + } + if (currentTag.Next != null) + currentTag.Next.Previous = currentTag.Previous; + } } internal void DumpDoc () { - Console.WriteLine ("<doc lines='{0}'>", lines); + Console.WriteLine ("<doc lines='{0}' width='{1}' height='{2}' ownerwidth='{3}' ownerheight='{4}'>", + lines, document_x, document_y, owner.Width, owner.Height); for (int i = 1; i <= lines ; i++) { Line line = GetLine (i); - Console.WriteLine ("<line no='{0}' ending='{1}'>", line.line_no, line.ending); + Console.WriteLine ("<line no='{0}' ending='{1}' x='{2}' y='{3}' width='{4}' height='{5}' indent='{6}' hanging-indent='{7}' right-indent='{8}'>", + line.line_no, line.ending, line.X, line.Y, line.Width, line.Height, line.Indent, line.HangingIndent, line.RightIndent); LineTag tag = line.tags; while (tag != null) { - Console.Write ("\t<tag type='{0}' span='{1}->{2}' font='{3}' color='{4}'>", - tag.GetType (), tag.Start, tag.Length, tag.Font, tag.Color); + Console.Write ("\t<tag type='{0}' span='{1}->{2}' font='{3}' color='{4}' position='{5}' " + + "charoffset='{6}' x='{7}' width='{8}' height='{11}' ascent='{9}' descent='{10}'>", + tag.GetType (), tag.Start, tag.Length, tag.Font, tag.Color, tag.TextPosition, + tag.CharOffset, tag.X, tag.Width, tag.Ascent, tag.Descent, tag.MaxHeight()); Console.Write (tag.Text ()); Console.WriteLine ("</tag>"); tag = tag.Next; @@ -1713,7 +1775,9 @@ namespace System.Windows.Forms { StringBuilder text; // String representing the current line int line_no; Color tag_color; + Color tag_backcolor; Color current_color; + Color current_backcolor; // First, figure out from what line to what line we need to draw GetVisibleLineIndexes (clip, out start, out end); @@ -1730,7 +1794,7 @@ namespace System.Windows.Forms { /// Make sure that we aren't drawing one more line then we need to line = GetLine (end - 1); - if (line != null && clip.Bottom == offset_y + line.Y + line.height - viewport_y) + if (line != null && clip.Bottom == offset_y + line.Y + (int)line.SpacingBefore + line.height - viewport_y) end--; line_no = start; @@ -1748,15 +1812,15 @@ namespace System.Windows.Forms { g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), offset_x + selection_start.line.widths [selection_start.pos] + selection_start.line.X - viewport_x, - offset_y + selection_start.line.Y, + offset_y + selection_start.line.Y, (selection_end.line.X + selection_end.line.widths [selection_end.pos]) - (selection_start.line.X + selection_start.line.widths [selection_start.pos]), - selection_start.line.height); + selection_start.line.height); } while (line_no <= end) { line = GetLine (line_no); - float line_y = line.Y - viewport_y + offset_y; + float line_y = line.Y - viewport_y + offset_y + line.SpacingBefore; tag = line.tags; if (!calc_pass) { @@ -1792,35 +1856,28 @@ namespace System.Windows.Forms { } else if (multiline) { // lets draw some selection baby!! (non multiline selection is drawn outside the loop) g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), - offset_x + line.widths [line_selection_start - 1] + line.X - viewport_x, - line_y, line.widths [line_selection_end - 1] - line.widths [line_selection_start - 1], - line.height); + offset_x + line.widths [line_selection_start - 1] + line.X - viewport_x, line_y - line.SpacingBefore, + line.widths [line_selection_end - 1] - line.widths [line_selection_start - 1], line.height); } } - current_color = line.tags.ColorToDisplay; while (tag != null) { // Skip empty tags - if (tag.Length == 0) { + if (tag.Length == 0 || !tag.Visible) { tag = tag.Next; continue; } - if (((tag.X + tag.Width) < (clip.Left - viewport_x - offset_x)) && - (tag.X > (clip.Right - viewport_x - offset_x))) { + if (((tag.X + tag.Width) < (clip.Left + viewport_x - offset_x)) || + (tag.X > (clip.Right + viewport_x - offset_x))) { + // Don't draw a tag that is horizontally outside the visible region. tag = tag.Next; continue; } - if (tag.BackColor != Color.Empty) { - g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (tag.BackColor), - offset_x + tag.X + line.X - viewport_x, - line_y + tag.Shift, tag.Width, line.height); - } - tag_color = tag.ColorToDisplay; - current_color = tag_color; + tag_backcolor = tag.BackColor; if (!owner.Enabled) { Color a = tag.Color; @@ -1832,26 +1889,36 @@ namespace System.Windows.Forms { } int tag_pos = tag.Start; - current_color = tag_color; while (tag_pos < tag.Start + tag.Length) { int old_tag_pos = tag_pos; if (tag_pos >= line_selection_start && tag_pos < line_selection_end) { current_color = ThemeEngine.Current.ColorHighlightText; tag_pos = Math.Min (tag.End, line_selection_end); + current_backcolor = Color.Empty; } else if (tag_pos < line_selection_start) { current_color = tag_color; tag_pos = Math.Min (tag.End, line_selection_start); + current_backcolor = tag_backcolor; } else { current_color = tag_color; tag_pos = tag.End; + current_backcolor = tag_backcolor; + } + + if (current_backcolor != Color.Empty && current_backcolor != owner.BackColor) { + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (current_backcolor), + offset_x + line.widths [old_tag_pos - 1] + line.X - viewport_x, + line_y - line.SpacingBefore, + line.widths [Math.Min (tag.Start + tag.Length, tag_pos) - 1] - line.widths [old_tag_pos - 1], + line.height); } Rectangle text_size; tag.Draw (g, current_color, offset_x + line.X - viewport_x, - line_y + tag.Shift, + line_y + tag.Shift - tag.CharOffset, old_tag_pos - 1, Math.Min (tag.Start + tag.Length, tag_pos) - 1, text.ToString (), out text_size, tag.IsLink); @@ -1975,7 +2042,21 @@ namespace System.Windows.Forms { internal void Insert (Line line, int pos, bool update_caret, string s) { - Insert (line, pos, update_caret, s, line.FindTag (pos)); + LineTag tag = line.FindTag(pos); + if (tag.Length != 0) { + if (tag.Start == pos + 1) { // pos is zero-based, tag.Start and tag.End are one-based. + // Check for empty tags before this one at the same position + var t = tag.Previous; + while (t != null && t.End == pos + 1) { + if (t.Length == 0) { + tag = t; + break; + } + t = t.Previous; + } + } // There will never be empty tags after this one, because FindTag gets the last tag at the position. + } + Insert (line, pos, update_caret, s, tag); } // Insert text at the given position; use formatting at insertion point for inserted text @@ -2004,9 +2085,11 @@ namespace System.Windows.Forms { // There are no line feeds in our text to be pasted if (break_index == s.Length) { line.InsertString (pos, s, tag); + CharCount += s.Length; } else { // Add up to the first line feed to our current position line.InsertString (pos, s.Substring (0, break_index + LineEndingLength (ending)), tag); + CharCount += break_index + LineEndingLength (ending); // Split the rest of the original line to a new line Split (line, pos + (break_index + LineEndingLength (ending))); @@ -2035,15 +2118,13 @@ namespace System.Windows.Forms { // Add the remainder of the insert text to the split // part of the original line + CharCount += s.Length - break_index; split_line.InsertString (0, s.Substring (break_index)); } // Allow the document to recalculate things ResumeRecalc (false); - // Update our character count - CharCount += s.Length; - UpdateView (line, lines - old_line_count + 1, pos); // Move the caret to the end of the inserted text if requested @@ -2191,8 +2272,15 @@ namespace System.Windows.Forms { if (!multiline) { UpdateView (line, lines, pos); owner.Invalidate (); - } else + } else { + if (line.line_no > 1) { + // If the previous line is wrapped, we update that too in case the wrap point has changed. + var l = GetLine(line.line_no - 1); + if (l != null && (l.ending == LineEnding.None || l.ending == LineEnding.Wrap)) + line = l; + } UpdateView (line, pos); + } } // Deletes a character at or after the given position (depending on forward); it will not delete past line limits @@ -2349,7 +2437,9 @@ namespace System.Windows.Forms { // cover the easy case first if (pos == line.text.Length) { - Add (line.line_no + 1, String.Empty, line.alignment, tag.Font, tag.Color, line.ending); + Add (line.line_no + 1, String.Empty, line.alignment, tag.Font, tag.Color, tag.BackColor, tag.TextPosition, + tag.CharOffset, line.Indent, line.HangingIndent, line.RightIndent, line.spacing_before, line.spacing_after, + line.line_spacing, line.line_spacing_multiple, line.tab_stops, tag.Visible, line.ending); new_line = GetLine (line.line_no + 1); @@ -2382,7 +2472,10 @@ namespace System.Windows.Forms { } // We need to move the rest of the text into the new line - Add (line.line_no + 1, line.text.ToString (pos, line.text.Length - pos), line.alignment, tag.Font, tag.Color, line.ending); + Add (line.line_no + 1, line.text.ToString (pos, line.text.Length - pos), line.alignment, tag.Font, tag.Color, + tag.BackColor, tag.TextPosition, tag.CharOffset, line.Indent, line.HangingIndent, line.RightIndent, + line.spacing_before, line.spacing_after, line.line_spacing, line.line_spacing_multiple, line.tab_stops, + tag.Visible, line.ending); // Now transfer our tags from this line to the next new_line = GetLine(line.line_no + 1); @@ -2515,12 +2608,19 @@ namespace System.Windows.Forms { internal void Add (int LineNo, string Text, HorizontalAlignment align, Font font, Color color, LineEnding ending) { + Add (LineNo, Text, align, font, color, Color.Empty, TextPositioning.Normal, + 0, 0, 0, 0, 0, 0, 0, false, new TabStopCollection(), true, ending); + } + + internal void Add (int LineNo, string Text, HorizontalAlignment align, Font font, Color color, Color back_color, + TextPositioning text_position, float char_offset, float left_indent, float hanging_indent, + float right_indent, float spacing_before, float spacing_after, float line_spacing, + bool line_spacing_multiple, TabStopCollection tab_stops, bool visible, LineEnding ending) + { Line add; Line line; int line_no; - CharCount += Text.Length; - if (LineNo<1 || Text == null) { if (LineNo<1) { throw new ArgumentNullException("LineNo", "Line numbers must be positive"); @@ -2529,7 +2629,10 @@ namespace System.Windows.Forms { } } - add = new Line (this, LineNo, Text, align, font, color, ending); + CharCount += Text.Length; + + add = new Line (this, LineNo, Text, align, font, color, back_color, text_position, char_offset, left_indent, + hanging_indent, right_indent, spacing_before, spacing_after, line_spacing, line_spacing_multiple, tab_stops, visible, ending); line = document; while (line != sentinel) { @@ -2598,7 +2701,7 @@ namespace System.Windows.Forms { Delete (line); } - private void Delete(Line line1) { + internal void Delete(Line line1) { Line line2;// = new Line(); Line line3; @@ -3202,7 +3305,9 @@ namespace System.Windows.Forms { int selection_start_pos = LineTagToCharIndex (selection_start.line, selection_start.pos); SuspendRecalc (); - // First, delete any selected text + var formatTag = selection_start.tag; + + // Delete any selected text if ((selection_start.pos != selection_end.pos) || (selection_start.line != selection_end.line)) { if (selection_start.line == selection_end.line) { undo.RecordDeleteString (selection_start.line, selection_start.pos, selection_end.line, selection_end.pos); @@ -3244,9 +3349,23 @@ namespace System.Windows.Forms { } } + if (!String.IsNullOrEmpty(s)) { + int old_line_count = lines; + Insert(selection_start.line, selection_start.pos, false, s); + Line end_line; + int end_pos; + if (lines == old_line_count) { + end_line = selection_start.line; + end_pos = selection_start.pos + s.Length + 1; + } else { + end_line = GetLine(selection_start.line.line_no + lines - old_line_count); + end_pos = end_line.text.Length; + } + FormatText(selection_start.line, selection_start.pos + 1, end_line, end_pos, formatTag); // 0-base to 1-base... + undo.RecordInsertString(selection_start.line, selection_start.pos, s); + } + - Insert(selection_start.line, selection_start.pos, false, s); - undo.RecordInsertString (selection_start.line, selection_start.pos, s); Line begin_update_line = selection_start.line; int begin_update_pos = selection_start.pos; @@ -3279,6 +3398,11 @@ namespace System.Windows.Forms { ResumeRecalc (false); PositionCaret (selection_start.line, selection_start.pos); + + if (begin_update_line.line_no > selection_start.line.line_no) { + begin_update_line = selection_start.line; + begin_update_pos = selection_start.pos; + } UpdateView (begin_update_line, selection_end.line.line_no - begin_update_line.line_no, begin_update_pos); } @@ -3297,7 +3421,7 @@ namespace System.Windows.Forms { start = chars; chars += line.text.Length; - if (index <= chars) { + if (index < chars) { // we found the line tag = line.tags; @@ -3410,6 +3534,56 @@ namespace System.Windows.Forms { return null; } + internal IEnumerable<Line> TransverseLines (int start, int end) + { + Line l, c, r, prev = null; + bool r2l = start > end; + int number; + if (r2l) { + // swap start and end so that start is less than end + int s = start; + start = end; + end = s; + } + c = document; + while (c != null && c != sentinel) { + l = c.left; + r = c.right; + + if (((r2l && c.line_no < end) || (!r2l && c.line_no > start)) && (r2l ? r : l) != sentinel && (r2l ? r : l) != prev) { + // There's no point going further this way if we're just finding lines we don't want! + c = r2l ? r : l; + continue; + } + + number = c.line_no; + if (number >= start && number <= end) + yield return c; + + if ((r2l && number <= start) || (!r2l && number >= end)) + yield break; // We're done here, no need to look further. + + if ((r2l ? l : r) != sentinel) { + c = r2l ? l : r; + } else { + // If we're on the first-side node, the parent is finished with too (continues up tree), otherwise we're only done with the current node. + // We don't want to come back to first-side nodes we've already done when we do the new parent. + // The highest node we discard is going to be a first-side node, because we're discarding all second-side nodes we run into. + // The exception is when we run off the top, which is just fine too, because we're done. + // But the highest node we discard is already visited, so that is the one we're not allowed back to -- anything higher needs visiting still. + prev = c; + c = c.parent; + // The xor inverts the condition when we're going right-to-left, and therefore trims non-right (i.e. left) branches. + // With both forwards and reverse transversal, prev will be given the first-side node. + while (c != null && c.parent != null && c.right == prev ^ r2l) { + prev = c; + c = c.parent; + } + // And prev is now the previous first-side node, unless we happen to have none remaining! + } + } + } + /// <summary>Retrieve the previous tag; walks line boundaries</summary> internal LineTag PreviousTag(LineTag tag) { Line l; @@ -3539,30 +3713,45 @@ namespace System.Windows.Forms { return tag; } + public void FormatText (Line start_line, int start_pos, Line end_line, int end_pos, LineTag copyFrom) { + FormatText(start_line, start_pos, end_line, end_pos, copyFrom.Font, copyFrom.Color, + copyFrom.BackColor, copyFrom.TextPosition, copyFrom.CharOffset, copyFrom.Visible, FormatSpecified.All); + } + + internal void FormatText (Line start_line, int start_pos, Line end_line, int end_pos, Font font, + Color color, Color back_color, FormatSpecified specified) + { + FormatText (start_line, start_pos, end_line, end_pos, font, color, back_color, + TextPositioning.Normal, 0, true, specified); + } + /// <summary>Format area of document in specified font and color</summary> /// <param name="start_pos">1-based start position on start_line</param> /// <param name="end_pos">1-based end position on end_line </param> internal void FormatText (Line start_line, int start_pos, Line end_line, int end_pos, Font font, - Color color, Color back_color, FormatSpecified specified) + Color color, Color back_color, TextPositioning text_position, float char_offset, + bool visible, FormatSpecified specified) { Line l; // First, format the first line if (start_line != end_line) { // First line - LineTag.FormatText(start_line, start_pos, start_line.text.Length - start_pos + 1, font, color, back_color, specified); + LineTag.FormatText(start_line, start_pos, start_line.text.Length - start_pos + 1, font, color, + back_color, text_position, char_offset, visible, specified); // Format last line - LineTag.FormatText(end_line, 1, end_pos, font, color, back_color, specified); + LineTag.FormatText(end_line, 1, end_pos - 1, font, color, back_color, text_position, char_offset, visible, specified); // Now all the lines inbetween for (int i = start_line.line_no + 1; i < end_line.line_no; i++) { l = GetLine(i); - LineTag.FormatText(l, 1, l.text.Length, font, color, back_color, specified); + LineTag.FormatText(l, 1, l.text.Length, font, color, back_color, text_position, char_offset, visible, specified); } } else { // Special case, single line - LineTag.FormatText(start_line, start_pos, end_pos - start_pos, font, color, back_color, specified); + LineTag.FormatText(start_line, start_pos, end_pos - start_pos, font, color, back_color, + text_position, char_offset, visible, specified); if ((end_pos - start_pos) == 0 && CaretTag.Length != 0) CaretTag = CaretTag.Next; @@ -3582,17 +3771,7 @@ namespace System.Windows.Forms { line = GetLine(line_no); if (line != null) { - switch (line.alignment) { - case HorizontalAlignment.Left: - line.align_shift = 0; - break; - case HorizontalAlignment.Center: - line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2; - break; - case HorizontalAlignment.Right: - line.align_shift = viewport_width - (int)line.widths[line.text.Length] - right_margin; - break; - } + line.CalculateAlignment(); } line_no++; @@ -3623,6 +3802,8 @@ namespace System.Windows.Forms { int new_width; bool changed; int shift; + bool width_changed; + bool height_changed; if (recalc_suspended > 0) { recalc_pending = true; @@ -3641,6 +3822,8 @@ namespace System.Windows.Forms { line_no = start; new_width = 0; shift = this.lines; + width_changed = false; + height_changed = false; if (!optimize) { changed = true; // We always return true if we run non-optimized } else { @@ -3677,17 +3860,10 @@ namespace System.Windows.Forms { } if (line.widths[line.text.Length] > new_width) { - new_width = (int)line.widths[line.text.Length]; + new_width = (int)Math.Ceiling(line.widths[line.text.Length]); } - // Calculate alignment - if (line.alignment != HorizontalAlignment.Left) { - if (line.alignment == HorizontalAlignment.Center) { - line.align_shift = (viewport_width - (int)line.widths[line.text.Length]) / 2; - } else { - line.align_shift = viewport_width - (int)line.widths[line.text.Length] - 1; - } - } + line.CalculateAlignment (); if (multiline) offset += line.height; @@ -3701,22 +3877,22 @@ namespace System.Windows.Forms { if (document_x != new_width) { document_x = new_width; - if (WidthChanged != null) { - WidthChanged(this, null); - } + width_changed = true; } - RecalculateAlignments(); - line = GetLine(lines); if (document_y != line.Y + line.height) { document_y = line.Y + line.height; - if (HeightChanged != null) { - HeightChanged(this, null); - } + height_changed = true; + } + + if (height_changed || width_changed) { + SizeChanged?.Invoke (this, new SizeChangedEventArgs(height_changed)); } + RecalculateAlignments (); + // scan for links and tell us if its all // changed, so we can update everything if (EnableLinks) @@ -3731,13 +3907,15 @@ namespace System.Windows.Forms { } private void owner_HandleCreated(object sender, EventArgs e) { - using (var graphics = owner.CreateGraphics()) + using (var graphics = owner.CreateGraphics()) { + dpi = (graphics.DpiX + graphics.DpiY) / 2; RecalculateDocument(graphics); + } AlignCaret(); } private void owner_VisibleChanged(object sender, EventArgs e) { - if (owner.Visible) { + if (owner.Visible && owner.IsHandleCreated) { using (var graphics = owner.CreateGraphics()) RecalculateDocument(graphics); } @@ -4031,9 +4209,17 @@ namespace System.Windows.Forms { #endregion // Internal Methods #region Events + internal class SizeChangedEventArgs : EventArgs { + public bool HeightChanged { get; } + + public SizeChangedEventArgs (bool HeightChanged) + { + this.HeightChanged = HeightChanged; + } + } + internal event EventHandler CaretMoved; - internal event EventHandler WidthChanged; - internal event EventHandler HeightChanged; + internal event EventHandler<SizeChangedEventArgs> SizeChanged; internal event EventHandler LengthChanged; internal event EventHandler UIASelectionChanged; #endregion // Events @@ -4089,7 +4275,10 @@ namespace System.Windows.Forms { public override SizeF SizeOfPosition (Graphics dc, int pos) { - return picture.Size; + if (Visible) + return picture.Size; + else + return SizeF.Empty; } internal override int MaxHeight () @@ -4099,12 +4288,24 @@ namespace System.Windows.Forms { public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end) { - picture.DrawImage (dc, xoff + Line.widths [start], y, false); + if (Visible) + picture.DrawImage (dc, (xoff + Line.widths [start]), y, false); } public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end, string text) { - picture.DrawImage (dc, xoff + + Line.widths [start], y, false); + Draw (dc, color, xoff, y, start, end); + } + + public override void Draw (Graphics dc, Color color, float xoff, float y, int start, int end, + string text, out Rectangle measuredText, bool measureText) + { + Draw (dc, color, xoff, y, start, end); + if (measureText && Visible) { + measuredText = new Rectangle (Point.Round (new PointF (xoff + Line.widths [start], y)), Size.Round (picture.Size)); + } else { + measuredText = new Rectangle (); + } } public override string Text () |