Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Intricate Treeview Design

I am trying to design an IDE-like (Non-Editable) program with a richtextbox control. Basically, I need the treeview which is positioned to the left side of the RTB to expand/collapse a certain portion of my code whenever the user clicks on the +/- buttons. The expandable collapsable ranges are defined as wherever the curly brackets are seen. For instance in the RTB if I had something like:

int main()
{
   if (...)
   {
       if (...)
       {
       }
   }
   else
   {
   }
}

If I were to click on the top-most curly bracket, it would collapse everything inside the main function. Basically what's contained inside that curly bracket is what is folded. So in summary, I'm trying to design something that is very similar to Visual Studio's expand/collapse code function except it also does that with the if/else functions.

I'm aware of the bracket matching algorithm and I implemented a stack to know which pairs of the brackets match (Line numbers stored in a list of tuple).

The issue I'm having majorly is how to go about designing the actual treeview. I need the treeview to be in a linear fashion, where no nodes are added on top of another. I am not aware of any approach which can add the expand/collapse button without actually adding child nodes on top of another node.

Also, with the exception of the +/- buttons and a singular vertical line, I need the treeview nodes to be non-editable, non-visible and non-clickable.

Finally and this is assuming if I fulfilled the above requirements, I need the RTB's vertical scroll event to correctly scroll the treeview as well. That is, the Treeview's collapse/expand section would update based on the portion of the code visible on the RTB.

Here is a section of the code I am using to initialize the tree:

public partial class LogicSimulationViewerForm : Form
{
    private List<Tuple<string,Boolean>> visibleLines = new List<Tuple<string,Boolean>>();
    private List<Tuple<int, int>> collapseRange = new List<Tuple<int, int>>();

    private void TreeInit()
    {
        TreeNode tn;
        Stack<int> openBracketLine = new Stack<int>();
        int i = 0;
        TreeLogicCode.Nodes.Clear();
        foreach (string s in rtbLogicCode.Lines)
        {
            visibleLines.Add(Tuple.Create(s, true));
            if (s == "{")
            {
                openBracketLine.Push(i);
            }
            else if (s == "}")
            {
                collapseRange.Add(Tuple.Create(openBracketLine.Pop(),i));
            }
            i++;
        }
    }

Here is the Designer.sc source code, although I believe this won't really be necessary but just in case:

namespace DDCUI
{
    partial class LogicSimulationViewerForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.TreeLogicCode = new System.Windows.Forms.TreeView();
            this.labelLogicCode = new System.Windows.Forms.Label();
            this.rtbLogicCode = new System.Windows.Forms.RichTextBox();
            this.SuspendLayout();
            // 
            // TreeLogicCode
            // 
            this.TreeLogicCode.Dock = System.Windows.Forms.DockStyle.Left;
            this.TreeLogicCode.Location = new System.Drawing.Point(50, 0);
            this.TreeLogicCode.Name = "TreeLogicCode";
            this.TreeLogicCode.Scrollable = false;
            this.TreeLogicCode.Size = new System.Drawing.Size(40, 600);
            this.TreeLogicCode.TabIndex = 4;
            // 
            // labelLogicCode
            // 
            this.labelLogicCode.BackColor = System.Drawing.Color.LightGray;
            this.labelLogicCode.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.labelLogicCode.Dock = System.Windows.Forms.DockStyle.Left;
            this.labelLogicCode.ForeColor = System.Drawing.SystemColors.ControlText;
            this.labelLogicCode.Location = new System.Drawing.Point(0, 0);
            this.labelLogicCode.Margin = new System.Windows.Forms.Padding(3);
            this.labelLogicCode.Name = "labelLogicCode";
            this.labelLogicCode.Padding = new System.Windows.Forms.Padding(3);
            this.labelLogicCode.Size = new System.Drawing.Size(50, 600);
            this.labelLogicCode.TabIndex = 3;
            this.labelLogicCode.TextAlign = System.Drawing.ContentAlignment.TopRight;
            // 
            // rtbLogicCode
            // 
            this.rtbLogicCode.Dock = System.Windows.Forms.DockStyle.Fill;
            this.rtbLogicCode.Location = new System.Drawing.Point(90, 0);
            this.rtbLogicCode.Name = "rtbLogicCode";
            this.rtbLogicCode.Size = new System.Drawing.Size(510, 600);
            this.rtbLogicCode.TabIndex = 5;
            this.rtbLogicCode.Text = "";
            this.rtbLogicCode.VScroll += new System.EventHandler(this.rtbLogicCode_VScroll);
            // 
            // LogicSimulationViewerForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(600, 600);
            this.Controls.Add(this.rtbLogicCode);
            this.Controls.Add(this.TreeLogicCode);
            this.Controls.Add(this.labelLogicCode);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.Name = "LogicSimulationViewerForm";
            this.Text = "LogicSimulationViewerForm";
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.TreeView TreeLogicCode;
        private System.Windows.Forms.Label labelLogicCode;
        private System.Windows.Forms.RichTextBox rtbLogicCode;
    }
}

I would really appreciate any guidance on solving this matter. Thanks in advance.

like image 733
l46kok Avatar asked Jun 20 '12 02:06

l46kok


1 Answers

You should take a look at Scintilla and the .NET version here: http://scintillanet.codeplex.com/.

It includes source code for solving these kinds of problems, though to be honest I'd just use the control and make it read-only to solve your programming requirements.

like image 148
Kell Avatar answered Oct 04 '22 20:10

Kell