<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2074310494330781844</id><updated>2011-07-08T06:23:07.292+03:00</updated><category term='C#'/><category term='VBScript'/><category term='LINQ'/><category term='Console'/><category term='MDI Application'/><category term='InDesign'/><category term='GDI+'/><category term='XML'/><category term='T-SQL'/><category term='JavaScript'/><category term='BinaryWriter'/><category term='Word'/><category term='.NET'/><title type='text'>Oren's Folder</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-5568313199738890367</id><published>2009-11-28T20:37:00.012+02:00</published><updated>2009-11-28T21:24:26.128+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='BinaryWriter'/><category scheme='http://www.blogger.com/atom/ns#' term='Console'/><title type='text'>Write .ICO files [C#]</title><content type='html'>&lt;p&gt;Greetings. Here's a console application I wrote, which uses the BinaryWriter to create icon files (.ico image file format). It is based on &lt;a href="http://www.daubnet.com/en/file-format-ico"&gt;these&lt;/a&gt; specifications.&lt;br&gt;[Note: .NET ImageFormat.Icon doesn't really write .ico files]&lt;/p&gt;
&lt;p&gt;You can drag and drop one or more .NET compatible image files over the app icon (equivalent to console arguments).&lt;br&gt;The program creates a Bitmap of each image, and checks if it is within the 256x256 pixels limit. Then, the Bitmap data is used by the BinaryWriter to create the converted file.&lt;/p&gt;
&lt;p&gt;CreateNew mode on the FileStream avoids file overwriting.&lt;br&gt;Since the app is targeted to run from its' icon, exceptions are shown via MessageBoxes.&lt;/p&gt; 
&lt;textarea rows="28" cols="48" Wrap=Off&gt;using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

