예제 #1
0
        public static GLine CreateSimpleGLine(string text, TextDecoration dec)
        {
            char[]    buff      = new char[text.Length * 2];
            int       offset    = 0;
            int       start     = 0;
            CharGroup prevType  = CharGroup.LatinHankaku;
            GWord     firstWord = null;
            GWord     lastWord  = null;

            for (int i = 0; i < text.Length; i++)
            {
                char      originalChar = text[i];
                char      privateChar  = Unicode.ToPrivate(originalChar);
                CharGroup nextType     = Unicode.GetCharGroup(privateChar);
                int       size         = CharGroupUtil.GetColumnsPerCharacter(nextType);
                if (nextType != prevType)
                {
                    if (offset > start)
                    {
                        GWord newWord = new GWord(dec, start, prevType);
                        if (lastWord == null)
                        {
                            firstWord = lastWord = newWord;
                        }
                        else
                        {
                            lastWord.Next = newWord;
                            lastWord      = newWord;
                        }
                    }
                    prevType = nextType;
                    start    = offset;
                }

                buff[offset++] = originalChar;
                if (size == 2)
                {
                    buff[offset++] = WIDECHAR_PAD;
                }
            }

            GWord w = new GWord(dec, start, prevType);

            if (lastWord == null)
            {
                firstWord = w;
            }
            else
            {
                lastWord.Next = w;
            }

            return(new GLine(buff, offset, firstWord));
        }
예제 #2
0
        /// <summary>
        /// Gets number of columns used to display a character.
        /// </summary>
        /// <param name="ch">Private character code.</param>
        /// <returns>1 (half-width character) or 2 (full-width character)</returns>
        public static int GetCharacterWidth(char ch)
        {
            CharGroup charGroup = GetCharGroup(ch);

            return(CharGroupUtil.GetColumnsPerCharacter(charGroup));
        }
예제 #3
0
        internal void Render(IntPtr hdc, RenderProfile prof, Color baseBackColor, int x, int y)
        {
            if (_text.Length == 0 || _text[0] == '\0')
            {
                return; //何も描かなくてよい。これはよくあるケース
            }
            float fx0 = (float)x;
            float fx1 = fx0;
            int   y1  = y;
            int   y2  = y1 + (int)prof.Pitch.Height;

            float pitch = prof.Pitch.Width;
            int   defaultBackColorArgb = baseBackColor.ToArgb();

            Win32.SetBkMode(hdc, Win32.TRANSPARENT);

            GWord word = _firstWord;

            while (word != null)
            {
                TextDecoration dec = word.Decoration;

                IntPtr hFont = prof.CalcHFONT_NoUnderline(dec, word.CharGroup);
                Win32.SelectObject(hdc, hFont);

                uint foreColorRef = DrawUtil.ToCOLORREF(prof.CalcTextColor(dec));
                Win32.SetTextColor(hdc, foreColorRef);

                Color bkColor  = prof.CalcBackColor(dec);
                bool  isOpaque = (bkColor.ToArgb() != defaultBackColorArgb);
                if (isOpaque)
                {
                    uint bkColorRef = DrawUtil.ToCOLORREF(bkColor);
                    Win32.SetBkColor(hdc, bkColorRef);
                }

                int nextOffset = GetNextOffset(word);

                float fx2 = fx0 + pitch * nextOffset;

                if (prof.CalcBold(dec) || CharGroupUtil.IsCJK(word.CharGroup))
                {
                    // It is not always true that width of a character in the CJK font is twice of a character in the ASCII font.
                    // Characters are drawn one by one to adjust pitch.

                    int   step      = CharGroupUtil.GetColumnsPerCharacter(word.CharGroup);
                    float charPitch = pitch * step;
                    int   offset    = word.Offset;
                    float fx        = fx1;
                    if (isOpaque)
                    {
                        // If background fill is required, we call ExtTextOut() with ETO_OPAQUE to draw the first character.
                        if (offset < nextOffset)
                        {
                            Win32.RECT rect = new Win32.RECT((int)fx1, y1, (int)fx2, y2);
                            char       ch   = _text[offset];
                            Debug.Assert(ch != GLine.WIDECHAR_PAD);
                            unsafe {
                                Win32.ExtTextOut(hdc, rect.left, rect.top, Win32.ETO_OPAQUE, &rect, &ch, 1, null);
                            }
                        }
                        offset += step;
                        fx     += charPitch;
                    }

                    for (; offset < nextOffset; offset += step)
                    {
                        char ch = _text[offset];
                        Debug.Assert(ch != GLine.WIDECHAR_PAD);
                        unsafe {
                            Win32.ExtTextOut(hdc, (int)fx, y1, 0, null, &ch, 1, null);
                        }
                        fx += charPitch;
                    }
                }
                else
                {
                    int offset        = word.Offset;
                    int displayLength = nextOffset - offset;
                    if (isOpaque)
                    {
                        Win32.RECT rect = new Win32.RECT((int)fx1, y1, (int)fx2, y2);
                        unsafe
                        {
                            fixed(char *p = &_text[offset])
                            {
                                Win32.ExtTextOut(hdc, rect.left, rect.top, Win32.ETO_OPAQUE, &rect, p, displayLength, null);
                            }
                        }
                    }
                    else
                    {
                        unsafe
                        {
                            fixed(char *p = &_text[offset])
                            {
                                Win32.ExtTextOut(hdc, (int)fx1, y1, 0, null, p, displayLength, null);
                            }
                        }
                    }
                }

                if (dec.Underline)
                {
                    DrawUnderline(hdc, foreColorRef, (int)fx1, y2 - 1, (int)fx2 - (int)fx1);
                }

                fx1  = fx2;
                word = word.Next;
            }
        }
