Amro Omran
Amro Omran

Reputation: 1

Need Help How To Draw Both Arabic And English Words Char By Char

I'm trying to draw the same text from textBox to Panel char By Char For both Arabic & English with the same char size and position also style and color my code works perfectly if the text is English language but for Arabic its printing separated chars . I Know if i use DrawString , DrawTextBox or TextRenderer.DrawText strate forward i will get the result but it will show only the first visible liens and can't move through the liens if multiline true or move to the end if multiline false

my problem only in drawing Arabic chars these are what I tried

  1. draw word by word
  2. draw two chars by two chars to make joined chars as Arabic writing but not worked as i want
  3. if the char has space or white space after it handles the chars before as one word but i faced another problem with alignment between Arabic and English and also setting the starting position for each word
  4. -also tried using enum CaseMap { End = 0, Middle = 1, Beginning = 2, Isolated = 3 };
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Microsoft_TextBox
{
    public partial class Arabic_English_Draw_TextBox : Form
    {
        private TextBox textBox1;
        private Panel panel1;
        private Label TexeLabel;
        private Label PanelLabel;
        public Arabic_English_Draw_TextBox()
        {
            InitializeComponent();
            textBox1 = new TextBox();
            this.Controls.Add(textBox1);
            textBox1.Text = "مرحبا بالعالم Hello شكرا I'm trying to draw the same text from textBox to Panel char By Char For Arabic & English ";
            textBox1.Font = new Font("Tahoma", 18, FontStyle.Bold);
            textBox1.Multiline = true;
            textBox1.BorderStyle = BorderStyle.Fixed3D;
            textBox1.Size = new Size(200, 150);
            textBox1.Location = new Point(50, 50);
            textBox1.TextAlign = HorizontalAlignment.Center;
            textBox1.ForeColor = Color.DeepSkyBlue;
            textBox1.TextChanged += textBox1_TextChanged;
            textBox1.KeyDown += textBox1_KeyDown;

            TexeLabel = new Label();
            this.Controls.Add(TexeLabel);
            TexeLabel.Location = new Point(50, 20);
            TexeLabel.Text = "Text Box";



            panel1 = new Panel();
            this.Controls.Add(panel1);
            panel1.BorderStyle = BorderStyle.Fixed3D;
            panel1.Size = new Size(200, 150);
            panel1.Location = new Point(textBox1.Width+ 50, 50);
            panel1.Paint += panel1_Paint; // Hook up the Paint event handler

            PanelLabel = new Label();
            this.Controls.Add(PanelLabel);
            PanelLabel.Location = new Point(panel1.Location.X, 20);
            PanelLabel.Text = "Panel To Draw";


            this.Width = 500;
            this.Height = 300;
            StartPosition = FormStartPosition.CenterScreen;


        }

       
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            panel1.Invalidate();
        }
        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            panel1.Invalidate();
        }



        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            using (SolidBrush br = new SolidBrush(textBox1.ForeColor))
            using (StringFormat sf = new StringFormat())
            {
                // Calculate the width of the text
                SizeF textSize = e.Graphics.MeasureString(textBox1.Text, textBox1.Font, textBox1.ClientSize, sf);
                // Draw each character
                int firstCharIndex = textBox1.GetCharIndexFromPosition(new Point(0, 0));
                int lastCharIndex = textBox1.GetCharIndexFromPosition(new Point(textBox1.ClientSize.Width - 1, textBox1.ClientSize.Height - 1));
                StringBuilder stringBuilder = new StringBuilder(); // Initialize StringBuilder
                int csizeH = 0;
                int csizeW = 0;
                int CCount = 0;
                List<RectangleF> charRects = new List<RectangleF>(); // Store rectangles for each character
                for (int i = firstCharIndex; i <= lastCharIndex && i < textBox1.Text.Length; i++)
                {
                    char Char = textBox1.Text[i];
                    Size charSize = TextRenderer.MeasureText(Char.ToString(), textBox1.Font);

                    // Append each character to the StringBuilder
                    stringBuilder.Append(Char);

                    csizeH = (int)charSize.Height;
                    csizeW = (int)charSize.Width;
                    RectangleF charRect = new RectangleF(
                          textBox1.GetPositionFromCharIndex(i),
                          charSize);
                    switch (textBox1.TextAlign)
                    {
                        case HorizontalAlignment.Left:
                            charRect.Offset(-(int)textBox1.Font.Size / 5f, 0);
                            break;
                        case HorizontalAlignment.Center:
                            charRect.Offset(-(int)textBox1.Font.Size / 2.8f, 0);
                            break;
                        case HorizontalAlignment.Right:
                            charRect.Offset(-(int)textBox1.Font.Size / 2.05f, 0);
                            break;
                    }
                    charRects.Add(charRect); // Store the rectangle for each character
                    CCount = charRects.Count;

                }

                // Determine the start position for drawing the concatenated string
                PointF startPosition = charRects.Count > 0 ? charRects[0].Location : PointF.Empty;
                // Draw each character individually at their respective positions
                for (int i = 0; i < stringBuilder.Length; i++)
                {
                    e.Graphics.DrawString(stringBuilder[i].ToString(), textBox1.Font, br, charRects[i], sf);
                }
            }
        }
    }
}