namespace Icon_Maker
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (string _file in args)
            {
                try
                {
                    Bitmap _bitmap = (Bitmap)Image.FromFile(_file);
                    if (_bitmap.Width &gt; 256 || _bitmap.Height &gt; 256)
                        throw new ArgumentOutOfRangeException("Image must not exceed 256x256 pixels.");
                    ConvertFile(_file, _bitmap);
                    _bitmap.Dispose();
                    _bitmap = null;
                }
                catch (OutOfMemoryException ex)
                {
                    MessageBox.Show(ex.Message + "\n" + 
                        _file.Substring(_file.LastIndexOf(".")) + 
                        " is not a valid image format.", "Icon Maker",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                catch (ArgumentOutOfRangeException ex)
                {
                    MessageBox.Show(ex.Message, "Icon Maker",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                catch (IOException ex) // raised by the FileStream, if target file already exists
                {
                    MessageBox.Show(ex.Message, "Icon Maker", 
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private static void ConvertFile(string _file, Bitmap _bitmap)
        {
            FileStream _fileStream = new FileStream(_file.Remove(_file.LastIndexOf(@".")) + ".ico", 
                FileMode.CreateNew); // the mode raises IOException if the file already exists
            BinaryWriter _binaryWriter = new BinaryWriter(_fileStream);

            /* Write file header. */

            // [2 bytes] Reserved
            _binaryWriter.Write((ushort)0);

            // [2 bytes] Type: 1 for .ICO, 2 for .CUR 
            _binaryWriter.Write((ushort)1);

            // [2 bytes] Number of icons in the file.
            _binaryWriter.Write((ushort)1);

            // [1 byte] Icon width in pixels (0 is used for 256 pixels). 
            if (_bitmap.Width &lt; 256)
                _binaryWriter.Write((byte)_bitmap.Width);
            else
                _binaryWriter.Write((byte)0);

            // [1 byte] Icon height in pixels (0 is used for 256 pixels). 
            if (_bitmap.Height &lt; 256)
                _binaryWriter.Write((byte)_bitmap.Height);
            else
                _binaryWriter.Write((byte)0);

            // [1 byte] Number of colors (0 is used for non-palette RGB)
            _binaryWriter.Write((byte)0);

            // [1 byte] Reserved
            _binaryWriter.Write((byte)0);

            // [2 bytes] In .ICO: Color planes.
            // In .CUR: Horizontal coordinates of the hotspot.
            _binaryWriter.Write((ushort)1);

            // [2 bytes] In .ICO format: Bits per pixel (RGB + Alpha is 4 channels of 8 bits each.)
            // In .CUR format: Vertical coordinates of the hotspot.
            _binaryWriter.Write((ushort)32);

            // [4 bytes] Size of the bitmap data in bytes + InfoHeader which equals 40.
            _binaryWriter.Write((uint)(40 + _bitmap.Width * _bitmap.Height * 32 / 8));

            // [4 bytes] The offset where the bitmap InfoHeader starts.
            _binaryWriter.Write((uint)22);

            /* Write bitmap InfoHeader */

            // [4 bytes] Size of InfoHeader.
            _binaryWriter.Write((uint)40);

            // [4 bytes] Bitmap width in pixels.
            _binaryWriter.Write((uint)_bitmap.Width);

            // [4 bytes] Bitmap height in pixels * 2 
            // (the multiplication represents the alpha channel image).
            _binaryWriter.Write((uint)_bitmap.Height * 2);

            // Number of planes.
            _binaryWriter.Write((ushort)1);

            // Bits per pixel.
            _binaryWriter.Write((ushort)32);

            // Type of compression (0 for none).
            _binaryWriter.Write((uint)0);

            // Size of image in bytes(0 for uncompressed).
            _binaryWriter.Write((uint)0);

            // Unused
            _binaryWriter.Write((uint)0);
            _binaryWriter.Write((uint)0);
            _binaryWriter.Write((uint)0);
            _binaryWriter.Write((uint)0);

            /* Write bitmap data */

            for (int y = _bitmap.Height - 1; y &gt;= 0; y--) // Pixels are written bottom-up
            {
                for (int x = 0; x &lt; _bitmap.Width; x++) // and left-to-right.
                {
                    // Color values are written GBR.
                    _binaryWriter.Write((byte)(_bitmap.GetPixel(x, y).B));
                    _binaryWriter.Write((byte)(_bitmap.GetPixel(x, y).G));
                    _binaryWriter.Write((byte)(_bitmap.GetPixel(x, y).R));
                    _binaryWriter.Write((byte)(255)); // Transparency (alpha channel)
                }
            }

            _binaryWriter.Close();
            _fileStream.Close();
        }
    }
}
&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-5568313199738890367?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/5568313199738890367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/11/write-ico-files-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/5568313199738890367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/5568313199738890367'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/11/write-ico-files-c.html' title='Write .ICO files [C#]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-402442858925251287</id><published>2009-11-07T17:36:00.005+02:00</published><updated>2009-11-07T18:01:41.193+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GDI+'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Snake Game [C#]</title><content type='html'>&lt;p&gt;Hello again. I wrote a snake game in C#, let me tell you a little bit about it:&lt;/p&gt;
&lt;p&gt;The game features two classes of sprites: Vertebra, representing a single snake link; and Pizza, which is, of course, the pizza.&lt;br&gt;Each of these classes inherits from the PictureBox class, and uses a Timer for a nice animation when these objects appear.&lt;/p&gt;
&lt;p&gt;Game pause is achieved simply by start and stop of the game Timer.&lt;/p&gt;
&lt;p&gt;There is a top 10 high scores, which is stored in an xml file.&lt;br&gt;This file is created automatically on the first time it is requested by the game.&lt;br&gt;The handling of the high scores is done with LINQ to XML, which is awesome!&lt;/p&gt;
&lt;p&gt;Here is the code for the Main form:
&lt;textarea rows="28" cols="48" Wrap=Off&gt;using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Xml.Linq;
using System.Text;
using System.Windows.Forms;

namespace Snake
{
    public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();

            // Initialize ClientSize - measurements are in const 
            // variables on class Board.
            this.ClientSize = new Size(Board.Width, Board.Height + Board.Unit + menuStrip.Height);

            // Initialize game status label
            statusLabel = new Label();
            statusLabel.Font = new Font("Arial", 12);
            statusLabel.BackColor = Color.LightGray;
            statusLabel.AutoSize = true;
            statusLabel.Location = new Point(Board.Width * 1 / 24, Board.Height + Board.HalfUnit / 2 + menuStrip.Height);
            statusLabel.Text = "Press F2 to start a new game";
            this.Controls.Add(statusLabel);

            // Initialize pizza counter label
            pizzaLabel = new Label();
            pizzaLabel.Font = new Font("Arial", 12);
            pizzaLabel.BackColor = Color.LightGray;
            pizzaLabel.AutoSize = true;
            pizzaLabel.Location = new Point(Board.Width * 2 / 3, Board.Height + Board.HalfUnit / 2 + menuStrip.Height);
            pizzaLabel.Text = "";
            this.Controls.Add(pizzaLabel);

            // Initilaize game time label
            timeLabel = new Label();
            timeLabel.Font = new Font("Arial", 12);
            timeLabel.BackColor = Color.LightGray;
            timeLabel.AutoSize = true;
            timeLabel.Location = new Point(Board.Width * 5 / 6, Board.Height + Board.HalfUnit / 2 + menuStrip.Height);
            timeLabel.Text = "";
            this.Controls.Add(timeLabel);

            // Initialize status area label
            statusArea = new Label();
            statusArea.BackColor = Color.LightGray;
            statusArea.Size = new Size(Board.Width, Board.Unit);
            statusArea.Location = new Point(0, Board.Height + menuStrip.Height);
            this.Controls.Add(statusArea);

            // Subscribe method for game timer event, and set the interval
            myTimer.Tick += new EventHandler(myTimer_Tick);
            myTimer.Interval = 350;
        }

        private Random myRandom = new Random();

        // Class Vertebra inherits from PictureBox
        // and represents a single snake link.
        private Vertebra myVertebra; // currently moved vertebra
        private Vertebra browseVertebra; // for browsing through vertebras
        private Vertebra newVertebra; // newely created vertebra

        // Class Pizza inherits from PictureBox
        // and represents the pizza sprite.
        private Pizza myPizza;

        // The statusArea Label serves as background 
        // area for the three game status Labels.
        private Label statusArea, statusLabel, pizzaLabel, timeLabel;

        private int pizzaLocX, pizzaLocY;
        private Point nextHeadLocation, lastTailLocation, pizzaLocation;
        private int vertCount = 0, pizzaCount = -1;

        private enum Direction { Left, Right, Up, Down }
        private Direction myDirection;
 
        private enum GameState { None, Play, Grow, Pause, Over };
        private GameState myGameState = GameState.None;

        // Please note that the game Timer is of 
        // System.Windows.Forms.Timer class.
        private Timer myTimer = new Timer();
        private int tickCount = 0, timeCount = 0;

        private XDocument highScoresDoc; // XML High Scores document used in LINQ to XML
        private string highScoresStr;

        // Property for getting the current 
        // game state by Vertebra class.
        public string MyGameState
        {
            get { return myGameState.ToString(); }
        }

        // On KeyDown snake movement is determined,
        // and also the game pause / resume keys.
        private void Main_KeyDown(object sender, KeyEventArgs e)
        {
            if (myGameState == GameState.Pause)
            {
                ResumeGame();
            }
            else if (myGameState == GameState.Play)
            {
                // Please not that the snake can't turn 
                // in the opposite direction.
                if (e.KeyCode == Keys.Left &amp;&amp; myDirection != Direction.Right)
                    myDirection = Direction.Left;
                else if (e.KeyCode == Keys.Right &amp;&amp; myDirection != Direction.Left)
                    myDirection = Direction.Right;
                else if (e.KeyCode == Keys.Up &amp;&amp; myDirection != Direction.Down)
                    myDirection = Direction.Up;
                else if (e.KeyCode == Keys.Down &amp;&amp; myDirection != Direction.Up)
                    myDirection = Direction.Down;
                if (e.KeyCode == Keys.P)
                {
                    PauseGame();
                }
            }
        }

        // Starts a new game. Called by the New menu item.
        private void NewGame()
        {
            // If this isn't the first game played,
            // dispose of all previous game resources.
            if (myGameState != GameState.None)
            {
                myTimer.Stop();
                for (int i = 1; i &lt;= vertCount; i++)
                {
                    browseVertebra = (Vertebra)this.Controls.Find("vert" + i.ToString(), false)[0];
                    browseVertebra.Dispose();
                }
                vertCount = 0;
                myPizza.Dispose();
                pizzaCount = -1;
                myGameState = GameState.None;
                tickCount = 0;
                timeCount = 0;
            }

            statusLabel.Text = "Press P to pause game";
            pizzaLabel.Text = "0";
            timeLabel.Text = "0";

            myTimer.Start();
            myDirection = (Direction)myRandom.Next(0, 3); // initial snake movement direction is random
            myGameState = GameState.Play;

            // Initialize first snake Vertebra
            myVertebra = new Vertebra();
            myVertebra.Name = "vert1";
            nextHeadLocation = new System.Drawing.Point((Board.Width - Board.Unit) / 2, (Board.Height - Board.Unit) / 2 + menuStrip.Height);
            myVertebra.Location = nextHeadLocation;
            this.Controls.Add(myVertebra);
            vertCount++;

            // Initialize the Pizza
            myPizza = new Pizza();
            RelocatePizza();
            this.Controls.Add(myPizza);
        }

        // Calculates the snake head location for the next move (nextHeadLocation), 
        // and returns a boolean according to the move's validity.
        private bool NextMove()
        {
            if (myDirection == Direction.Left)
                nextHeadLocation = new Point(myVertebra.Location.X - Board.Unit, myVertebra.Location.Y);
            else if (myDirection == Direction.Right)
                nextHeadLocation = new Point(myVertebra.Location.X + Board.Unit, myVertebra.Location.Y);
            else if (myDirection == Direction.Up)
                nextHeadLocation = new Point(myVertebra.Location.X, myVertebra.Location.Y - Board.Unit);
            else if (myDirection == Direction.Down)
                nextHeadLocation = new Point(myVertebra.Location.X, myVertebra.Location.Y + Board.Unit);

            // check if location is outside the game board
            if (nextHeadLocation.X &lt; 0 ||
                    nextHeadLocation.X &gt;= Board.Width ||
                    nextHeadLocation.Y &lt; menuStrip.Height ||
                    nextHeadLocation.Y &gt;= Board.Height + menuStrip.Height)
            {
                return false;
            }
            // check if snake overlaps itself (only for over 4 vertebras)
            else if (vertCount &gt; 4)
            {
                for (int i = 1; i &lt; vertCount; i++)
                {
                    browseVertebra = (Vertebra)this.Controls.Find("vert" + i.ToString(), false)[0];
                    if (browseVertebra.Location == nextHeadLocation)
                    {
                        return false;
                    }
                }
                return true;
            }
            else
            {
                return true;
            }
        }

        // Executes the move calculated by NextMove method,
        // by placing the last Vertebra at nextHeadLocation.
        private void MakeMove()
        {
            // The vertebras are named as "vert" + position number from 1 to vertCount.

            myVertebra = (Vertebra)this.Controls.Find("vert" + vertCount.ToString(), false)[0]; // get the last Vertebra
            lastTailLocation = myVertebra.Location; // save its location, may be needed by a new Vertebra
            myVertebra.Name = "vert0"; // temporary rename as position 0
            myVertebra.Location = nextHeadLocation; // move to nextHeadLocation

            // After the move is performed, position numbers in Vertebra names
            // are pushed one step up, to restore the 1 to vertCount numbering.
            for (int i = vertCount; i &gt; 0; i--)
            {
                browseVertebra = (Vertebra)this.Controls.Find("vert" + (i - 1).ToString(), false)[0];
                browseVertebra.Name = "vert" + i.ToString();
            }

            // If the new location overlaps the Pizza,
            // relocate Pizza and place a new Vertebra at lastTailLocation.
            if (myVertebra.Location == pizzaLocation)
            {
                RelocatePizza();
                newVertebra = new Vertebra();
                vertCount++;
                newVertebra.Name = "vert" + vertCount.ToString();
                newVertebra.Location = lastTailLocation;
                this.Controls.Add(newVertebra);
            }
        }

        // Relocates the Pizza at a random available location.
        // Called by the MakeMove method.
        private void RelocatePizza()
        {
            pizzaCount++;
            pizzaLabel.Text = pizzaCount.ToString() + " pizzas";
            pizzaLocX = myRandom.Next(1, Board.UnitsOnX) * Board.Unit;
            pizzaLocY = myRandom.Next(1, Board.UnitsOnY) * Board.Unit + menuStrip.Height;
            pizzaLocation = new Point(pizzaLocX, pizzaLocY);

            // Check if the new random location overlaps with any Vertebra.
            // If so - this method recalls itself for a new random location.
            for (int i = 1; i &lt;= vertCount; i++)
            {
                browseVertebra = (Vertebra)this.Controls.Find("vert" + i.ToString(), false)[0];
                if (browseVertebra.Location == pizzaLocation)
                    RelocatePizza();
            }

            // If no overlaps were found, the Pizza is relocated.
            myPizza.Location = pizzaLocation;
        }

        // Subscribed by the game timer Tick event.
        private void myTimer_Tick(object source, EventArgs e)
        {
            // Update game time counter and label.
            tickCount++;
            timeCount = (int)(tickCount * myTimer.Interval / 1000);
            timeLabel.Text = timeCount.ToString() + " sec.";

            if (myGameState == GameState.Play)
            {
                if (NextMove() == true) // if next move is valid - proceed
                {
                    MakeMove();
                }
                else // game over
                {
                    myTimer.Stop();
                    myGameState = GameState.Over;
                    statusLabel.Text = "Game Over, press F2 to restart";
                    CheckScores();                  
                }
            }
        }

        // Checks to enter the game in the high scores.
        // Called by timer Tick event handler when a game is over.
        private void CheckScores()
        {
            // If it doesn't exist - create the high scores xml file.
            if (!System.IO.File.Exists("SnakeHighScores.xml"))
            {
                CreateHighScoresDoc();
            }

            highScoresDoc = XDocument.Load("SnakeHighScores.xml");

            // Get the lowest score - the smallest amount of pizzas 
            // in the longest game time.
            XElement lowestScore = highScoresDoc.Root.Element("Slot");
            foreach (XElement browseSlot in highScoresDoc.Root.Elements())
            {
                int browsePizzas = int.Parse(browseSlot.Element("Pizzas").Value);
                int browseTime = int.Parse(browseSlot.Element("Time").Value);
                int lowestPizzas = int.Parse(lowestScore.Element("Pizzas").Value);
                int lowestTime = int.Parse(lowestScore.Element("Time").Value);

                if ((browsePizzas &lt; lowestPizzas) ||
                    (browsePizzas == lowestPizzas) &amp;&amp;
                    (browseTime &gt; lowestTime))
                {
                    lowestScore = browseSlot;
                }
            }

            // If the game score is higher than the lowest score,
            // prompt the player for his name, replace that 
            // high scores slot, and display the new scores.
            if ((int.Parse(lowestScore.Element("Pizzas").Value) &lt; pizzaCount) ||
                (int.Parse(lowestScore.Element("Pizzas").Value) == pizzaCount) &amp;&amp;
                (int.Parse(lowestScore.Element("Time").Value) &gt; timeCount))
            {
                PlayerDialog MyPlayerDialog = new PlayerDialog();
                if (MyPlayerDialog.ShowDialog() == DialogResult.OK)
                {
                    lowestScore.Element("Player").SetValue(MyPlayerDialog.PlayerName);
                    lowestScore.Element("Pizzas").SetValue(pizzaCount.ToString());
                    lowestScore.Element("Time").SetValue(timeCount);
                    highScoresDoc.Save("SnakeHighScores.xml");
                    DisplayHighScores();
                }
            }
        }

        // Creates a high scores xml file.
        private void CreateHighScoresDoc()
        {
            highScoresDoc = 
                new XDocument(
                    new XElement("HighScores")
                    );
            for (int i = 0; i &lt; 10; i++)
            {
                highScoresDoc.Root.Add(new XElement("Slot",
                    new XElement("Player", "-"),
                    new XElement("Pizzas", "0"),
                    new XElement("Time", "0")
                    )
                    );
            }
            highScoresDoc.Save("SnakeHighScores.xml");
        }

        // Displays the high scores in a MessageBox.
        private void DisplayHighScores()
        {
            highScoresDoc = XDocument.Load("SnakeHighScores.xml");
            var myHighScores = from mySlot in highScoresDoc.Root.Elements()
                               orderby int.Parse(mySlot.Element("Pizzas").Value) descending,
                               int.Parse(mySlot.Element("Time").Value)
                               select new
                               {
                                   player = mySlot.Element("Player").Value,
                                   pizzas = mySlot.Element("Pizzas").Value,
                                   time = mySlot.Element("Time").Value
                               };

            highScoresStr = "Player\tPizzas\tTime\n\n";
            foreach (var myHighScore in myHighScores)
            {
                highScoresStr += myHighScore.player + "\t" +
                    myHighScore.pizzas + "\t" + myHighScore.time + "\n";
            }
            MessageBox.Show(highScoresStr, "Snake");
        }

        // Method for the New menu item.
        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // If a game is in progress, prompt the user about restarting a new game.
            if (myGameState == GameState.Play)
            {
                DialogResult result;
                result = MessageBox.Show("There is a game in progress.\nDo you want to restart?", "Snake",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
                if (result == DialogResult.Yes)
                {
                    NewGame();
                }
            }
            else
            {
                NewGame();
            }       
        }

        // Method for the High Scores menu item.
        private void highScoresToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // If it doesn't exist - create the high scores xml file.
            if (!System.IO.File.Exists("SnakeHighScores.xml"))
            {
                CreateHighScoresDoc();
            }
            DisplayHighScores();
        }

        // Pauses a game - stops the game timer.
        private void PauseGame()
        {
            myTimer.Stop();
            myGameState = GameState.Pause;
            statusLabel.Text = "Paused, press any key to resume";
        }

        // Resumes a paused game - starts the game timer.
        private void ResumeGame()
        {
            myTimer.Start();
            myGameState = GameState.Play;
            statusLabel.Text = "Press P to pause game";
        }

        // On deactivation of the Main window, the game is paused.
        private void Main_Deactivate(object sender, EventArgs e)
        {
            if (myGameState == GameState.Play)
            {
                PauseGame();
            }
        }

        // On activation of the game menu, the game is paused.
        private void menuStrip_MenuActivate(object sender, EventArgs e)
        {
            if (myGameState == GameState.Play)
            {
                PauseGame();
            }
        }

        // Method for the Exit menu item.
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
&lt;/textarea&gt;
&lt;p&gt;&lt;/p&gt;
Here is the code of the Vertebra Class:
&lt;textarea rows="28" cols="48" Wrap=Off&gt;using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Timers;

namespace Snake
{
    public class Vertebra : System.Windows.Forms.PictureBox
    {
        private Bitmap myImage;

        // Please note that the Vertebra Timer is of 
        // System.Timers.Timer class.
        private Timer myTimer = new Timer();

        private enum VertebraState { None, Born, Move, Dead };
        private VertebraState myVertebraState = VertebraState.None;

        int i = 0; // for numbering animation steps

        public Vertebra() : base()
        {
            // Subscribe method for Vertebra timer event.
            myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);

            this.Size = new Size(Board.Unit, Board.Unit);
            this.BackColor = Color.Transparent;
            myImage = new Bitmap(Board.Unit, Board.Unit);
            myTimer.Interval = 25;
            myTimer.Start();
            myVertebraState = VertebraState.Born;
        }

        // Subscribed by the Vertebra timer Elapsed event.
        private void myTimer_Elapsed(object source, EventArgs e)
        {
            if (myVertebraState == VertebraState.Born) // when a Vertebra is created
            {
                DrawVertebra(Pens.BlueViolet, VertebraState.Move);
            }
            else if (((Main)this.Parent).MyGameState == "Over" &amp;&amp;
                myVertebraState == VertebraState.Move) // when game is over
            {
                DrawVertebra(Pens.Gray, VertebraState.Dead);
            }
        }

        // Draws the growing squares animation with the requested Pen.
        // On finish, sets the requested myVertebraState.
        private void DrawVertebra(Pen myPen, VertebraState myNextState)
        {
            Graphics g = Graphics.FromImage(myImage);
            g.DrawRectangle(myPen, (myImage.Width - i) / 2, (myImage.Height - i) / 2, i, i);
            this.Image = myImage;
            i += 4;
            if (i &gt;= Board.Unit)
            {
                myVertebraState = myNextState;
                i = 0;
            }
        }
    }
}
&lt;/textarea&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;And here are a couple of screenshots:&lt;/p&gt;
&lt;a href="http://1.bp.blogspot.com/_CjLw9oSooQ0/SvWVHLg9gXI/AAAAAAAAABQ/tvld9vI2ZLA/s1600-h/snake-screenshot1.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 345px; height: 400px;" src="http://1.bp.blogspot.com/_CjLw9oSooQ0/SvWVHLg9gXI/AAAAAAAAABQ/tvld9vI2ZLA/s400/snake-screenshot1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5401387278683439474" /&gt;&lt;/a&gt;
&lt;a href="http://2.bp.blogspot.com/_CjLw9oSooQ0/SvWVHMT2dbI/AAAAAAAAABY/l_sc8DSJNCw/s1600-h/snake-screenshot2.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 345px; height: 400px;" src="http://2.bp.blogspot.com/_CjLw9oSooQ0/SvWVHMT2dbI/AAAAAAAAABY/l_sc8DSJNCw/s400/snake-screenshot2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5401387278896887218" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-402442858925251287?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/402442858925251287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/11/snake-game-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/402442858925251287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/402442858925251287'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/11/snake-game-c.html' title='Snake Game [C#]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_CjLw9oSooQ0/SvWVHLg9gXI/AAAAAAAAABQ/tvld9vI2ZLA/s72-c/snake-screenshot1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-3386152358556293408</id><published>2009-10-26T16:08:00.008+02:00</published><updated>2009-10-26T17:11:45.342+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GDI+'/><category scheme='http://www.blogger.com/atom/ns#' term='MDI Application'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Paint Application [C#]</title><content type='html'>&lt;p&gt;Greetings. I wrote a Paint Application in C#, here is a summary of it:&lt;/p&gt;
&lt;p&gt;It is a Multiple-Document Interface application - The Image forms are MdiChildren of the Main application form.&lt;br&gt;According to this, the main menu is merged with a non-visible MenuStrip on the Image form.&lt;br&gt;The various tool windows are owned by the Main application form.&lt;/p&gt;
&lt;p&gt;The featured tools are: Select, Pencil (1px free-draw), Brush, Eraser, Rectangle, Circle, Fill and Pipette (color picker).&lt;/p&gt;
&lt;p&gt;The different parameters for each tool are displayed in the Tool Options window.&lt;br&gt;Each tool's options are arranged on a dedicated panel on this form. When a tool is chosen, its' options panel toggles to the only visible panel.&lt;/p&gt;
&lt;p&gt;The edited image is displayed inside a PictureBox control.&lt;br&gt;All drawing actions are done in the course of the MouseDown, MouseMove and MouseUp events of that PictureBox.&lt;br&gt;A boolean named isDragging is turned true on MouseDown event, and false on MouseUp event, thus enabling continuous drawing actions.&lt;/p&gt;
&lt;p&gt;Selection definition, dragging and dropping is done in a similar way, based on four selection states listed in an enum.&lt;/p&gt;
&lt;p&gt;The algorithm for the flood fill tool is taken from &lt;a href="http://www.academictutorials.com/graphics/graphics-flood-fill.asp"&gt;this tutorial.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Two image filters are available from the Image menu - Brightness and Invert, and can also be applied to selections.&lt;br&gt;Brightness also features a dialog for setting the filter level, with a small preview of its' effect.&lt;/p&gt;
&lt;p&gt;The data for the multiple undo and redo features is stored in Stacks.&lt;/p&gt;
&lt;p&gt;Image files can be loaded and saved in the various ImageFormats provided by .NET.&lt;/p&gt;
&lt;p&gt;Here are a couple of screenshots:&lt;/p&gt;

&lt;a href="http://3.bp.blogspot.com/_CjLw9oSooQ0/SuWu-madmII/AAAAAAAAABA/56thj2dyFx8/s1600-h/paint_app-screenshot_1.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 241px;" src="http://3.bp.blogspot.com/_CjLw9oSooQ0/SuWu-madmII/AAAAAAAAABA/56thj2dyFx8/s400/paint_app-screenshot_1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5396912118960068738" /&gt;&lt;/a&gt;

&lt;p&gt;&lt;/p&gt;

&lt;a href="http://1.bp.blogspot.com/_CjLw9oSooQ0/SuWvMrMHkkI/AAAAAAAAABI/3LgLYUpR0RE/s1600-h/paint_app-screenshot_2.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 241px;" src="http://1.bp.blogspot.com/_CjLw9oSooQ0/SuWvMrMHkkI/AAAAAAAAABI/3LgLYUpR0RE/s400/paint_app-screenshot_2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5396912360760250946" /&gt;&lt;/a&gt;

&lt;p&gt;And here is the code for the Image form:&lt;/p&gt;
&lt;textarea rows="28" cols="48" Wrap=Off&gt;using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.Text;
using System.Windows.Forms;

namespace PaintApp
{
    public partial class ImageForm : Form
    {
        public ImageForm()
        {
            InitializeComponent();

            // Subscribe to event for PrintDocument page printing.
            myPrintDocument.PrintPage += new PrintPageEventHandler(myPrintDocument_PrintPage);
        }

        private string fileName = "";
        private System.Drawing.Imaging.ImageFormat fileImageFormat;

        private Stack&lt;Bitmap&gt; undoStack = new Stack&lt;Bitmap&gt;();
        private Stack&lt;Bitmap&gt; redoStack = new Stack&lt;Bitmap&gt;();

        // Property for getting the image fileName by the main application form. 
        public string FileName
        {
            get { return fileName; } //
        }

        // Property for getting myImage Bitmap by the BrightnessDialog.
        public Bitmap MyImage
        {
            get { return myImage; }
        }

        // Property for getting the selection Bitmap by the BrightnessDialog.
        public Bitmap SelectBi
        {
            get { return selectBi; }
        }

        // Property for getting the selection state by the BrightnessDialog.
        // If a selection exists, the brightness preview uses it.
        public string MySelectionState
        {
            get { return mySelectionState.ToString(); }
        }

        private Bitmap myImage; // the image Bitmap
        private Bitmap tempBi; // for temporary changes in the image
        private Bitmap selectBi; // the selection bitmap
        
        private bool isDragging = false; // enables continuous drawing actions
        private bool selectPaste = false; // determines whether the selection origin is a clipboard paste
        private bool selectChanged = false; // determines if any change was applied on the selection
        
        private enum SelectionState { None, Define, Selected, Drag }; // the list of states for selections
        private SelectionState mySelectionState = SelectionState.None; // the current selection state
        
        private int lastX, lastY, // last mouse position for free drawing tools
            selectionStartX, selectionStartY, // the selection origin
            eFixX, eFixY, // calculated by the FixEValues method, to avoid selecting outside image boundaries
            selectionLocationX, selectionLocationY, // current selection location (upper-left corner)
            selectionDragOffsetX, selectionDragOffsetY, // the distances between SelectionLocation and where the mouse pressed inside the selection
            selectionWidth, selectionHeight, // selection measurements
            shapeStartX, shapeStartY; // shape origin
        private Rectangle mySelection; // Rectangle of the selection location and measurements
        
        private Pen selectPen = new Pen(Brushes.Blue, 1); // Pen for selection frame
        private Pen pencilPen, brushPen, eraserPen, rectanglePen, circlePen; // draw and shape tools Pens
        private SolidBrush selectionCutBrush, rectangleFillBrush, circleFillBrush; // Brushes for filling shapes and the original location of a selection

        // The classes needed for printing.
        private PrintDocument myPrintDocument = new PrintDocument();
        private PageSettings myPageSettings = new PageSettings();
        private PageSetupDialog myPageSetupDialog = new PageSetupDialog();
        private PrintPreviewDialog myPrintPreviewDialog = new PrintPreviewDialog();
        private PrintDialog myPrintDialog = new PrintDialog();
        private Rectangle myPrintArea; // the image area on the printed page


        /* The three methods below are for the MouseDown, MouseMove and MouseUp events 
           of pictureBox1. All drawing is done in the course of these three events. */

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (ToolsWindow.MyTool == "select") // the selection tool is different from the rest, since it has four states
            {
                if (mySelectionState == SelectionState.None) // if there is no selection, start defining a new one
                {
                    selectionStartX = e.X;
                    selectionStartY = e.Y;
                    mySelectionState = SelectionState.Define;
                }
                else if (mySelectionState == SelectionState.Selected) // if a selection exists
                {
                    if ((e.X &gt; selectionLocationX) &amp;&amp; 
                        (e.X &lt; selectionLocationX + selectionWidth) &amp;&amp; 
                        (e.Y &gt; selectionLocationY) &amp;&amp; 
                        (e.Y &lt; selectionLocationY + selectionHeight)) // if mouse pressed inside the selection, start dragging it
                    {
                        selectionDragOffsetX = e.X - selectionLocationX;
                        selectionDragOffsetY = e.Y - selectionLocationY;
                        mySelectionState = SelectionState.Drag;
                    }
                    else // if mouse pressed outside the selection, drop it down
                    {
                        DropSelection();

                        // Immediately after dropping a selection, a new one can be defined by dragging the mouse.
                        selectionStartX = e.X;
                        selectionStartY = e.Y;
                        mySelectionState = SelectionState.Define;
                    }
                }
            }
            else // for all tools other than select
            {
                // If a selection exists, drop it down.
                if (mySelectionState == SelectionState.Selected)
                {
                    DropSelection();
                }

                // Before drawing, push the current image to the undoStack.
                PushEdit();

                if ((ToolsWindow.MyTool == "pencil") || 
                    (ToolsWindow.MyTool == "brush") || 
                    (ToolsWindow.MyTool == "eraser")) // these tools draw the first 'dot' on MouseDown
                {
                    Graphics g = Graphics.FromImage(myImage);
                    if (ToolsWindow.MyTool == "pencil")
                    {
                        pencilPen = new Pen(new SolidBrush(ColorsWindow.MyForeColor), 1);
                        myImage.SetPixel(e.X, e.Y, pencilPen.Color);
                    }
                    else if (ToolsWindow.MyTool == "brush")
                    {
                        brushPen = new Pen(new SolidBrush(ColorsWindow.MyForeColor), ToolOptionsWindow.MyBrushDiameter);
                        g.FillEllipse(brushPen.Brush, e.X - brushPen.Width / 2, e.Y - brushPen.Width / 2, brushPen.Width, brushPen.Width);
                    }
                    else if (ToolsWindow.MyTool == "eraser")
                    {
                        eraserPen = new Pen(new SolidBrush(ColorsWindow.MyForeColor), ToolOptionsWindow.MyEraserDiameter);
                        g.FillRectangle(eraserPen.Brush, e.X - eraserPen.Width / 2, e.Y - eraserPen.Width / 2, eraserPen.Width, eraserPen.Width);
                    }
                    // Storing the last mouse position is required on the free drawing tools,
                    // to draw a line between that position and the new one.
                    lastX = e.X;
                    lastY = e.Y;
                }
                else if ((ToolsWindow.MyTool == "rectangle") || 
                    (ToolsWindow.MyTool == "circle")) // the shape origin is defined on MouseDown
                {
                    shapeStartX = e.X;
                    shapeStartY = e.Y;
                }
                else if ((ToolsWindow.MyTool == "fill") || 
                    (ToolsWindow.MyTool == "pipette")) // these tools complete their tasks on MouseDown
                {
                    if (ToolsWindow.MyTool == "fill")
                    {
                        Color myReplacedColor = myImage.GetPixel(e.X, e.Y);
                        if (myReplacedColor != ColorsWindow.MyBackColor)
                        {
                            if (ToolOptionsWindow.MyFillContiguous == true) // flood fill
                            {
                                FillContiguously(e.X, e.Y, myImage.GetPixel(e.X, e.Y));
                            }
                            else // fill which replaces all pixels of the pressed pixel color
                            {
                                for (int x = 0; x &lt; myImage.Width; x++)
                                {
                                    for (int y = 0; y &lt; myImage.Height; y++)
                                    {
                                        if (myImage.GetPixel(x, y) == myReplacedColor)
                                        {
                                            myImage.SetPixel(x, y, ColorsWindow.MyBackColor);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else if (ToolsWindow.MyTool == "pipette")
                    {
                        // Calls a method on the Main form which calls a method on its' owned ColorsWindow form.
                        ((Main)(this.MdiParent)).SetPipetteColor(myImage.GetPixel(e.X, e.Y));
                    }
                }
                pictureBox1.Image = myImage;
                isDragging = true;
            }
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            // Update the StatusStrip on the Main form.
            ((Main)(this.MdiParent)).StatusStripUpdate(e.Location);

            if (ToolsWindow.MyTool == "select")
            {
                // When a selection is defined or dragged,
                // myImage is cloned to tempBi, for the temporary changes.
                if (mySelectionState == SelectionState.Define)
                {
                    tempBi = (Bitmap)myImage.Clone();
                    Graphics tempGr = Graphics.FromImage(tempBi);
                    FixEValues(e.X, e.Y);
                    tempGr.DrawRectangle(selectPen, (int)Math.Min(selectionStartX, eFixX), (int)Math.Min(selectionStartY, eFixY), Math.Abs(eFixX - selectionStartX), Math.Abs(eFixY - selectionStartY));
                    pictureBox1.Image = tempBi;
                }
                else if (mySelectionState == SelectionState.Drag)
                {
                    selectChanged = true;
                    tempBi = (Bitmap)myImage.Clone();
                    Graphics tempGr = Graphics.FromImage(tempBi);
                    if (selectPaste == false) // if true, the original location will not be erased
                    {
                        selectionCutBrush = new SolidBrush(ColorsWindow.MyBackColor);
                        tempGr.FillRectangle(selectionCutBrush, mySelection);
                    }
                    tempGr.DrawImage(selectBi, e.X - selectionDragOffsetX, e.Y - selectionDragOffsetY);
                    tempGr.DrawRectangle(selectPen, e.X - selectionDragOffsetX, e.Y - selectionDragOffsetY, selectionWidth - 1, selectionHeight - 1);
                    pictureBox1.Image = tempBi;
                }
            }
            else // for all tools other than select
            {
                if (isDragging)
                {
                    if ((ToolsWindow.MyTool == "pencil") || 
                        (ToolsWindow.MyTool == "brush") || 
                        (ToolsWindow.MyTool == "eraser")) // these tools draw a line between the current and last mouse positions on MouseMove
                    {
                        Graphics g = Graphics.FromImage(myImage);
                        if (ToolsWindow.MyTool == "pencil")
                            g.DrawLine(pencilPen, lastX, lastY, e.X, e.Y);
                        else if (ToolsWindow.MyTool == "brush")
                        {
                            g.DrawLine(brushPen, lastX, lastY, e.X, e.Y);
                            g.FillEllipse(brushPen.Brush, e.X - brushPen.Width / 2, e.Y - brushPen.Width / 2, brushPen.Width, brushPen.Width);
                        }
                        else if (ToolsWindow.MyTool == "eraser")
                        {
                            g.DrawLine(eraserPen, lastX, lastY, e.X, e.Y);
                            g.FillRectangle(eraserPen.Brush, e.X - eraserPen.Width / 2, e.Y - eraserPen.Width / 2, eraserPen.Width, eraserPen.Width);
                        }
                        // Storing the last mouse position is required on the free drawing tools,
                        // to draw a line between that position and the new one.
                        lastX = e.X;
                        lastY = e.Y;
                        pictureBox1.Image = myImage;
                    }
                    else if ((ToolsWindow.MyTool == "rectangle") || 
                        (ToolsWindow.MyTool == "circle")) // shapes are previewed dynamically on tempBi on MouseMove
                    {
                        tempBi = (Bitmap)myImage.Clone();
                        Graphics tempGr = Graphics.FromImage(tempBi);
                        if (ToolsWindow.MyTool == "rectangle")
                        {
                            if (ToolOptionsWindow.MyRectangleFill == true) // fill the shape if checked to do so
                            {
                                rectangleFillBrush = new SolidBrush(ColorsWindow.MyBackColor);
                                tempGr.FillRectangle(rectangleFillBrush, (int)Math.Min(shapeStartX, e.X), (int)Math.Min(shapeStartY, e.Y), Math.Abs(e.X - shapeStartX), Math.Abs(e.Y - shapeStartY));
                            }
                            rectanglePen = new Pen(new SolidBrush(ColorsWindow.MyForeColor), ToolOptionsWindow.MyRectangleContour);
                            tempGr.DrawRectangle(rectanglePen, (int)Math.Min(shapeStartX, e.X), (int)Math.Min(shapeStartY, e.Y), Math.Abs(e.X - shapeStartX), Math.Abs(e.Y - shapeStartY));
                        }
                        else if (ToolsWindow.MyTool == "circle")
                        {
                            if (ToolOptionsWindow.MyCircleFill == true) // fill the shape if checked to do so
                            {
                                circleFillBrush = new SolidBrush(ColorsWindow.MyBackColor);
                                tempGr.FillEllipse(circleFillBrush, (int)Math.Min(shapeStartX, e.X), (int)Math.Min(shapeStartY, e.Y), Math.Abs(e.X - shapeStartX), Math.Abs(e.Y - shapeStartY));
                            }
                            circlePen = new Pen(new SolidBrush(ColorsWindow.MyForeColor), ToolOptionsWindow.MyCircleContour);
                            tempGr.DrawEllipse(circlePen, (int)Math.Min(shapeStartX, e.X), (int)Math.Min(shapeStartY, e.Y), Math.Abs(e.X - shapeStartX), Math.Abs(e.Y - shapeStartY));
                        }
                        pictureBox1.Image = tempBi;
                    }
                    else if (ToolsWindow.MyTool == "pipette") // the pipette tool will repeat its' task on MouseMove
                    {
                        ((Main)(this.MdiParent)).SetPipetteColor(myImage.GetPixel(e.X, e.Y));
                    }
                }
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (ToolsWindow.MyTool == "select")
            {
                if (mySelectionState == SelectionState.Define) // definition of a selection ends on MouseUp
                {
                    FixEValues(e.X, e.Y);
                    selectionWidth = Math.Abs(eFixX - selectionStartX + 1);
                    selectionHeight = Math.Abs(eFixY - selectionStartY + 1);
                    if (selectionWidth &gt; 0 &amp;&amp; selectionHeight &gt; 0)
                    {
                        if (eFixX &lt; selectionStartX)
                        {
                            selectionStartX = eFixX;
                        }
                        if (eFixY &lt; selectionStartY)
                        {
                            selectionStartY = eFixY;
                        }
                        mySelection = new Rectangle(selectionStartX, selectionStartY, selectionWidth, selectionHeight);
                        selectionLocationX = selectionStartX;
                        selectionLocationY = selectionStartY;

                        selectBi = new Bitmap(selectionWidth, selectionHeight);
                        Graphics selectGr = Graphics.FromImage(selectBi);
                        selectGr.DrawImage(myImage, 0, 0, mySelection, GraphicsUnit.Pixel);

                        mySelectionState = SelectionState.Selected;
                        selectChanged = false;
                        selectPaste = false;
                    }
                    else // if one of the measurements equals 0, no selection is done
                    {
                        mySelectionState = SelectionState.None;
                    }
                }
                else if (mySelectionState == SelectionState.Drag) // location of a dragged selection is updated on MouseUp
                {
                    selectionLocationX = e.X - selectionDragOffsetX;
                    selectionLocationY = e.Y - selectionDragOffsetY;
                    mySelectionState = SelectionState.Selected;
                }
            }
            else // for all tools other than select
            {
                if ((ToolsWindow.MyTool == "rectangle") || 
                    (ToolsWindow.MyTool == "circle")) // shapes are finalized and drawn to myImage on MouseUp
                {
                    Graphics g = Graphics.FromImage(myImage);
                    if (ToolsWindow.MyTool == "rectangle")
                    {
                        if (ToolOptionsWindow.MyRectangleFill == true)
                        {
                            rectangleFillBrush = new SolidBrush(ColorsWindow.MyBackColor);
                            g.FillRectangle(rectangleFillBrush, (int)Math.Min(shapeStartX, e.X), (int)Math.Min(shapeStartY, e.Y), Math.Abs(e.X - shapeStartX), Math.Abs(e.Y - shapeStartY));
                        }
                        rectanglePen = new Pen(new SolidBrush(ColorsWindow.MyForeColor), ToolOptionsWindow.MyRectangleContour);
                        g.DrawRectangle(rectanglePen, (int)Math.Min(shapeStartX, e.X), (int)Math.Min(shapeStartY, e.Y), Math.Abs(e.X - shapeStartX), Math.Abs(e.Y - shapeStartY));
                    }
                    else if (ToolsWindow.MyTool == "circle")
                    {
                        if (ToolOptionsWindow.MyCircleFill == true)
                        {
                            circleFillBrush = new SolidBrush(ColorsWindow.MyBackColor);
                            g.FillEllipse(circleFillBrush, (int)Math.Min(shapeStartX, e.X), (int)Math.Min(shapeStartY, e.Y), Math.Abs(e.X - shapeStartX), Math.Abs(e.Y - shapeStartY));
                        }
                        circlePen = new Pen(new SolidBrush(ColorsWindow.MyForeColor), ToolOptionsWindow.MyCircleContour);
                        g.DrawEllipse(circlePen, (int)Math.Min(shapeStartX, e.X), (int)Math.Min(shapeStartY, e.Y), Math.Abs(e.X - shapeStartX), Math.Abs(e.Y - shapeStartY));
                    }
                    pictureBox1.Image = myImage;
                }
                isDragging = false;
            }

            // On MouseUp, the Edit menu items are updated accordingly.
            MonitorEditMenu();
        }

        // When mouse leaves the pictureBox1, the StatusStrip on the Main form is cleared.
        private void pictureBox1_MouseLeave(object sender, EventArgs e)
        {
            ((Main)(this.MdiParent)).StatusStripReset();
        }

        /* The three methods below are called in the course of the 
           MouseDown, MouseMove and MouseUp events */

        // On selection definition, mouse e values are inserted to eFixX, eFixY
        // accordingly, while ensuring values are inside image bounds.
        private void FixEValues(int eX, int eY)
        {
            if (eX &lt; 0)
            {
                eFixX = 0;
            }
            else if (eX &gt; tempBi.Width - 1)
            {
                eFixX = tempBi.Width - 1;
            }
            else
            {
                eFixX = eX;
            }

            if (eY &lt; 0)
            {
                eFixY = 0;
            }
            else if (eY &gt; tempBi.Height - 1)
            {
                eFixY = tempBi.Height - 1;
            }
            else
            {
                eFixY = eY;
            }
        }

        // Called when a selection is dropped down.
        private void DropSelection()
        {
            if (selectChanged == true)
            {
                // Before dropping, push the current image to the undoStack.
                PushEdit();

                Graphics g = Graphics.FromImage(myImage);
                if (selectPaste == false) // if true, the original location will not be erased
                {
                    selectionCutBrush = new SolidBrush(ColorsWindow.MyBackColor);
                    g.FillRectangle(selectionCutBrush, mySelection);
                }
                g.DrawImage(selectBi, selectionLocationX, selectionLocationY);
            }
            mySelectionState = SelectionState.None; // clear selection
            pictureBox1.Image = myImage;
        }

        // Called recursively by the flood fill tool. This algorithm is from:
        // http://www.academictutorials.com/graphics/graphics-flood-fill.asp
        private void FillContiguously(int myX, int myY, Color myReplacedColor)
        {
            int myY1;

            myY1 = myY;
            while ((myY1 &lt; myImage.Height) &amp;&amp; (myImage.GetPixel(myX, myY1) == myReplacedColor))
            {
                myImage.SetPixel(myX, myY1, ColorsWindow.MyBackColor);
                myY1++;
            }

            myY1 = myY - 1;
            while ((myY1 &gt;= 0) &amp;&amp; (myImage.GetPixel(myX, myY1) == myReplacedColor))
            {
                myImage.SetPixel(myX, myY1, ColorsWindow.MyBackColor);
                myY1--;
            }

            myY1 = myY;
            while ((myY1 &lt; myImage.Height) &amp;&amp; (myImage.GetPixel(myX, myY1) == ColorsWindow.MyBackColor))
            {
                if ((myX &gt; 0) &amp;&amp; (myImage.GetPixel(myX-1, myY1) == myReplacedColor))
                {
                    FillContiguously(myX - 1, myY1, myReplacedColor);
                }
                myY1++;
            }

            myY1 = myY - 1;
            while ((myY1 &gt;= 0) &amp;&amp; (myImage.GetPixel(myX, myY1) == ColorsWindow.MyBackColor))
            {
                if ((myX &gt; 0) &amp;&amp; (myImage.GetPixel(myX-1, myY1) == myReplacedColor))
                {
                    FillContiguously(myX - 1, myY1, myReplacedColor);
                }
                myY1--;
            }

            myY1 = myY;
            while ((myY1 &lt; myImage.Height) &amp;&amp; (myImage.GetPixel(myX, myY1) == ColorsWindow.MyBackColor))
            {
                if ((myX &lt; myImage.Width - 1) &amp;&amp; (myImage.GetPixel(myX + 1, myY1) == myReplacedColor))
                {
                    FillContiguously(myX + 1, myY1, myReplacedColor);
                }
                myY1++;
            }

            myY1 = myY - 1;
            while ((myY1 &gt;= 0) &amp;&amp; (myImage.GetPixel(myX, myY1) == ColorsWindow.MyBackColor))
            {
                if ((myX &lt; myImage.Width - 1) &amp;&amp; (myImage.GetPixel(myX + 1, myY1) == myReplacedColor))
                {
                    FillContiguously(myX + 1, myY1, myReplacedColor);
                }
                myY1--;
            }
        }

        // Updates the Edit menu items according to undo and redo Stacks counts,
        // Selection state, and clipboard contents.
        public void MonitorEditMenu()
        {
            if (undoStack.Count &lt; 1)
            {
                undoToolStripMenuItem.Enabled = false;
            }
            else
            {
                undoToolStripMenuItem.Enabled = true;
            }
            if (redoStack.Count &lt; 1)
            {
                redoToolStripMenuItem.Enabled = false;
            }
            else
            {
                redoToolStripMenuItem.Enabled = true;
            }
            if (mySelectionState == SelectionState.Selected)
            {
                cutToolStripMenuItem.Enabled = true;
                copyToolStripMenuItem.Enabled = true;
                deleteToolStripMenuItem.Enabled = true;
            }
            else
            {
                cutToolStripMenuItem.Enabled = false;
                copyToolStripMenuItem.Enabled = false;
                deleteToolStripMenuItem.Enabled = false;
            }
            if (Clipboard.ContainsImage() == true)
            {
                pasteToolStripMenuItem.Enabled = true;
            }
            else
            {
                pasteToolStripMenuItem.Enabled = false;
            }
        }


        /* The ten methods below process the tasks of the File menu items,
           in the order of their appearance. */

        // Called by the Main form, after a new instance of ImageForm class is declared
        public void FileNew(int myImageWidth, int myImageHeight, Color myImageBackground)
        {
            myImage = new Bitmap(myImageWidth, myImageHeight);
            Graphics g = Graphics.FromImage(myImage);
            g.Clear(myImageBackground);
            pictureBox1.ClientSize = new Size(myImage.Width, myImage.Height);
            pictureBox1.Image = myImage;
            saveToolStripMenuItem.Enabled = false;
            MonitorEditMenu();
        }

        // Called by the Main form, using the FileName chosen by an OpenFileDialog
        public void FileOpen(string myFileName)
        {
            fileName = myFileName;

            // The ImageFormat is determined according to the FileName extension.
            string myFileExt = myFileName.Substring(myFileName.LastIndexOf(".") + 1).ToLower();
            if ((myFileExt == "bmp") || (myFileExt == "dib"))
            {
                fileImageFormat = System.Drawing.Imaging.ImageFormat.Bmp;
            }
            else if ((myFileExt == "jpg") || (myFileExt == "jpeg") || (myFileExt == "jpe") || (myFileExt == "jfif"))
            {
                fileImageFormat = System.Drawing.Imaging.ImageFormat.Jpeg;
            }
            else if (myFileExt == "gif")
            {
                fileImageFormat = System.Drawing.Imaging.ImageFormat.Gif;
            }
            else if ((myFileExt == "tif") || (myFileExt == "tiff"))
            {
                fileImageFormat = System.Drawing.Imaging.ImageFormat.Tiff;
            }
            else
            {
                fileImageFormat = System.Drawing.Imaging.ImageFormat.Png;
            }

            myImage = new Bitmap(Image.FromFile(myFileName));
            pictureBox1.ClientSize = new Size(myImage.Width, myImage.Height);
            pictureBox1.Image = myImage;
            saveToolStripMenuItem.Enabled = false;
            MonitorEditMenu();
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        // On ImageForm closing the user is prompted to save the image, if needed.
        private void ImageForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (saveToolStripMenuItem.Enabled == true)
            {
                DialogResult result;
                result = MessageBox.Show("Save changes to '" + this.Text + "'?", "Paint Application",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button3);
                if (result == DialogResult.Yes)
                {
                    saveAsToolStripMenuItem_Click(sender, e);
                }
                else if (result == DialogResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (fileName != "")
            {
                myImage.Save(fileName, fileImageFormat);
                saveToolStripMenuItem.Enabled = false;
            }
            else // if the image isn't provided yet with a fileName, the save method calls saveAs
            {
                saveAsToolStripMenuItem_Click(sender, e);
            }
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFile1 = new SaveFileDialog();
            saveFile1.AddExtension = true;
            saveFile1.OverwritePrompt = true;
            saveFile1.Filter = "Bitmap Files (*.bmp;*.dib)|*.bmp;*.dib|JPEG (*.jpg;*.jpeg;*.jpe;*.jfif)|*.jpg;*.jpeg;*.jpe;*.jfif|" +
                "GIF (*.gif)|*.gif|TIFF (*.tif;*.tiff)|*.tif;*.tiff|PNG (*.png)|*.png";

            // If the image provides ImageFormat (i.e. it is not 'Untitled'), 
            // the dialog jumps to the appropriate FilterIndex.
            if (fileImageFormat != null) 
            {
                if (fileImageFormat == System.Drawing.Imaging.ImageFormat.Bmp)
                {
                    saveFile1.FilterIndex = 1;
                }
                else if (fileImageFormat == System.Drawing.Imaging.ImageFormat.Jpeg)
                {
                    saveFile1.FilterIndex = 2;
                }
                else if (fileImageFormat == System.Drawing.Imaging.ImageFormat.Gif)
                {
                    saveFile1.FilterIndex = 3;
                }
                else if (fileImageFormat == System.Drawing.Imaging.ImageFormat.Tiff)
                {
                    saveFile1.FilterIndex = 4;
                }
                else if (fileImageFormat == System.Drawing.Imaging.ImageFormat.Png)
                {
                    saveFile1.FilterIndex = 5;
                }                
            }
            else // if the image isn't provided yet with ImageFormat, the default is Png
            {
                fileImageFormat = System.Drawing.Imaging.ImageFormat.Png;
                saveFile1.FilterIndex = 5;
            }

            // If the image provides fileName (i.e. it is not 'Untitled'), 
            // the dialog uses it, and also jumps to the appropriate directory.
            if (fileName != "")
            {
                saveFile1.FileName = fileName.Substring(fileName.LastIndexOf("\\") + 1).Remove(fileName.Substring(fileName.LastIndexOf("\\") + 1).LastIndexOf("."));
                saveFile1.InitialDirectory = (fileName.Remove(fileName.LastIndexOf("\\") + 1));
            }
            else // if the image is 'Untitled', it is used as default FileName
            {
                saveFile1.FileName = this.Text;
            }

            if (saveFile1.ShowDialog() == System.Windows.Forms.DialogResult.OK &amp;&amp;
               saveFile1.FileName.Length &gt; 0)
            {
                fileName = saveFile1.FileName;
                this.Text = saveFile1.FileName.Substring(fileName.LastIndexOf("\\") + 1);

                // On DialogResult.OK, the fileImageFormat is updated.
                switch (saveFile1.FilterIndex)
                {
                    case 1:
                        fileImageFormat = System.Drawing.Imaging.ImageFormat.Bmp;
                        break;
                    case 2:
                        fileImageFormat = System.Drawing.Imaging.ImageFormat.Jpeg;
                        break;
                    case 3:
                        fileImageFormat = System.Drawing.Imaging.ImageFormat.Gif;
                        break;
                    case 4:
                        fileImageFormat = System.Drawing.Imaging.ImageFormat.Tiff;
                        break;
                    case 5:
                        fileImageFormat = System.Drawing.Imaging.ImageFormat.Png;
                        break;
                }
                myImage.Save(saveFile1.FileName, fileImageFormat);
                saveToolStripMenuItem.Enabled = false;
            }
        }

        /* The four methods below serve the print items of the File menu. */

        private void pageSetupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            myPageSetupDialog.PageSettings = myPageSettings;
            myPageSetupDialog.ShowDialog();
            myPrintDocument.DefaultPageSettings = myPageSettings;
        }

        private void printPreviewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            myPrintPreviewDialog.Document = myPrintDocument;
            myPrintPreviewDialog.ShowDialog();
        }

        private void printToolStripMenuItem_Click(object sender, EventArgs e)
        {
            myPrintDialog.Document = myPrintDocument;
            myPrintDialog.AllowSomePages = false;
            if (myPrintDialog.ShowDialog() == DialogResult.OK)
            {
                myPrintDocument.Print();
            }
        }

        private void myPrintDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            // Here myPrintArea of the image is determined according to 
            // the page orientation and margins on myPageSettings 
            // (which were defined in myPageSetupDialog).
            if (myPageSettings.Landscape == false) // for Portrait page printing
            {
                myPrintArea = new Rectangle(myPageSettings.Margins.Left, myPageSettings.Margins.Top,
                    (myPageSettings.PaperSize.Width - myPageSettings.Margins.Left - myPageSettings.Margins.Right),
                    (myPageSettings.PaperSize.Height - myPageSettings.Margins.Top - myPageSettings.Margins.Bottom));
                myPrintArea.Height = (int)(myPrintArea.Width * myImage.Height / myImage.Width);

                // This fixes myPrintArea if myImage aspect ratio is narrower than the page's. 
                if (myPrintArea.Height &gt; (myPageSettings.PaperSize.Height - myPageSettings.Margins.Top - myPageSettings.Margins.Bottom))
                {
                    myPrintArea.Height = (myPageSettings.PaperSize.Height - myPageSettings.Margins.Top - myPageSettings.Margins.Bottom);
                    myPrintArea.Width = myPrintArea.Height * myImage.Width / myImage.Height;
                }
            }
            else // for landscape page printing
            {
                myPrintArea = new Rectangle(myPageSettings.Margins.Bottom, myPageSettings.Margins.Left,
                   (myPageSettings.PaperSize.Height - myPageSettings.Margins.Top - myPageSettings.Margins.Bottom),
                   (myPageSettings.PaperSize.Width - myPageSettings.Margins.Left - myPageSettings.Margins.Right));
                myPrintArea.Width = (int)(myPrintArea.Height * myImage.Width / myImage.Height);

                // This fixes myPrintArea if myImage aspect ratio is wider than the page's.
                if (myPrintArea.Width &gt; (myPageSettings.PaperSize.Height - myPageSettings.Margins.Top - myPageSettings.Margins.Bottom))
                {
                    myPrintArea.Width = (myPageSettings.PaperSize.Height - myPageSettings.Margins.Top - myPageSettings.Margins.Bottom);
                    myPrintArea.Height = myPrintArea.Width * myImage.Height / myImage.Width;
                }
            }

            e.Graphics.DrawImage(myImage, myPrintArea);
        }

        /* The nine methods below process the tasks of the Edit menu items,
           in the order of their appearance. */

        private void undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            mySelectionState = SelectionState.None; // the Undo first clears any existing selection
            if (undoStack.Count &gt; 0)
            {
                Bitmap pushImage = new Bitmap(myImage);
                redoStack.Push(pushImage); // the current myImage is pushed to the redoStack
                myImage = undoStack.Pop();
                pictureBox1.Image = myImage;
                saveToolStripMenuItem.Enabled = true;
            }
            MonitorEditMenu();
        }

        private void redoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            mySelectionState = SelectionState.None; // the Redo first clears any existing selection
            if (redoStack.Count &gt; 0)
            {
                Bitmap pushImage = new Bitmap(myImage);
                undoStack.Push(pushImage); // the current myImage is pushed to the undoStack
                myImage = redoStack.Pop();
                pictureBox1.Image = myImage;
                saveToolStripMenuItem.Enabled = true;
            }
            MonitorEditMenu();
        }

        // Pushes myImage into the undoStack.
        // Always called before a change is applied.
        public void PushEdit()
        {
            saveToolStripMenuItem.Enabled = true;
            redoStack.Clear();
            Bitmap pushImage = new Bitmap(myImage);
            undoStack.Push(pushImage);
        }

        private void cutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetImage(selectBi);

            // The cut method calls the delete method to erase the selection original location.
            deleteToolStripMenuItem_Click(sender, e);
        }

        private void copyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetImage(selectBi);
        }

        private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            mySelectionState = SelectionState.None; // pasting first clears any existing selection
            selectBi = (Bitmap)Clipboard.GetImage();
            FetchSelection();
            selectChanged = true; // a pasted selection is always considered as changed
            selectPaste = true;
        }

        // Called by the paste and selectAll methods, to define
        // a selection and locate it on the upper-left corner.
        private void FetchSelection()
        {
            selectionWidth = selectBi.Width;
            selectionHeight = selectBi.Height;
            if (selectionWidth &gt; 0 &amp;&amp; selectionHeight &gt; 0)
            {
                selectionLocationX = selectionStartX = 0;
                selectionLocationY = selectionStartY = 0;
                mySelection = new Rectangle(selectionStartX, selectionStartY, selectionWidth, selectionHeight);
                mySelectionState = SelectionState.Selected;

                tempBi = (Bitmap)myImage.Clone();
                Graphics tempGr = Graphics.FromImage(tempBi);
                tempGr.DrawImage(selectBi, selectionLocationX, selectionLocationY);
                tempGr.DrawRectangle(selectPen, selectionLocationX, selectionLocationY, selectionWidth - 1, selectionHeight - 1);
                pictureBox1.Image = tempBi;

                ((Main)(this.MdiParent)).ChosenToolUpdate("select");
            }
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (selectPaste == false)
            {
                PushEdit();
                Graphics g = Graphics.FromImage(myImage);
                selectionCutBrush = new SolidBrush(ColorsWindow.MyBackColor);
                g.FillRectangle(selectionCutBrush, mySelection);
            }
            pictureBox1.Image = myImage;

            // After erasing the selection original location, 
            // the selection is cleared.
            mySelectionState = SelectionState.None;
        }

        private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            mySelectionState = SelectionState.None;
            selectBi = (Bitmap)myImage.Clone();
            FetchSelection();
            selectPaste = false;
        }

        /* The five methods below process the tasks of the Image menu items,
           in the order of their appearance. */

        private void brightnessToolStripMenuItem_Click(object sender, EventArgs e)
        {
            BrightnessDialog MyBrightnessDialog = new BrightnessDialog();
            MyBrightnessDialog.Owner = this; // the new BrightnessDialog is owned by the ImageForm for interaction
            if (MyBrightnessDialog.ShowDialog() == DialogResult.OK)
            {
                if (mySelectionState == SelectionState.Selected) // the brightness is applied to the selection, if such exists
                {
                    // Here PushEdit is not needed, since the selection is yet to dropped down.
                    selectBi = BrightenImage(selectBi, MyBrightnessDialog.BrightnessLevel);
                    UpdateProcessedSelectionBitmap();
                }
                else // the brightness is applied to myImage
                {
                    PushEdit();
                    myImage = BrightenImage(myImage, MyBrightnessDialog.BrightnessLevel);
                    pictureBox1.Image = myImage;
                }
            }
        }

        // Returns a brightened Bitmap according to the level defined in MyBrightnessDialog.
        // This method is public so MyBrightnessDialog can access it for its' preview.
        public Bitmap BrightenImage(Bitmap imageToBrighten, int brightnessLevel)
        {
            int newR, newG, newB;
            for (int x = 0; x &lt; imageToBrighten.Width; x++)
            {
                for (int y = 0; y &lt; imageToBrighten.Height; y++)
                {
                    newR = imageToBrighten.GetPixel(x, y).R + brightnessLevel;
                    if (newR &gt; 255)
                        newR = 255;
                    else if (newR &lt; 0)
                        newR = 0;
                    newG = imageToBrighten.GetPixel(x, y).G + brightnessLevel;
                    if (newG &gt; 255)
                        newG = 255;
                    else if (newG &lt; 0)
                        newG = 0;
                    newB = imageToBrighten.GetPixel(x, y).B + brightnessLevel;
                    if (newB &gt; 255)
                        newB = 255;
                    else if (newB &lt; 0)
                        newB = 0;
                    imageToBrighten.SetPixel(x, y, Color.FromArgb(newR, newG, newB));
                }
            }
            return imageToBrighten;
        }

        private void invertToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (mySelectionState == SelectionState.Selected) // the inversion is applied to the selection, if such exists
            {
                // Here PushEdit is not needed, since the selection is yet to dropped down.
                selectBi = InvertImage(selectBi);
                UpdateProcessedSelectionBitmap();
            }
            else // the inversion is applied to myImage
            {
                PushEdit();
                myImage = InvertImage(myImage);
                pictureBox1.Image = myImage;
            }
        }

        // Returns an inverted Bitmap.
        private Bitmap InvertImage(Bitmap imageToInvert)
        {
            int invR, invG, invB;
            for (int x = 0; x &lt; imageToInvert.Width; x++)
            {
                for (int y = 0; y &lt; imageToInvert.Height; y++)
                {
                    invR = 255 - imageToInvert.GetPixel(x, y).R;
                    invG = 255 - imageToInvert.GetPixel(x, y).G;
                    invB = 255 - imageToInvert.GetPixel(x, y).B;
                    imageToInvert.SetPixel(x, y, Color.FromArgb(invR, invG, invB));
                }
            }
            return imageToInvert;
        }

        // If an image filter (i.e. brightness or invert) 
        // is applied to a selection, this method is called 
        // to update the selection display after processing.
        private void UpdateProcessedSelectionBitmap()
        {
            selectChanged = true; // declares the processed selection as changed
            tempBi = (Bitmap)myImage.Clone();
            Graphics tempGr = Graphics.FromImage(tempBi);
            if (selectPaste == false)
            {
                selectionCutBrush = new SolidBrush(ColorsWindow.MyBackColor);
                tempGr.FillRectangle(selectionCutBrush, mySelection);
            }
            tempGr.DrawImage(selectBi, selectionLocationX, selectionLocationY);
            tempGr.DrawRectangle(selectPen, selectionLocationX, selectionLocationY, selectionWidth, selectionHeight);
            pictureBox1.Image = tempBi;
        }
    }
}&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-3386152358556293408?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/3386152358556293408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/10/paint-application-c.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/3386152358556293408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/3386152358556293408'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/10/paint-application-c.html' title='Paint Application [C#]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_CjLw9oSooQ0/SuWu-madmII/AAAAAAAAABA/56thj2dyFx8/s72-c/paint_app-screenshot_1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-434622186073563937</id><published>2009-10-05T14:05:00.008+02:00</published><updated>2009-10-05T14:28:21.442+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MDI Application'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>VBScript Editor [C#]</title><content type='html'>&lt;p&gt;Hi there. I wrote a simple VBScript Editor in C#, here is a summary of it:&lt;/p&gt;
&lt;p&gt;It is a Multiple-Document Interface application, the main menu is merged with a non-visible MenuStrip on the Document form.&lt;/p&gt;
&lt;p&gt;Syntax coloring and letter casing is done live, based on the lines affected by the change in the text. The keywords for each color are stored in a regular expression.&lt;/p&gt;
&lt;p&gt;Line numbers and column ruler are achieved by RichTextBoxes moved on separate panels. Line and column markers are updated according to the caret's position.&lt;/p&gt;
&lt;p&gt;The data for the multiple undo and redo features is stored in Stacks.&lt;/p&gt; 
&lt;p&gt;Printing is available using the &lt;a href="http://support.microsoft.com/kb/812425"&gt;RichTextBoxPrintCtrl&lt;/a&gt; from Microsoft.&lt;/p&gt;
&lt;p&gt;The tool windows, 'Find\Replace' and 'Jump to line' are always owned by the current active Document.&lt;/p&gt;

&lt;a href="http://3.bp.blogspot.com/_CjLw9oSooQ0/SsnhW1REaMI/AAAAAAAAAA4/3VEAByAeLZE/s1600-h/vbscript_editor-screenshot.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 241px;" src="http://3.bp.blogspot.com/_CjLw9oSooQ0/SsnhW1REaMI/AAAAAAAAAA4/3VEAByAeLZE/s400/vbscript_editor-screenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5389086211497552066" /&gt;&lt;/a&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Here is the code for the Document form:&lt;/p&gt;
&lt;textarea rows="28" cols="48" Wrap=Off&gt;using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Drawing.Printing;

namespace VBScriptEditor
{
    public partial class Document : Form
    {
        public Document()
        {
            // Create the font for all controls, and measure its' character size.
            myFont = new Font("Courier New", 11);
            myFontHeight = TextRenderer.MeasureText("A", myFont).Height;
            myFontWidth = TextRenderer.MeasureText("A", myFont).Width;

            InitializeComponent();

            // Subscribe to events for printing.
            this.printDocument1.BeginPrint += new System.Drawing.Printing.PrintEventHandler(this.printDocument1_BeginPrint);
            this.printDocument1.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.printDocument1_PrintPage);

            // Set myFont for all RichTextBox controls on the form.
            // Use its' measurements as a basic unit for the size of all controls.
            columnRulerMarker.Font = columnRulerBox.Font = lineNumbersMarker.Font = lineNumbersBox.Font = richTextBox1.Font = myFont;
            verticalSplitContainer.SplitterDistance = lineNumbersMarker.Width = lineNumbersBox.Width = myFontWidth;
            columnRulerMarker.Width = myFontWidth * 2 / 3;
            horizontalSplitContainer.SplitterDistance = columnRulerMarker.Height = columnRulerBox.Height = lineNumbersMarker.Height = lineNumbersBox.Height = myFontHeight;
            columnRulerMarker.Location = columnRulerBox.Location = new Point((lineNumbersBox.Width + verticalSplitContainer.SplitterWidth), 0);
            columnRulerBox.Width = richTextBox1.Width;
            columnRulerBox.Text = rulerUnit;

            // Create the ContextMenuStrip for richTextBox1.
            ToolStripMenuItem[] richTextBox1_MenuGroup1 = new ToolStripMenuItem[2];
            richTextBox1_MenuGroup1[0] = new ToolStripMenuItem("Undo",
                null, new System.EventHandler(undoToolStripMenuItem_Click));
            richTextBox1_MenuGroup1[1] = new ToolStripMenuItem("Redo",
                null, new System.EventHandler(redoToolStripMenuItem_Click));
            ToolStripMenuItem[] richTextBox1_MenuGroup2 = new ToolStripMenuItem[4];
            richTextBox1_MenuGroup2[0] = new ToolStripMenuItem("Cut",
                null, new System.EventHandler(cutToolStripMenuItem_Click));
            richTextBox1_MenuGroup2[1] = new ToolStripMenuItem("Copy",
                null, new System.EventHandler(copyToolStripMenuItem_Click));
            richTextBox1_MenuGroup2[2] = new ToolStripMenuItem("Paste",
                null, new System.EventHandler(pasteToolStripMenuItem_Click));
            richTextBox1_MenuGroup2[3] = new ToolStripMenuItem("Delete",
                null, new System.EventHandler(deleteToolStripMenuItem_Click));
            ToolStripMenuItem[] richTextBox1_MenuGroup3 = new ToolStripMenuItem[1];
            richTextBox1_MenuGroup3[0] = new ToolStripMenuItem("Select All",
                null, new System.EventHandler(selectAllToolStripMenuItem_Click));
            ContextMenuStrip richTextBox1_Menu = new ContextMenuStrip();
            richTextBox1_Menu.Items.AddRange(richTextBox1_MenuGroup1);
            richTextBox1_Menu.Items.Add("-");
            richTextBox1_Menu.Items.AddRange(richTextBox1_MenuGroup2);
            richTextBox1_Menu.Items.Add("-");
            richTextBox1_Menu.Items.AddRange(richTextBox1_MenuGroup3);
            richTextBox1.ContextMenuStrip = richTextBox1_Menu;
            richTextBox1.ContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip_Opening);
            richTextBox1.ContextMenuStrip.Enabled = true;

            // Set the tabs for richTextBox1.
            int myTabWidth = myFontWidth * 95 / 100;
            int[] myTabs = new int[32];
            for (int i = 0; i &lt; myTabs.Length; i++)
            {
                myTabs[i] = myTabWidth * (i + 1);
            }
            SendMessage(richTextBox1.Handle, EM_SETTABSTOPS, 1, myTabs);

            // Arrange the placement of all controls,
            // and update the edit menu items accordingly.
            FixLineNumbers();
            ScrollColumnRuler();
            MoveMarkers();
            MonitorEditMenu();
            saveToolStripMenuItem.Enabled = false;
        }

        // needed for window update locking while making adjustments
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool LockWindowUpdate(IntPtr hWndLock);

        // needed for setting the tabs on richTextBox1
        private const int EM_SETTABSTOPS = 0x00CB;
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr h, int msg, int wParam, int[] lParam);

        private int checkPrint;

        private Font myFont;
        private int myFontHeight, myFontWidth;
        private string rulerUnit = "----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0";
        private string fileName = "";

        private Stack undoStack = new Stack();
        private Stack redoStack = new Stack();

        private int lastLinesLength;
        private int lastLineNumbersLength = 1;
        
        private int lastKeyPosition;
        private Keys lastKey = new Keys();

        // property for getting the document's 
        // filename by the main application form. 
        public string FileName
        {
            get { return fileName; }
        }

        // Process syntax coloring, line numbering 
        // and markers location while text is being typed.
        // Any other method which changes the text on richTextBox1
        // will temporarily unsubscribe this method from the TextChanged event.
        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            richTextBox1.SelectionChanged -= new System.EventHandler(richTextBox1_SelectionChanged);
            int originStart = richTextBox1.SelectionStart;
            LockWindowUpdate(this.Handle);

            // The text is checked a character before and a character after
            // the change location, so in cases of line-breaks
            // both of the new lines will be processed.
            GetLines(originStart - 1, originStart + 1);
            richTextBox1.SelectionStart = originStart;
            MoveMarkers();
            if (richTextBox1.Lines.Length != lastLinesLength)
            {
                FixLineNumbers();
            }
            lineNumbersBox.Location = new Point(0, richTextBox1.GetPositionFromCharIndex(0).Y);
            LockWindowUpdate(IntPtr.Zero);
            lastLinesLength = richTextBox1.Lines.Length;
            saveToolStripMenuItem.Enabled = true;
            richTextBox1.SelectionChanged += new System.EventHandler(richTextBox1_SelectionChanged);
        }

        // Gets all lines in a range of character indexes,
        // and sends each line for syntax coloring.
        private void GetLines(int runStart, int runEnd)
        {
            for (int i = richTextBox1.GetLineFromCharIndex(runStart); i &lt;= richTextBox1.GetLineFromCharIndex(runEnd); i++)
            {
                FixLine(i);
            }
        }

        // Colors the syntax of a single line.
        private void FixLine(int myLine)
        {
            if (richTextBox1.TextLength &lt; 1)
            {
                richTextBox1.SelectionStart = 0;
                richTextBox1.SelectionStart = 0;
            }
            else
            {
                richTextBox1.Select((richTextBox1.GetFirstCharIndexFromLine(myLine)), (richTextBox1.Lines[myLine].Length));
            }
            richTextBox1.SelectionColor = Color.Black;
            MatchCollection myQuotes = Keywords.QM.Matches(richTextBox1.SelectedText);
            MatchCollection myComments = Keywords.CO.Matches(richTextBox1.SelectedText);
            MatchCollection myFunctions = Keywords.FC.Matches(richTextBox1.SelectedText);
            MatchCollection myStatements = Keywords.ST.Matches(richTextBox1.SelectedText);
            MatchCollection myLetterCase = Keywords.LC.Matches(richTextBox1.SelectedText);
            for (int i = 0; i &lt; myQuotes.Count; i += 2)
            {
                int j = i + 1;
                richTextBox1.SelectionStart = (myQuotes[i].Index + richTextBox1.GetFirstCharIndexFromLine(myLine));
                if (j &lt; myQuotes.Count)
                {    
                    richTextBox1.SelectionLength = (1 - myQuotes[i].Index + myQuotes[j].Index);   
                }
                else
                {
                    richTextBox1.SelectionLength = 1;
                }
                richTextBox1.SelectionColor = Color.DeepPink;
                richTextBox1.DeselectAll();
            }
            for (int i = 0; i &lt; myComments.Count; i++)
            {
                richTextBox1.Select((myComments[i].Index + richTextBox1.GetFirstCharIndexFromLine(myLine)), (myComments[i].Length));
                if (richTextBox1.SelectionColor == Color.Black)
                {
                    richTextBox1.SelectionLength = richTextBox1.Lines[myLine].Length - myComments[i].Index;
                    richTextBox1.SelectionColor = Color.Green;
                }
            }
            for (int i = 0; i &lt; myFunctions.Count; i++)
            {
                richTextBox1.Select((myFunctions[i].Index + richTextBox1.GetFirstCharIndexFromLine(myLine)), (myFunctions[i].Length));
                if (richTextBox1.SelectionColor == Color.Black)
                {
                    richTextBox1.SelectionColor = Color.Red;
                    richTextBox1.SelectionLength = 1;
                    richTextBox1.SelectedText = richTextBox1.SelectedText.ToUpper();
                    if (myFunctions[i].Length &gt; 1)
                    {
                        richTextBox1.SelectionLength = (myFunctions[i].Length - 1);
                        richTextBox1.SelectedText = richTextBox1.SelectedText.ToLower();
                    }
                }
            }
            for (int i = 0; i &lt; myStatements.Count; i++)
            {
                richTextBox1.Select((myStatements[i].Index + richTextBox1.GetFirstCharIndexFromLine(myLine)), (myStatements[i].Length));
                if (richTextBox1.SelectionColor == Color.Black)
                {
                    richTextBox1.SelectionColor = Color.Blue;
                    richTextBox1.SelectionLength = 1;
                    richTextBox1.SelectedText = richTextBox1.SelectedText.ToUpper();
                    if (myStatements[i].Length &gt; 1)
                    {
                        richTextBox1.SelectionLength = (myStatements[i].Length - 1);
                        richTextBox1.SelectedText = richTextBox1.SelectedText.ToLower();
                    }
                }
            }
            for (int i = 0; i &lt; myLetterCase.Count; i++)
            {
                richTextBox1.Select((myLetterCase[i].Index + richTextBox1.GetFirstCharIndexFromLine(myLine)), 1);
                if ((richTextBox1.SelectionColor != Color.Black) &amp;&amp; (richTextBox1.SelectionColor != Color.DeepPink) &amp;&amp; (richTextBox1.SelectionColor != Color.Green))
                {
                    richTextBox1.SelectedText = richTextBox1.SelectedText.ToUpper();
                }
            }
            richTextBox1.DeselectAll();
        }

        /* The four methods below are called accrodingly
           during the various adjustements which occur in the Document. */

        // Updates the text and height of the lineNumbersBox.
        private void FixLineNumbers()
        {
            string linesLengthString = (richTextBox1.Lines.Length).ToString();
            if (richTextBox1.Lines.Length &gt; lineNumbersBox.Lines.Length + 1)
            {
                lineNumbersBox.Text = "1";
                for (int i = 2; i &lt;= richTextBox1.Lines.Length; i++)
                {
                    lineNumbersBox.AppendText("\n");
                    lineNumbersBox.AppendText(i.ToString());
                }
            }
            else if (richTextBox1.Lines.Length == lineNumbersBox.Lines.Length + 1)
            {
                lineNumbersBox.AppendText("\n");
                lineNumbersBox.AppendText(richTextBox1.Lines.Length.ToString());
            }
            else if (richTextBox1.Lines.Length &lt; 1)
            {
                lineNumbersBox.Text = "1";
            }
            lineNumbersBox.Height = (richTextBox1.Lines.Length * myFontHeight);
            if (linesLengthString.Length != lastLineNumbersLength)
            {
                lineNumbersBox.Width = linesLengthString.Length * myFontWidth;
                lineNumbersMarker.Width = lineNumbersBox.Width;
                verticalSplitContainer.SplitterDistance = lineNumbersBox.Width;
                ScrollColumnRuler();
                MoveMarkers();
            }
            lastLineNumbersLength = linesLengthString.Length;
        }

        // Updates the location of the lineNumbersBox 
        // and lineNumbersMarker for scrolling.
        private void ScrollLineNumbers()
        {
            lineNumbersBox.Location = new Point(0, richTextBox1.GetPositionFromCharIndex(0).Y);
            lineNumbersMarker.Location = new Point(0, richTextBox1.GetPositionFromCharIndex(richTextBox1.SelectionStart).Y);
        }

        // Updates the location and of the columnRulerBox 
        // and columnRulerMarker for scrolling.
        // Appends the columnRulerBox with more units if needed.
        private void ScrollColumnRuler()
        {
            columnRulerBox.Location = new Point((richTextBox1.GetPositionFromCharIndex(0).X + lineNumbersBox.Width + verticalSplitContainer.SplitterWidth), 0);
            columnRulerBox.Width = columnRulerBox.Location.X * -1 + this.Width;
            if ((columnRulerBox.Width * 2) &gt; (columnRulerBox.TextLength * myFontWidth))
            {
                columnRulerBox.AppendText(rulerUnit);
            }
        }

        // Updates both markers location for non-scrolling actions
        // and sets them with the appropriate text.
        private void MoveMarkers()
        {
            lineNumbersMarker.Location = new Point(0, richTextBox1.GetPositionFromCharIndex(richTextBox1.SelectionStart).Y);
            lineNumbersMarker.Text = ((lineNumbersMarker.Location.Y + lineNumbersBox.Location.Y * -1) / myFontHeight + 1).ToString();
            columnRulerMarker.Location = new Point((richTextBox1.GetPositionFromCharIndex(richTextBox1.SelectionStart).X + lineNumbersBox.Width + verticalSplitContainer.SplitterWidth), 0);
            columnRulerMarker.Text = (columnRulerBox.GetCharFromPosition(new Point(columnRulerBox.Width - this.Width + columnRulerMarker.Location.X, 0)).ToString());
        }

        // Uses to block focus from any control other than richTextBox1.
        private void richTextBox2_Enter(object sender, EventArgs e)
        {
            richTextBox1.Focus();
        }

        /* The four methods below call the appropriate methods
           when resizing the form, scrolling richTextBox1 
           and moving the caret in richTextBox1. */

        private void richTextBox1_VScroll(object sender, EventArgs e)
        {
            ScrollLineNumbers();
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            if (this.WindowState != FormWindowState.Maximized)
            {
                ScrollLineNumbers();
            }
            ScrollColumnRuler();
            MoveMarkers();
        }

        private void richTextBox1_SelectionChanged(object sender, EventArgs e)
        {
            MoveMarkers();

            // Call the method to update edit menu items,
            // since the cut, copy and delete items are enabled 
            // and disabled according to the selection start and length.
            MonitorEditMenu();
        }

        private void richTextBox1_HScroll(object sender, EventArgs e)
        {
            ScrollColumnRuler();
            MoveMarkers();
        }

        // Processes keys pressed on richTextBox1,
        // and determines wheter to push the state before into the Undo stack.
        private void richTextBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (!e.Control &amp;&amp; !e.Alt &amp;&amp; !e.Shift &amp;&amp; (e.KeyData &lt; Keys.Prior || e.KeyData &gt; Keys.Insert) &amp;&amp;
                ((lastKey &lt; Keys.A || lastKey &gt; Keys.Z) || (richTextBox1.SelectionStart != lastKeyPosition + 1)))
            {
                PushEdit();
            }

            // The data and caret location for the last key pressed
            // are used for comparison with the current key pressed.
            lastKey = e.KeyData;
            lastKeyPosition = richTextBox1.SelectionStart;
        }

        // Enables and disables the edit menu items appropriatly.
        private void MonitorEditMenu()
        {
            if (undoStack.Count &lt; 1)
            {
                undoToolStripMenuItem.Enabled = false;
            }
            else
            {
                undoToolStripMenuItem.Enabled = true;
            }
            if (redoStack.Count &lt; 1)
            {
                redoToolStripMenuItem.Enabled = false;
            }
            else
            {
                redoToolStripMenuItem.Enabled = true;
            }
            if (richTextBox1.SelectionLength &lt; 1)
            {
                cutToolStripMenuItem.Enabled = false;
                copyToolStripMenuItem.Enabled = false;
            }
            else
            {
                cutToolStripMenuItem.Enabled = true;
                copyToolStripMenuItem.Enabled = true;
            }
            if (richTextBox1.SelectionStart == richTextBox1.TextLength)
            {
                deleteToolStripMenuItem.Enabled = false;
            }
            else
            {
                deleteToolStripMenuItem.Enabled = true;
            }
            if (richTextBox1.TextLength &lt; 1)
            {
                selectAllToolStripMenuItem.Enabled = false;
            }
            else
            {
                selectAllToolStripMenuItem.Enabled = true;
            }
            if (!Clipboard.ContainsText())
            {
                pasteToolStripMenuItem.Enabled = false;
            }
            else
            {
                pasteToolStripMenuItem.Enabled = true;
            }
        }

        /* The methods below process the tasks of each menu strip item,
           in the order of their appearance. */

        public void FileOpen(string myFileName)
        {
            richTextBox1.TextChanged -= new System.EventHandler(richTextBox1_TextChanged);
            LockWindowUpdate(this.Handle);
            fileName = myFileName;
            richTextBox1.LoadFile(fileName, RichTextBoxStreamType.PlainText);
            GetLines(0, richTextBox1.TextLength);
            FixLineNumbers();
            richTextBox1.SelectionStart = 0;
            saveToolStripMenuItem.Enabled = false;
            LockWindowUpdate(IntPtr.Zero);
            MonitorEditMenu();
            richTextBox1.TextChanged += new System.EventHandler(richTextBox1_TextChanged);
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void Document_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (saveToolStripMenuItem.Enabled == true)
            {
                DialogResult result;
                result = MessageBox.Show("Save changes to '" + this.Text + "'?", "VBScript Editor",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button3);
                if (result == DialogResult.Yes)
                {
                    saveAsToolStripMenuItem_Click(sender, e);
                }
                else if (result == DialogResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (fileName != "")
            {
                richTextBox1.SaveFile(fileName, RichTextBoxStreamType.PlainText);
                saveToolStripMenuItem.Enabled = false;
            }
            else
            {
                saveAsToolStripMenuItem_Click(sender, e);
            }
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFile1 = new SaveFileDialog();
            saveFile1.OverwritePrompt = true;
            saveFile1.DefaultExt = ("*.vbs");
            saveFile1.Filter = "All Files (*.vbs;*.txt)|*.vbs;*.txt|VBScript (*.vbs)|*.vbs|Text Files (*.txt)|*.txt";
            if (fileName != "")
            {
                saveFile1.FileName = fileName.Substring(fileName.LastIndexOf("\\") + 1);
                saveFile1.InitialDirectory = (fileName.Remove(fileName.LastIndexOf("\\") + 1));
            }
            else
            {
                saveFile1.FileName = this.Text;
            }
            if (saveFile1.ShowDialog() == System.Windows.Forms.DialogResult.OK &amp;&amp;
               saveFile1.FileName.Length &gt; 0)
            {
                fileName = saveFile1.FileName;
                this.Text = saveFile1.FileName.Substring(fileName.LastIndexOf("\\") + 1);
                richTextBox1.SaveFile(saveFile1.FileName, RichTextBoxStreamType.PlainText);
                saveToolStripMenuItem.Enabled = false;
            }
        }

        /* The five methods below are copied from Microsoft's RichTextBoxPrintCtrl
           tutorial for printing RichTextBox contents. */

        private void pageSetupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            pageSetupDialog1.ShowDialog();
        }

        private void printPreviewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            printPreviewDialog1.ShowDialog();
        }

        private void printToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (printDialog1.ShowDialog() == DialogResult.OK)
                printDocument1.Print();
        }

        private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
        {
            checkPrint = 0;
        }

        private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            // Print the content of RichTextBox. Store the last character printed.
            checkPrint = richTextBox1.Print(checkPrint, richTextBox1.TextLength, e);

            // Check for more pages
            if (checkPrint &lt; richTextBox1.TextLength)
                e.HasMorePages = true;
            else
                e.HasMorePages = false;
        }

        private void undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            richTextBox1.TextChanged -= new System.EventHandler(richTextBox1_TextChanged);
            if (undoStack.Count &gt; 0)
            {
                LockWindowUpdate(this.Handle);

                // The Undo first pushes the current state
                // into the Redo stack.
                Hashtable myState = new Hashtable();
                myState["text"] = richTextBox1.Rtf;
                myState["position"] = richTextBox1.SelectionStart;
                redoStack.Push(myState);

                // Then, the last state is popped from the Undo stack.
                Hashtable undoState = (Hashtable)undoStack.Pop();
                richTextBox1.Rtf = (string)undoState["text"];
                richTextBox1.SelectionStart = (int)undoState["position"];

                FixLineNumbers();
                LockWindowUpdate(IntPtr.Zero);
                saveToolStripMenuItem.Enabled = true;
            }
            MonitorEditMenu();
            richTextBox1.TextChanged += new System.EventHandler(richTextBox1_TextChanged);
        }

        private void redoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            richTextBox1.TextChanged -= new System.EventHandler(richTextBox1_TextChanged);
            if (redoStack.Count &gt; 0)
            {
                LockWindowUpdate(this.Handle);

                // The Redo first pushes the current state
                // into the Undo stack.
                Hashtable myState = new Hashtable();
                myState["text"] = richTextBox1.Rtf;
                myState["position"] = richTextBox1.SelectionStart;
                undoStack.Push(myState);

                // Then, the last state is popped from the Redo stack.
                Hashtable redoState = (Hashtable)redoStack.Pop();
                richTextBox1.Rtf = (string)redoState["text"];
                richTextBox1.SelectionStart = (int)redoState["position"];
                FixLineNumbers();
                LockWindowUpdate(IntPtr.Zero);
                saveToolStripMenuItem.Enabled = true;
            }
            MonitorEditMenu();
            richTextBox1.TextChanged += new System.EventHandler(richTextBox1_TextChanged);
        }

        // Pushes a state into the Undo stack.
        // This method is always called before the change 
        // in the text is applied (e.g. the PreviewKeyDown event).
        public void PushEdit()
        {
            redoStack.Clear();
            Hashtable myState = new Hashtable();
            myState["text"] = richTextBox1.Rtf;
            myState["position"] = richTextBox1.SelectionStart;
            undoStack.Push(myState);
        }

        private void cutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetDataObject(richTextBox1.SelectedText);
            richTextBox1.SelectedText = "";
        }

        private void copyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetDataObject(richTextBox1.SelectedText);
            MonitorEditMenu();
        }

        private void pasteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            richTextBox1.TextChanged -= new System.EventHandler(richTextBox1_TextChanged);
            if (Clipboard.ContainsText())
            {
                PushEdit();
                LockWindowUpdate(this.Handle);
                int originStart = richTextBox1.SelectionStart;
                richTextBox1.Paste(DataFormats.GetFormat("Text"));
                int newLocation = richTextBox1.SelectionStart;

                // The recoloring range after pasting text
                // starts on the line where the caret was pre-paste,
                // and ends with the line of its' post-paste location.
                GetLines(originStart, newLocation);

                FixLineNumbers();
                richTextBox1.SelectionStart = newLocation;
                LockWindowUpdate(IntPtr.Zero);
                saveToolStripMenuItem.Enabled = true;
            }
            richTextBox1.TextChanged += new System.EventHandler(richTextBox1_TextChanged);
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (richTextBox1.SelectionLength &lt; 1)
            {
                richTextBox1.SelectionLength = 1;
            }
            richTextBox1.SelectedText = "";
        }

        /* The eight methods below are for the Find\Replace 
           and Jump to line tools. */ 

        private void findReplaceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RenewToolWindows();
            ((Main)(this.MdiParent)).FindReplaceWindow.Visible = true;
            ((Main)(this.MdiParent)).FindReplaceWindow.Focus();
        }

        public int FindTextDown(string myFind)
        {
            int findResult = -1;
            richTextBox1.Select(richTextBox1.SelectionStart + richTextBox1.SelectionLength, 0);
            findResult = richTextBox1.Find(myFind, richTextBox1.SelectionStart, richTextBox1.TextLength, RichTextBoxFinds.None);
            if (findResult == -1)
            {
                findResult = richTextBox1.Find(myFind, 0, richTextBox1.TextLength , RichTextBoxFinds.None);
            }

            if (findResult != -1)
            {
                return richTextBox1.SelectionStart;
            }
            else
            {
                return findResult;
            }
        }

        public int FindTextUp(string myFind)
        {
            int findResult = -1;
            richTextBox1.Select(richTextBox1.SelectionStart, 0);
            findResult = richTextBox1.Find(myFind, 0, richTextBox1.SelectionStart, RichTextBoxFinds.Reverse);
            if (findResult == -1)
            {
                findResult = richTextBox1.Find(myFind, 0, richTextBox1.TextLength, RichTextBoxFinds.Reverse);
            }
            return findResult;
        }

        public void ReplaceText(string myFind, string myReplace)
        {
            richTextBox1.TextChanged -= new System.EventHandler(richTextBox1_TextChanged);
            if (richTextBox1.SelectedText.ToLower() == myFind.ToLower())
            {
                PushEdit();
                LockWindowUpdate(this.Handle);
                int originStart = richTextBox1.SelectionStart;
                richTextBox1.SelectedText = myReplace;
                int newLocation = richTextBox1.SelectionStart;
                GetLines(originStart, newLocation);
                FixLineNumbers();
                richTextBox1.SelectionStart = newLocation;
                LockWindowUpdate(IntPtr.Zero);
                saveToolStripMenuItem.Enabled = true;
            }
            richTextBox1.TextChanged += new System.EventHandler(richTextBox1_TextChanged);          
        }

        public int ReplaceAllText(string myFind, string myReplace)
        {
            int replaceCount = 0;

            richTextBox1.TextChanged -= new System.EventHandler(richTextBox1_TextChanged);
            PushEdit();
            LockWindowUpdate(this.Handle);
            richTextBox1.Select(0, 0);
            while (richTextBox1.Find(myFind, richTextBox1.SelectionStart, richTextBox1.TextLength, RichTextBoxFinds.None) != -1)
            {
                richTextBox1.SelectedText = myReplace;
                richTextBox1.SelectionStart += myReplace.Length;
                replaceCount++;
            }
            GetLines(0, richTextBox1.TextLength);
            FixLineNumbers();
            richTextBox1.SelectionStart = 0;
            LockWindowUpdate(IntPtr.Zero);
            saveToolStripMenuItem.Enabled = true;
            richTextBox1.TextChanged += new System.EventHandler(richTextBox1_TextChanged);

            return replaceCount;
        }

        private void jumpToLineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ((Main)(this.MdiParent)).JumpToLineWindow.Visible = true;
            ((Main)(this.MdiParent)).JumpToLineWindow.Focus();
        }

        public int JumpToLine(int myLine)
        {
            try
            {
                richTextBox1.Select((richTextBox1.GetFirstCharIndexFromLine(myLine - 1)), 0);
            }
            catch
            {
                if ((myLine &lt; 1) || (richTextBox1.TextLength &lt; 1))
                {
                    myLine = 1;
                }
                else if (myLine &gt; richTextBox1.Lines.Length)
                {
                    myLine = richTextBox1.Lines.Length;
                }
            }
            finally
            {
                richTextBox1.Select((richTextBox1.GetFirstCharIndexFromLine(myLine - 1)), 0);
            }
            richTextBox1.Focus();
            return myLine;
        }

        // Checks if each of the tool windows are disposed, 
        // and calls a Main application method to re-initialize them.
        private void RenewToolWindows()
        {
            if (((Main)(this.MdiParent)).FindReplaceWindow.IsDisposed)
            {
                ((Main)(this.MdiParent)).RenewFindReplaceWindow();
            }

            if (((Main)(this.MdiParent)).JumpToLineWindow.IsDisposed)
            {
                ((Main)(this.MdiParent)).RenewJumpToLineWindow();
            }
        }

        private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            richTextBox1.SelectAll();
        }

        /* Here end the methods for the menu strip items. */

        // Enables and disables the ContextMenuStrip items on opening,
        // accroding the items' state in the edit menu.
        private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            if (undoToolStripMenuItem.Enabled == true)
            {
                richTextBox1.ContextMenuStrip.Items[0].Enabled = true;
            }
            else
            {
                richTextBox1.ContextMenuStrip.Items[0].Enabled = false;
            }
            if (redoToolStripMenuItem.Enabled == true)
            {
                richTextBox1.ContextMenuStrip.Items[1].Enabled = true;
            }
            else
            {
                richTextBox1.ContextMenuStrip.Items[1].Enabled = false;
            }
            if (cutToolStripMenuItem.Enabled == true)
            {
                richTextBox1.ContextMenuStrip.Items[3].Enabled = true;
            }
            else
            {
                richTextBox1.ContextMenuStrip.Items[3].Enabled = false;
            }
            if (copyToolStripMenuItem.Enabled == true)
            {
                richTextBox1.ContextMenuStrip.Items[4].Enabled = true;
            }
            else
            {
                richTextBox1.ContextMenuStrip.Items[4].Enabled = false;
            }
            if (pasteToolStripMenuItem.Enabled == true)
            {
                richTextBox1.ContextMenuStrip.Items[5].Enabled = true;
            }
            else
            {
                richTextBox1.ContextMenuStrip.Items[5].Enabled = false;
            }
            if (deleteToolStripMenuItem.Enabled == true)
            {
                richTextBox1.ContextMenuStrip.Items[6].Enabled = true;
            }
            else
            {
                richTextBox1.ContextMenuStrip.Items[6].Enabled = false;
            }
            if (selectAllToolStripMenuItem.Enabled == true)
            {
                richTextBox1.ContextMenuStrip.Items[8].Enabled = true;
            }
            else
            {
                richTextBox1.ContextMenuStrip.Items[8].Enabled = false;
            }
        }

        // When a Document is activated, the edit menu is updated
        // according the active Document state,
        // and the Document takes ownership of the tool windows.
        private void Document_Activated(object sender, EventArgs e)
        {
            MonitorEditMenu();
            FixLineNumbers();
            RenewToolWindows();
            ((Main)(this.MdiParent)).FindReplaceWindow.Owner = this;
            ((Main)(this.MdiParent)).JumpToLineWindow.Owner = this;
        }
    }
}&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-434622186073563937?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/434622186073563937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/10/vbscript-editor-c_183.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/434622186073563937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/434622186073563937'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/10/vbscript-editor-c_183.html' title='VBScript Editor [C#]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_CjLw9oSooQ0/SsnhW1REaMI/AAAAAAAAAA4/3VEAByAeLZE/s72-c/vbscript_editor-screenshot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-1656009896172830709</id><published>2009-09-16T21:24:00.015+03:00</published><updated>2009-10-03T11:29:54.098+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='InDesign'/><title type='text'>Auto Links Rename [InDesign JavaScript]</title><content type='html'>&lt;p&gt;Here's my recipe for links renaming in Adobe InDesign.&lt;br&gt;The following script will rename all linked images in the defined page-sequence, with a padded page number and the user entered prefix. For pages featuring more than one image a letter counter is added, seperated by an underscore.&lt;/p&gt;&lt;p&gt;Page numbers are padded according to the total number of pages in the document. The prefix is checked not to contain any digits or space characters. If the letter counter passes the letter 'z' it resolves to continue with numbers.&lt;/p&gt;&lt;p&gt;The script was written for version CS4, but I assume it should also work on CS3.&lt;/p&gt;