예제 #4
0
        /// <summary>
        /// Invert text attribute at the specified position.
        /// </summary>
        /// <remarks>
        /// <para>If doInvert was false, only splitting of GWords will be performed.
        /// It is required to avoid problem when the text which conatins blinking cursor is drawn by DrawWord().</para>
        /// <para>DrawWord() draws contiguous characters at once,
        /// and the character pitch depends how the character in the font was designed.</para>
        /// <para>By split GWord even if inversion is not required,
        /// the position of a character of the blinking cursor will be constant.</para>
        /// </remarks>
        /// <param name="index">Column index to invert.</param>
        /// <param name="doInvert">Whether inversion is really applied.</param>
        /// <param name="color">Background color of the inverted character.</param>
        internal void InvertCharacter(int index, bool doInvert, Color color)
        {
            //先にデータのあるところより先の位置を指定されたらバッファを広げておく
            if (index >= _displayLength)
            {
                int prevLength = _displayLength;
                ExpandBuffer(index + 1);
                for (int i = prevLength; i < index + 1; i++)
                {
                    _text[i] = ' ';
                }
                _displayLength     = index + 1;
                this.LastWord.Next = new GWord(TextDecoration.Default, prevLength, CharGroup.LatinHankaku);
            }
            if (_text[index] == WIDECHAR_PAD)
            {
                index--;
            }

            GWord prev       = null;
            GWord word       = _firstWord;
            int   nextoffset = 0;

            while (word != null)
            {
                nextoffset = GetNextOffset(word);
                if (word.Offset <= index && index < nextoffset)
                {
                    GWord next = word.Next;

                    //キャレットの反転
                    TextDecoration inv_dec = word.Decoration;
                    if (doInvert)
                    {
                        inv_dec = inv_dec.GetInvertedCopyForCaret(color);
                    }

                    //GWordは最大3つ(head:indexの前、middle:index、tail:indexの次)に分割される
                    GWord head      = word.Offset < index ? new GWord(word.Decoration, word.Offset, word.CharGroup) : null;
                    GWord mid       = new GWord(inv_dec, index, word.CharGroup);
                    int   nextIndex = index + CharGroupUtil.GetColumnsPerCharacter(word.CharGroup);
                    GWord tail      = nextIndex < nextoffset ? new GWord(word.Decoration, nextIndex, word.CharGroup) : null;

                    //連結 head,tailはnullのこともあるのでややこしい
                    List <GWord> list = new List <GWord>(3);
                    if (head != null)
                    {
                        list.Add(head);
                        head.Next = mid;
                    }

                    list.Add(mid);
                    mid.Next = tail == null ? next : tail;

                    if (tail != null)
                    {
                        list.Add(tail);
                    }

                    //前後との連結
                    if (prev == null)
                    {
                        _firstWord = list[0];
                    }
                    else
                    {
                        prev.Next = list[0];
                    }

                    list[list.Count - 1].Next = next;

                    break;
                }

                prev = word;
                word = word.Next;
            }
        }