Draw Arabic & English

Upvotes: 0

Views: 109

Answers (1)

lork6
lork6

Reputation: 154

Oke two thing one TextBox is ignoring the "\n" character. if you put "\r\n" then it will create a new line.

Draw method:

 private void panel1_Paint(object sender, PaintEventArgs e)
 {
     using (SolidBrush br = new SolidBrush(textBox1.ForeColor))
     using (StringFormat sf = new StringFormat())
     {
         //sf.Alignment = StringAlignment.Center;
         sf.Trimming = StringTrimming.EllipsisCharacter;
         
         sf.FormatFlags = StringFormatFlags.MeasureTrailingSpaces ;
         
         // Draw each character
         int firstCharIndex = textBox1.GetCharIndexFromPosition(new Point(1, 1));
         
         int lastCharIndex = textBox1.GetCharIndexFromPosition(new Point(textBox1.ClientSize.Width - 1, textBox1.ClientSize.Height - 1));
         StringBuilder stringBuilder = new StringBuilder(); // Initialize StringBuilder
         
         List<RectangleF> charRects = new List<RectangleF>(); // Store rectangles for each character
         for (int i = firstCharIndex; i <= lastCharIndex && i < textBox1.Text.Length; i++)
         {
             char Char = textBox1.Text[i];
             Size charSize = TextRenderer.MeasureText(Char.ToString(), textBox1.Font);
             var isCharVisible = textBox1.GetPositionFromCharIndex(i);
             if (isCharVisible.Y < 0 || isCharVisible.Y > (textBox1.Height-charSize.Height/2))
             {
                 continue;
             }
             // Append each character to the StringBuilder
             stringBuilder.Append(Char);
             RectangleF charRect = new RectangleF(
                   textBox1.GetPositionFromCharIndex(i),
                   charSize);
            
             charRects.Add(charRect); // Store the rectangle for each character
         }

         int j = 0;
         int count = 0;
         var LineRect = charRects[0];

         for (int i = 1; i < charRects.Count; i++)
         {
             
             if (charRects[i-1].Y != charRects[i].Y || i == charRects.Count-1)
             {
                 // last char
                 if(i == charRects.Count - 1)
                 {
                     // set the location for the minimum X
                     // set the line Rectangel
                     if (LineRect.X < charRects[i].X)
                     {
                         LineRect = new RectangleF(LineRect.X, LineRect.Y, LineRect.Width + charRects[i].Width, LineRect.Height);
                     }
                     else
                     {
                         LineRect = new RectangleF(charRects[i].X, LineRect.Y, LineRect.Width + charRects[i].Width, LineRect.Height);
                     }
                     count++;
                 }
                 // Drawstring line by line
                 e.Graphics.DrawString(stringBuilder.ToString().Substring(j,count), textBox1.Font, br, LineRect, sf);
                 j = i;
                 count = 0;
                 LineRect = charRects[i];
             }
             else
             {
                 // set the location for the minimum X
                 // set the line Rectangel
                 if (LineRect.X < charRects[i].X)
                 {
                     LineRect = new RectangleF(LineRect.X, LineRect.Y, LineRect.Width + charRects[i].Width, LineRect.Height);
                 }
                 else
                 {
                     LineRect = new RectangleF(charRects[i].X, LineRect.Y, LineRect.Width + charRects[i].Width, LineRect.Height);
                 }
                 
             }
             count++;
         }
             
     }
 }

This draw the text line by line from the TextBox. Not perfect but i think is 99% good.

Upvotes: 0

Related Questions