&lt;a href="http://1.bp.blogspot.com/_CjLw9oSooQ0/SrE4zLNFnUI/AAAAAAAAAAU/X4py8DiQuUo/s1600-h/auto_links_rename-screenshot.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 400px; height: 209px;" src="http://1.bp.blogspot.com/_CjLw9oSooQ0/SrE4zLNFnUI/AAAAAAAAAAU/X4py8DiQuUo/s400/auto_links_rename-screenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5382145481516621122" /&gt;&lt;/a&gt;

&lt;p&gt;&lt;/p&gt;

&lt;textarea rows="28" cols="48" Wrap=Off&gt;// Auto Links Rename
// (c) by Oren Hadar, 2009

var docPages = app.activeDocument.pages;

myDisplayDialog()

function myDisplayDialog(){
 var myDialog = app.dialogs.add({name:"Auto Links Rename"}); 
  with(myDialog.dialogColumns.add()){
   with(dialogRows.add()){ 
    staticTexts.add({staticLabel:"Prefix:"}); 
    var linkPrefixField = textEditboxes.add({editContents:"", minWidth:96}); 
   }
   with(dialogRows.add()){ 
    staticTexts.add({staticLabel:"Pages"}); 
   }
   with(borderPanels.add()){
    with(dialogColumns.add()){
     with(dialogRows.add()){ 
      staticTexts.add({staticLabel:"From:", minWidth:32}); 
      var fromPageField = integerEditboxes.add({editValue:1, minWidth:64}); 
     }
     with(dialogColumns.add()){
      with(dialogRows.add()){ 
       staticTexts.add({staticLabel:"To:", minWidth:32}); 
       var toPageField = integerEditboxes.add({editValue:docPages.length, minWidth:64}); 
      } 
     }
    }
   }
  }
 var myResult = myDialog.show(); 
 if(myResult == true){
 var linkPrefix = linkPrefixField.editContents; 
 var fromPage = --fromPageField.editValue;
 var toPage = --toPageField.editValue;
  try{
   if((fromPage &gt; docPages.length) || (toPage &gt; docPages.length)){
    throw "Err1";
   }
   else if(fromPage &gt; toPage){
    throw "Err2";
   }
   else if((linkPrefix. search(/\s/)!= -1) || (linkPrefix.search(/\d/) != -1) || (linkPrefix == "")){
    throw "Err3";
   }
  }
  catch(er){
   if(er=="Err1"){
    myDialog.destroy();
    alert("Error!\n\nThe entered page numbers must not exceed the number of pages in the document.");
   }
   if(er=="Err2"){
    myDialog.destroy();
    alert("Error!\n\nThe 'From' page number exceeds the 'To' page number.");
   }
   if(er=="Err3"){
    myDialog.destroy();
    alert("Error!\n\nThe entered prefix contains digits or space characters, or no prefix was entered.");
   }
  }
  finally{
   myDialog.destroy();
   AutoLinksRename(linkPrefix, fromPage, toPage);
   alert("Done!");
  }
 }
 else{
  myDialog.destroy(); 
  alert("Cancelled.");
 }
}