예제 #5
0
        /// <summary>
        /// <ja>
        /// 指定位置に1文字書き込みます。
        /// </ja>
        /// <en>
        /// Write one character to specified position.
        /// </en>
        /// </summary>
        /// <param name="ch"><ja>書き込む文字</ja><en>Character to write.</en></param>
        /// <param name="dec"><ja>テキスト書式を指定するTextDecorationオブジェクト</ja>
        /// <en>TextDecoration object that specifies text format
        /// </en></param>
        public void PutChar(char ch, TextDecoration dec)
        {
            Debug.Assert(dec != null);
            Debug.Assert(_caretColumn >= 0);
            Debug.Assert(_caretColumn < _text.Length);

            char      originalChar = Unicode.ToOriginal(ch);
            CharGroup charGroup    = Unicode.GetCharGroup(ch);

            bool onZenkaku      = (_attrs[_caretColumn].CharGroup == CharGroup.CJKZenkaku);
            bool onZenkakuRight = (_text[_caretColumn] == GLine.WIDECHAR_PAD);

            if (onZenkaku)
            {
                //全角の上に書く
                if (!onZenkakuRight)
                {
                    _text[_caretColumn]  = originalChar;
                    _attrs[_caretColumn] = new CharAttr(dec, charGroup);
                    if (CharGroupUtil.GetColumnsPerCharacter(charGroup) == 1)
                    {
                        //全角の上に半角を書いた場合、隣にスペースを入れないと表示が乱れる
                        _caretColumn++;
                        if (_caretColumn < _text.Length)
                        {
                            _text[_caretColumn]            = ' ';
                            _attrs[_caretColumn].CharGroup = CharGroup.LatinHankaku;
                        }
                    }
                    else
                    {
                        _attrs[_caretColumn + 1] = new CharAttr(dec, charGroup);
                        _caretColumn            += 2;
                    }
                }
                else
                {
                    _text[_caretColumn - 1]            = ' ';
                    _attrs[_caretColumn - 1].CharGroup = CharGroup.LatinHankaku;
                    _text[_caretColumn]  = originalChar;
                    _attrs[_caretColumn] = new CharAttr(dec, charGroup);
                    if (CharGroupUtil.GetColumnsPerCharacter(charGroup) == 2)
                    {
                        if (CharGroupUtil.GetColumnsPerCharacter(_attrs[_caretColumn + 1].CharGroup) == 2)
                        {
                            if (_caretColumn + 2 < _text.Length)
                            {
                                _text[_caretColumn + 2]            = ' ';
                                _attrs[_caretColumn + 2].CharGroup = CharGroup.LatinHankaku;
                            }
                        }
                        _text[_caretColumn + 1]  = GLine.WIDECHAR_PAD;
                        _attrs[_caretColumn + 1] = _attrs[_caretColumn];
                        _caretColumn            += 2;
                    }
                    else
                    {
                        _caretColumn++;
                    }
                }
            }
            else   //半角の上に書く
            {
                _text[_caretColumn]  = originalChar;
                _attrs[_caretColumn] = new CharAttr(dec, charGroup);
                if (CharGroupUtil.GetColumnsPerCharacter(charGroup) == 2)
                {
                    if (CharGroupUtil.GetColumnsPerCharacter(_attrs[_caretColumn + 1].CharGroup) == 2)   //半角、全角となっているところに全角を書いたら
                    {
                        if (_caretColumn + 2 < _text.Length)
                        {
                            _text[_caretColumn + 2]            = ' ';
                            _attrs[_caretColumn + 2].CharGroup = CharGroup.LatinHankaku;
                        }
                    }
                    _text[_caretColumn + 1]  = GLine.WIDECHAR_PAD;
                    _attrs[_caretColumn + 1] = _attrs[_caretColumn];
                    _caretColumn            += 2;
                }
                else
                {
                    _caretColumn++; //これが最もcommonなケースだが
                }
            }
        }