function AutoLinksRename(linkPrefix, fromPage, toPage){
 for (var p = fromPage; p &lt;= toPage; p++){
  var pageImages = docPages[p].allGraphics;
  var imageCounter = 0;
  var letterCounter = 0;
  for (var i = pageImages.length-1 ; i &gt;= 0 ; i--){
   imageCounter++;
   letterCounter++;
   var myLink = pageImages[i].itemLink;
   var myLinkExtension = myLink.name.substr(myLink.name.lastIndexOf( "." ));
   var myFile = new File(myLink.filePath);
   if (pageImages.length == 1){
    var myNewLinkName = linkPrefix + PadPage(docPages[p].name) + myLinkExtension;
   }
   else{
    var myNewLinkName = linkPrefix + PadPage(docPages[p].name) + "_" + GetLetter(letterCounter) + myLinkExtension;
   }
   if (myNewLinkName !=  myLink.name){
    if (myFile.exists){
     myFile.rename(myNewLinkName);
     myLink.relink(myFile);
     myLink.update();
    }
   }
  }
 }
}

function PadPage(myPage){
 var toPad = String(docPages.length).length - String(myPage).length;
 var paddedPage = String(myPage);
 for(var i = 0; i &lt; toPad ; i++){
  paddedPage = "0" + paddedPage;
 }
 return paddedPage;
}

function GetLetter(myNumber){
 if (myNumber &lt;= 26){
  return String.fromCharCode(96 + myNumber);
 }
 else{
  return myNumber;
 }
}&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-1656009896172830709?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/1656009896172830709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/09/auto-links-rename-indesign-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/1656009896172830709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/1656009896172830709'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/09/auto-links-rename-indesign-javascript.html' title='Auto Links Rename [InDesign JavaScript]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_CjLw9oSooQ0/SrE4zLNFnUI/AAAAAAAAAAU/X4py8DiQuUo/s72-c/auto_links_rename-screenshot.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-8492760162614896169</id><published>2009-07-22T22:53:00.009+03:00</published><updated>2009-10-03T14:05:07.487+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VBScript'/><category scheme='http://www.blogger.com/atom/ns#' term='T-SQL'/><title type='text'>Search and Log using SQL</title><content type='html'>&lt;p&gt;Good evening. The following is an SQL-based version of the &lt;a href = "http://oren-folder.blogspot.com/2009/07/search-and-log-vbscript.html"&gt;Search and Log&lt;/a&gt; script.&lt;/p&gt;
&lt;p&gt;Here the search is done with the '.Global' parameter turned to false, and so the SQL also takes care of finding the number of instances per file. The logging starts after the search is done, and non-matching folders aren't listed.&lt;/p&gt;
&lt;p&gt;SQL usage details: The script creates a temporary table called 'search_log'. My default database is the Northwind sample database, and the connection string is suited to windows authentication mode.&lt;/p&gt;
&lt;textarea rows="28" cols="48" Wrap=Off&gt;' Search and Log using SQL
' (c) Oren Hadar, 2009

Option Explicit

Dim fso, wshell, f, mainFolder, mySearch, sfInclude, logFileName, logFile, _
cnn, rs, fc, f1, fileSearched, fileMatch, sfc, sf1, _
i, rs2, i2, most

Sub Define

Set fso = CreateObject("Scripting.FileSystemObject")
Set wshell = createobject("wscript.shell")

On Error Resume Next
Set f = fso.GetFolder(InputBox("Enter subfolder or full path:", , wshell.currentdirectory))
If f = False Then 
MsgBox "The entered path does not exist, " _
&amp; "or Cancel was pressed.", vbExclamation
WScript.Quit
End If

mainFolder = f

Set mySearch = New RegExp
With mySearch
  .Pattern = InputBox("Enter search string:")
  .Global = False
  .IgnoreCase = True
End With

If f.subfolders.Count &gt; 0 Then
sfInclude = MsgBox("Include SubFolders?", vbYesNo)
End If

logFileName = "~" &amp; f.name &amp; " - find '" &amp; mySearch.Pattern &amp; "'.tmp"
Set logFile = fso.CreateTextFile(logFileName , True)

logFile.Write("Searching for '" &amp; mySearch.Pattern &amp; "' in " &amp; Chr(34) &amp; mainFolder &amp; Chr(34))
If sfInclude = vbYes Then logFile.Write(" and its' subfolders")
logFile.Write(":" &amp; vbCrLf &amp; vbCrLf)

Set cnn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")

cnn.ConnectionString = "driver={SQL Server};" &amp; _
"server=USER-PC\SQLEXPRESS;database=Northwind;Trusted_Connection=Yes"
cnn.Open

cnn.Execute("Create Table search_log (Path varchar(255), " _
&amp; "FileName varchar(255), Instances Int, FileType varchar(255))")

End Sub

Sub Search

Set fc = f.Files
For Each f1 in fc
If mySearch.Execute(f1.name).Count =&gt; 1 Then
cnn.Execute("Insert Into search_log (Path, FileName, FileType) " _
&amp; "Values ('" &amp; Replace(Replace(f1.ParentFolder, mainFolder, ".."), "'", "_") _
&amp; "\', '" &amp; Replace(f1.name, "'", "_") &amp; "', '" &amp; Replace(f1.type, "'", "_") &amp; "')") 
End If
Next

If sfInclude = vbYes Then
Set sfc = f.Subfolders
For Each sf1 In sfc
 Set f = fso.GetFolder(sf1)
 Call Search
Next
End If

End Sub

Sub Log

If cnn.Execute("Select Count(*) From search_log")(0) = 0 Then
logFile.Write(vbCrLf &amp; "No matches were found.")
Exit Sub
End If

cnn.Execute("Update search_log Set Instances = " _
&amp; "(LEN(FileName) - LEN(REPLACE(FileName, '" &amp; mySearch.Pattern &amp; "', ''))) " _
&amp; " / LEN('" &amp; mySearch.Pattern &amp; "')")

Set rs = cnn.Execute("Select Path, Count(FileName), Sum(Instances) From search_log Group By Path")
rs.MoveFirst

For i = 1 To cnn.Execute("Select Count(Distinct Path) From search_log")(0)
logFile.Write(vbCrLf &amp; vbCrLf &amp; rs(0) &amp; "  [" &amp; rs(2) &amp; " instance")
If rs(2) &gt; 1 Then logFile.Write("s")
logFile.Write(" in " &amp; rs(1) &amp; " file")
If rs(1) &gt; 1 Then logFile.Write("s")
logFile.Write("]" &amp; vbCrLf)

Set rs2 = cnn.Execute("Select FileName, Instances From search_log Where Path = '" _
&amp; rs(0) &amp; "'")
rs2.MoveFirst

For i2 = 1 To cnn.Execute("Select Count(*) From search_log Where Path = '" _
&amp; rs(0) &amp; "'")(0)
logFile.Write(rs2(0) &amp; "  [" &amp; rs2(1) &amp; " instance")
If rs2(1) &gt; 1 Then logFile.Write("s")
logFile.Write("]" &amp; vbCrLF)
rs2.MoveNext
Next

rs.MoveNext
Next

rs.Close
rs2.Close

End Sub

Sub Summary

logFile.Write(vbCrLf &amp; vbCrLf &amp; vbCrLf &amp; "* * * * * * * *" _
&amp; vbCrLf &amp; "Search Summary" &amp; vbCrLf _
&amp; "* * * * * * * *" &amp; vbCrLf &amp; vbCrLf &amp; vbCrLf)

logFile.Write(cnn.Execute("Select SUM(Instances) From search_log")(0) _
&amp; " instances of '" &amp; mySearch.Pattern &amp; "' were found in " _
&amp; cnn.Execute("Select Count(FileName) From search_log")(0) &amp; " files, inside " _
&amp; cnn.Execute("Select Count(Distinct Path) From search_log")(0) &amp; " folders." _
&amp; vbCrLf &amp; vbCrLf &amp; vbCrLf &amp; vbCrLf)

Set rs = cnn.Execute("Select Path, Count(FileName), SUM(Instances) From search_log " _
&amp; "Group by Path Order by Count(FileName) DESC")
rs.MoveFirst
most = rs(1)

logFile.Write("Folder(s) with most matching files  [" &amp; most &amp; " files]" &amp; vbCrLf)

Do
logFile.Write(rs(0) &amp; "  [" &amp; rs(2) &amp; " instances]" &amp; vbCrLf)
On Error Resume Next
rs.MoveNext
Loop While rs(1) = most

rs.Close

logFile.Write(vbCrLf &amp; vbCrLf &amp; vbCrLF)

Set rs = cnn.Execute("Select Path, SUM(Instances), Count(FileName) From search_log " _
&amp; "Group by Path Order by SUM(Instances) DESC")
rs.MoveFirst
most = rs(1)

logFile.Write("Folder(s) with most instances  [" &amp; most &amp; " instances]" &amp; vbCrLf)

Do
logFile.Write(rs(0) &amp; "  [" &amp; rs(2) &amp; " files]" &amp; vbCrLf)
On Error Resume Next
rs.MoveNext
Loop While rs(1) = most

rs.Close

logFile.Write(vbCrLf &amp; vbCrLf &amp; vbCrLF)

Set rs = cnn.Execute("Select FileType, Count(FileName) From search_log " _
&amp; "Group by FileType Order by Count(FileName) DESC")
rs.MoveFirst

logFile.Write("The matching files are of the following " _
&amp; cnn.Execute("Select Count(Distinct FileType) From search_log")(0) _
&amp; " file types, in descending order:" &amp; vbCrLf)

Do
logFile.Write(rs(0) &amp; "  [" &amp; rs(1) &amp; " files]" &amp; vbCrLf)
On Error Resume Next
rs.MoveNext
Loop While rs(1) &gt; 0

End Sub

Call Define
Call Search
Call Log
If sfInclude = vbYes And _
cnn.Execute("Select Count(*) From search_log")(0) &gt; 0 Then Call Summary

cnn.Execute("Drop Table search_log")
cnn.Close
logFile.Close
fso.MoveFile logFileName, Mid(Replace(logFileName,".tmp" , ".log"), 2)&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-8492760162614896169?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/8492760162614896169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/07/search-and-log-using-sql.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/8492760162614896169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/8492760162614896169'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/07/search-and-log-using-sql.html' title='Search and Log using SQL'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-5826642815607980815</id><published>2009-07-18T17:42:00.005+03:00</published><updated>2009-10-03T14:10:47.023+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VBScript'/><title type='text'>Search and Log [VBScript]</title><content type='html'>&lt;p&gt;Greetings. I wrote a script that Searches for a string in file names and Logs the results in a text file. It has the following neat features:&lt;/p&gt;
&lt;p&gt;* Search results refer also to the number of instances the searched string appears in the file name.&lt;/p&gt;
&lt;p&gt;* While the process is running, search data is written to a ~.tmp file, and on successful completion the file is renamed to .log.&lt;br&gt;File names summarize the target of the search, and cannot be overridden.&lt;/p&gt;
&lt;p&gt;* If the selected folder for search contains subfolders, the user is prompted to include them in the search. By calling the search sub procedure from itself, the search drills down into deepest subfolders.&lt;/p&gt;
&lt;p&gt;* For searches that include subfolders, a short summary of the search results is featured in the end of the log file, including a list of the file types for the matching files, in descending order.&lt;/p&gt;
&lt;textarea rows="28" cols="48" Wrap=Off&gt;' Search and Log
' (c) Oren Hadar, 2009

Option Explicit

Dim fso, f, wshell, mainFolder, mySearch, logFile, sfInclude, logFileName, _ 
f1, fc, fileSearched, fileMatch, filesInstances, totalInstances, filesMatching, _
filesTable(), fileId, foldersTable(), folderId, sf1, sfc, _
genI, topX, TopXId, genNestedI, groupTable, groupId, groupExists, _
groupOrderedTable, groupOrderedTableId, tempTopGroup

Sub Define

Set fso = CreateObject("Scripting.FileSystemObject")
Set wshell = createobject("wscript.shell")

On Error Resume Next
Set f = fso.GetFolder(InputBox("Enter subfolder or full path:", , wshell.currentdirectory))
If f = False Then 
MsgBox "The entered path does not exist, " _
&amp; "or Cancel was pressed.", vbExclamation
WScript.Quit
End If

mainFolder = f

Set mySearch = New RegExp
With mySearch
  .Pattern = InputBox("Enter search string:")
  .Global = True
  .IgnoreCase = True
End With

If f.subfolders.Count &gt; 0 Then
sfInclude = MsgBox("Include SubFolders?", vbYesNo)
End If

logFileName = "~" &amp; f.name &amp; " - find '" &amp; mySearch.Pattern &amp; "'.tmp"
Set logFile = fso.CreateTextFile(logFileName , True)

logFile.Write("Searching for '" &amp; mySearch.Pattern &amp; "' in " &amp; Chr(34) &amp; mainFolder &amp; Chr(34))
If sfInclude = vbYes Then logFile.Write(" and its' subfolders")
logFile.Write(":" &amp; vbCrLf &amp; vbCrLf)

End Sub

Sub Search

filesInstances = Empty
filesMatching = Empty

If f &lt;&gt; mainFolder Then logFile.Write(".." _
&amp; Replace(f, mainFolder, "") &amp; "\" &amp; vbCrLf)

Set fc = f.Files
For Each f1 in fc
 Set fileSearched = mySearch.Execute(f1.name)
 For Each fileMatch in fileSearched  
  filesInstances = filesInstances + 1
  totalInstances = totalInstances + 1
 Next
If fileSearched.Count &gt; 0 Then
logFile.Write(f1.name &amp; "  [" &amp; fileSearched.Count &amp; " instances]" &amp; vbCrLf)
ReDim Preserve filesTable(2, fileId)
filesTable(0, fileId) = f1
filesTable(1, fileId) = fileSearched.Count
filesTable(2, fileId) = f1.type
filesMatching = filesMatching + 1
fileId = fileId + 1
End If
Next

If filesInstances &gt; 0 Then
ReDim Preserve foldersTable(2, folderId)
foldersTable(0, folderId) = f
foldersTable(1, folderId) = filesMatching
foldersTable(2, folderId) = filesInstances
folderId = folderId + 1
End If

Select Case filesInstances
Case 0
logFile.Write("No matches were found")
If f = mainFolder And sfInclude = vbYes Then logFile.Write(" in the main folder")
logFile.Write("." &amp; vbCrLf &amp; vbCrLf &amp; vbCrLf)
Case 1
logFile.Write("[1 instance in 1 file]" &amp; vbCrLf &amp; vbCrLf &amp; vbCrLf)
Case Else
logFile.Write("[" &amp; filesInstances &amp; " instances in " &amp; filesMatching _
&amp; " files]" &amp; vbCrLf &amp; vbCrLf &amp; vbCrLf)
End Select

If sfInclude = vbYes Then
Set sfc = f.Subfolders
For Each sf1 In sfc
 Set f = fso.GetFolder(sf1)
 Call Search
Next
End If

End Sub

Sub Summary

logFile.Write("* * * * * * * *" &amp; vbCrLf _
&amp; "Search Summary" &amp; vbCrLf _
&amp; "* * * * * * * *" &amp; vbCrLf &amp; vbCrLf &amp; vbCrLf)

If totalInstances = 0 Then 
logFile.Write("No instances of '" &amp; mySearch.Pattern &amp; "' were found.")
Exit Sub
End If

logFile.Write(totalInstances &amp; " instances of '" &amp; mySearch.Pattern _
&amp; "' were found in " &amp; fileId &amp; " files, inside " &amp; folderId &amp; " folders." _
&amp; vbCrLf &amp; vbCrLf &amp; vbCrLf &amp; vbCrLf)



Call ResVar

For genI = 0 To folderId - 1
If foldersTable(1, genI) &gt; foldersTable(1, topX(0)) Then
 ReDim topX(0)
 topX(0) = genI
ElseIf foldersTable(1, genI) = foldersTable(1, topX(0)) And _
foldersTable(0, genI) &lt;&gt; foldersTable(0, topX(0)) Then
 topXId = topXId + 1
 ReDim Preserve topX(topXId)
 topX(topXId)=genI
End If
Next

If topXId = 1 Then topXId = 0

LogFile.Write("Folder(s) with most matching files [" _
&amp; foldersTable(1, topX(0)) &amp; " files]:" &amp; vbCrLf)

For genI=0 To topXId
logFile.Write(foldersTable(0, topX(genI)) &amp; "  [" &amp; foldersTable(2, topX(genI)) _
&amp; " instances]" &amp; vbCrLf)
Next

logFile.Write(vbCrLf &amp; vbCrLf &amp; vbCrLf)

Call ResVar

For genI = 0 To folderId - 1
If foldersTable(2, genI) &gt; foldersTable(2, topX(0)) Then
 ReDim topX(0)
 topX(0) = genI
ElseIf foldersTable(2, genI) = foldersTable(2, topX(0)) And _
foldersTable(0, genI) &lt;&gt; foldersTable(0, topX(0)) Then
 topXId = topXId + 1
 ReDim Preserve topX(topXId)
 topX(topXId)=genI
End If
Next

LogFile.Write("Folder(s) with most instances [" _
&amp; foldersTable(2, topX(0)) &amp; " instances]:" &amp; vbCrLf)


If topXId = 1 Then topXId = 0

For genI=0 To topXId
logFile.Write(foldersTable(0, topX(genI)) &amp; "  [" &amp; foldersTable(1, topX(genI)) _
&amp; " files]" &amp; vbCrLf)
Next

logFile.Write(vbCrLf &amp; vbCrLf &amp; vbCrLf)

Call ResVar

For genI = 0 To fileId - 1
 groupExists = False
 For genNestedI = 0 To groupId
  If filesTable(2, genI) = groupTable(0, genNestedI) Then
  groupExists = True
  groupTable(1, genNestedI) = groupTable(1, genNestedI) + 1
  End If
 Next
 If groupExists = False Then
 groupId = groupId + 1
 ReDim Preserve groupTable(1, groupId)
 groupTable(0, groupId) = filesTable(2, genI)
 groupTable(1, groupId) = 1
 End If
Next

ReDim groupOrderedTable(1, groupId)

For genI = 0 To groupId
 For genNestedI = 0 To groupId
 If groupTable(1, genNestedI) &gt; groupOrderedTable(1, genI) Then
 groupOrderedTable(0, genI) =  groupTable(0, genNestedI)
 groupOrderedTable(1, genI) =  groupTable(1, genNestedI)
 tempTopGroup = genNestedI
 End If
 Next
groupTable(1, tempTopGroup) = 0
Next

logFile.Write("The matching files are of the following " _
&amp; groupId &amp; " file types, in descending order:" &amp; vbCrLf)

For genI = 0 To groupId - 1
logFile.Write(groupOrderedTable(0, genI) &amp; "  [" &amp; groupOrderedTable(1, genI) &amp; " files]" &amp; vbCrLf)
Next

End Sub

Sub ResVar

ReDim topX(0)
topX(0) = 0
topXId = 0

ReDim groupTable(1, 0)
groupTable(0, 0) = "No File Type"
groupTable(1, 0) = 0
groupId = Empty

End Sub

Call Define
Call Search
If sfInclude = vbYes Then Call Summary

logFile.Close
fso.MoveFile logFileName, Mid(Replace(logFileName,".tmp" , ".log"), 2)&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-5826642815607980815?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/5826642815607980815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/07/search-and-log-vbscript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/5826642815607980815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/5826642815607980815'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/07/search-and-log-vbscript.html' title='Search and Log [VBScript]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-2310670725020790427</id><published>2009-07-04T17:04:00.004+03:00</published><updated>2009-10-03T14:22:00.296+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VBScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Word'/><title type='text'>Convert Footnotes to Regular Text [Word VBScript]</title><content type='html'>&lt;p&gt;The next script for Word converts all footnotes and their references to regular text. The footnotes are inserted at the end of the document.&lt;/p&gt;
&lt;textarea rows="28" cols="48" Wrap=Off&gt;Sub convert_footnotes()

' Convert Footnotes to Regular Text
' (c) Oren Hadar, 2009

Dim fn_total
Dim fn_number
Dim fn_ref

fn_total = ActiveDocument.Footnotes.Count

ActiveDocument.Content.InsertAfter vbCrLf &amp; vbCrLf &amp; "Notes" &amp; vbCrLf

For fn_number = 1 To fn_total
    ActiveDocument.Footnotes(fn_number).Range.Copy
    ActiveDocument.Content.InsertAfter fn_number &amp; vbTab
    Set my_range = ActiveDocument.Content
    my_range.Collapse Direction:=wdCollapseEnd
    my_range.Paste
    ActiveDocument.Content.InsertAfter vbCrLf
Next

For fn_ref = 1 To fn_total
    ActiveDocument.Footnotes(1).Reference.Select
    Selection.Text = fn_ref
    With Selection.Font
        .Superscript = True
    End With
Next

End Sub
&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-2310670725020790427?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/2310670725020790427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/07/convert-footnotes-to-regular-text-word.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/2310670725020790427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/2310670725020790427'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/07/convert-footnotes-to-regular-text-word.html' title='Convert Footnotes to Regular Text [Word VBScript]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-5332531690633578331</id><published>2009-07-04T16:46:00.008+03:00</published><updated>2009-10-03T14:23:31.118+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VBScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Word'/><title type='text'>Find, Replace and Comment [Word VBScript]</title><content type='html'>&lt;p&gt;Hi there. I wrote a Find and Replace script for Word, which also adds a Comment for each replacement. Note: It works only on the 'body' of the text, since comments are not available on footnotes / endnotes.&lt;/p&gt;
&lt;textarea rows="28" cols="48" Wrap=Off&gt;Sub find_comment()

' Find, Replace and Comment
' (c) Oren Hadar, 2009

Dim myFind
Dim myReplace
Dim okInput
Dim myCount
Dim myContinue
Dim myRetry

myCount = 0
okInput = False

Do
myFind = InputBox("Find what:", "Find and Comment")
If StrPtr(myFind) = False Then
Exit Sub
ElseIf myFind = "" Then
myRetry = MsgBox("No find string was entered.", _
vbRetryCancel + vbExclamation, "Find and Comment")
Else
okInput = True
End If
If myRetry = vbCancel Then
Exit Sub
End If
Loop While okInput = False

okInput = False

Do
myReplace = InputBox("Replace with:", "Find and Comment")
If StrPtr(myReplace) = False Then
Exit Sub
ElseIf myReplace = "" Then
myRetry = MsgBox("No replacement string was entered." _
&amp; vbCrLf &amp; "The searched string will be deleted!" &amp; vbCrLf _
&amp; "Are you sure?", vbYesNoCancel + vbDefaultButton2 + _
vbExclamation, "Find and Comment")
ElseIf myReplace = myFind Then
myRetry = MsgBox("The replacement string must be different " &amp; vbCrLf _
&amp; "from the searched string.", vbRetryCancel + vbCritical, "Find and Comment")
Else
okInput = True
End If
If myRetry = vbYes Then
okInput = True
ElseIf myRetry = vbCancel Then
Exit Sub
End If
Loop While okInput = False

Do
With Selection.find
    .Forward = True
    .ClearFormatting
    .MatchWholeWord = False
    .MatchCase = False
    .Wrap = wdFindContinue
    .Execute FindText:=myFind
End With
If Selection.Text = myFind Then
Selection.Text = myReplace
myContinue = True
myCount = myCount + 1
ActiveDocument.Comments.Add Range:=Selection.Range, Text:="Replaces " &amp; myFind
Else
myContinue = False
End If
Loop Until myContinue = False
    
MsgBox myCount &amp; " instances of '" &amp; myFind _
&amp; "' were found, replaced with '" &amp; myReplace &amp; _
"' and commented.", , "Find and Comment"

End Sub&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-5332531690633578331?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/5332531690633578331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/07/find-replace-and-comment-word-vbscript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/5332531690633578331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/5332531690633578331'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/07/find-replace-and-comment-word-vbscript.html' title='Find, Replace and Comment [Word VBScript]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2074310494330781844.post-813083730995763685</id><published>2009-06-28T21:28:00.010+03:00</published><updated>2009-10-03T14:48:54.081+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='T-SQL'/><title type='text'>Multi-Rectangle \ Spiral [T-SQL]</title><content type='html'>&lt;p&gt;I wrote a script which draws multiple rectangle-inside-rectangle in T-SQL. The number of rectangles to be drawn can be set ... to a certain extent ;)&lt;/p&gt;
&lt;p&gt;A change of a parameter at the end of the script produces a spiral.&lt;/p&gt;
&lt;textarea rows="28" cols="48" Wrap=Off&gt;-- Multi-Rectangle \ Spiral
-- by Oren Hadar, 2009

DECLARE @total INT
DECLARE @count INT
DECLARE @horiz INT
DECLARE @vert INT
DECLARE @max_vert INT
DECLARE @h_draw varchar(128)
DECLARE @v_draw varchar(128)
SET @total = 7
-- @total sets to number of rectangles
SET @count = @total
SET @max_vert = @total * 3
SET @horiz = @total*6-3
SET @vert = @total * 3 - 1
SET @h_draw = '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
SET @v_draw = '+  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +'
WHILE @vert &gt; -@total * 3 - 3
BEGIN
PRINT LEFT(@v_draw, @max_vert-ABS(@vert)) 
  + SUBSTRING(@h_draw, 1, ABS(@horiz))
  + RIGHT(@v_draw, @max_vert-ABS(@vert))
PRINT LEFT(@v_draw, @max_vert-ABS(@vert)) 
  + REPLACE(SUBSTRING(@h_draw, 1, ABS(@horiz)), '+', ' ') 
  + RIGHT(@v_draw, @max_vert-ABS(@vert))
SELECT @horiz = @horiz - 6
SELECT @vert = @vert - 3
SELECT @count = @count-1
 IF @count=0
 BEGIN
-- In the next line, change the '-2' to '+1' to get a spiral!
 SELECT @horiz=@horiz-2
 SELECT @vert=@vert-2
 END
END&lt;/textarea&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2074310494330781844-813083730995763685?l=oren-folder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://oren-folder.blogspot.com/feeds/813083730995763685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://oren-folder.blogspot.com/2009/06/multi-rectangle-using-absolute-values-t_28.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/813083730995763685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2074310494330781844/posts/default/813083730995763685'/><link rel='alternate' type='text/html' href='http://oren-folder.blogspot.com/2009/06/multi-rectangle-using-absolute-values-t_28.html' title='Multi-Rectangle \ Spiral [T-SQL]'/><author><name>Oren Hadar</name><uri>http://www.blogger.com/profile/04168032872930019533</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
