Click here to Skip to main content
15,887,962 members
Articles / Programming Languages / C#

Three Zone World Clock

Rate me:
Please Sign up or sign in to vote.
4.33/5 (9 votes)
3 Mar 20052 min read 83.6K   1.4K   43  
A three time zone world clock
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;
using System.Drawing;
using System.Text;
using System.IO;
using System;

namespace ClockDemo
{
	/// <summary>
	/// Summary description for ClocksForm.
	/// </summary>
	public class ClocksForm : Form
	{
		private Clock[] m_clocks = new Clock[3];
		private Timer timer;
		private IContainer components;
		private bool m_saved = false;

		Point mouseOffset ;
		bool isMouseDown ;
		AppSettings m_appSettings = new AppSettings(true);
		
		/// <summary>
		/// The main form containing all the clocks
		/// </summary>
		public ClocksForm()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			//Load the application settings
			LoadAppSettings();

			//Check that bitmaps exist and create some if not
			EnsureBitmapsExist();

			//Add context menu
			AddContextmenu();

			//Set up the background
			NewBackgroundSelected(m_appSettings.SkinFile, true);

			//Set up the clocks
			CreateClocks();

			this.MouseDown+=new MouseEventHandler(ClocksForm_MouseDown);
			this.MouseUp+=new MouseEventHandler(ClocksForm_MouseUp);
			this.MouseMove+=new MouseEventHandler(ClocksForm_MouseMove);

			timer.Tick +=new EventHandler(timer_Tick);
			timer.Enabled = true;
			timer.Interval = 10000; //update the clocks every 10 seconds
			timer.Start();
		}


		/// <summary>
		/// Create the clocks
		/// </summary>
		private void CreateClocks()
		{
			int clockWidth  = (Width - 80) / 3;
			int clockOffset = (Width - (clockWidth * 3))/4;

			Point location = new Point(clockOffset + 40, 75);

			for(int clockCount = 0; clockCount < m_clocks.Length; clockCount++)
			{
				double plusHours = m_appSettings.ClockSettings[clockCount].HoursPlus;
				plusHours += m_appSettings.ClockSettings[clockCount].MinsPlus / 60.0;

				//Create and set up a new clock
				Clock newClock = new Clock();
				newClock.Location = location;
				newClock.LocalPlusHours = plusHours;
				newClock.Size = new Size(clockWidth, this.Height);
				newClock.ScaleToFit(newClock.Size);
				newClock.Text = m_appSettings.ClockSettings[clockCount].Name;
				m_clocks[clockCount] = newClock;

				//Move the location for the next clock to the right
				location.Offset(clockWidth + clockOffset,0);
			}
		}

		/// <summary>
		/// Load the application settings from xml file
		/// </summary>
		private void LoadAppSettings()
		{
			string appPath = Path.GetDirectoryName(Application.ExecutablePath);
			string settingsPath = appPath + "\\settings.xml";
			if(File.Exists(settingsPath))
			{
				StreamReader reader = new StreamReader(settingsPath , Encoding.UTF8);
				m_appSettings = AppSettings.Load(reader.BaseStream);
				reader.Close();
				if(m_appSettings.SkinFile == "")
				{
					m_appSettings.SkinFile = "none";
				}
			}
		}


		/// <summary>
		/// This is called when a new skin (or no skin) is selected
		/// </summary>
		private void NewBackgroundSelected(string skinName, bool initialising)
		{
			m_appSettings.SkinFile = skinName;
			if(skinName != "none")
			{
				//Set skin
				FormBorderStyle = FormBorderStyle.None;		
				SetSkin(skinName,initialising);
			}
			else
			{
				//Set no skin
				FormBorderStyle = FormBorderStyle.FixedSingle;				
				MaximizeBox = false;
				BackgroundImage = null;
				Invalidate();
			}
		}


		/// <summary>
		/// Sets a new named skin from a bitmap file
		/// </summary>
		private void SetSkin(string skinName, bool initializing)
		{
			//Keep the new skin name in the application settings object
			m_appSettings.SkinFile = skinName;

			//Find the application directory and then the full skin path
			string appPath = Path.GetDirectoryName(Application.ExecutablePath);
			string skinPath = appPath + "\\" + skinName;

			//Load skin if it exists
			if(File.Exists(skinPath))
			{
				Bitmap skinBmp = (Bitmap)Bitmap.FromFile(skinPath);

				//Clear form background to prevent overlays
				if(!initializing)
				{
					Graphics g = this.CreateGraphics();
					g.Clear(Color.Black);
					g.Clear(TransparencyKey);
				}

				//Apply transparency to the bitmap
				skinBmp.MakeTransparent(skinBmp.GetPixel(1,1));

				//Set the background image of the form
				BackgroundImage = skinBmp;

				//Apply transparency to the Form
				TransparencyKey = skinBmp.GetPixel(1,1);

				//Get the form to refresh
				Invalidate();
			}
		}


		/// <summary>
		/// Add a context menu that lists available skins
		/// </summary>
		private void AddContextmenu()
		{
			//Enumerate skin files
			StringCollection fileNames = GetSkinFilesNames();

			ContextMenu contextMenu = new ContextMenu();
			MenuItem[]   menuItems = new MenuItem[fileNames.Count];

			int nameIndex = 0;
			foreach(string name in fileNames)
			{
				menuItems[nameIndex] = new MenuItem();
				menuItems[nameIndex].Text = name;
				menuItems[nameIndex].Click +=new EventHandler(menuItem_Click);
				nameIndex ++;
			}

			contextMenu.MenuItems.AddRange(menuItems); 
			this.ContextMenu = contextMenu; 
		}


		/// <summary>
		/// Checks to see if there are skin bitmaps in the application directory, and if not creates some
		/// from internal bitmap resources
		/// </summary>
		private void EnsureBitmapsExist()
		{
			StringCollection skinFiles = GetSkinFilesNames(); //Don't actually need the names, but just need to count them
			if(skinFiles.Count == 1) //The "none" option is the only one.
			{
				//Pull bitmaps out of the embedded resources and save to the application directory. That
				//way the user can alter them and add to them.
				ExtractAndSaveBitmap("balls.bmp");
				ExtractAndSaveBitmap("beach.bmp");
				ExtractAndSaveBitmap("chrome.bmp");
				ExtractAndSaveBitmap("lens.bmp");
				ExtractAndSaveBitmap("sky.bmp");
			}
		}

		/// <summary>
		/// Checks to see if there are skin bitmaps in the application directory, and if not creates some
		/// from internal bitmap resources
		/// </summary>
		private void ExtractAndSaveBitmap(string bmpName)
		{
			Bitmap bmp = LoadBitmap(bmpName);
			string bmpPath = Path.GetDirectoryName(Application.ExecutablePath);
			bmp.Save(bmpPath + "\\" + bmpName);
		}

		/// <summary>
		/// Loads a bitmap resource from the assembly
		/// </summary>
		/// <param name="name"></param>
		/// <returns></returns>
		private Bitmap LoadBitmap(string name)
		{
			name = "ClockDemo.Resources." + name; 
			Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
			if( s != null )
			{
				return new Bitmap(s);
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// Iterates through the application directory picking up skin (.bmp) files
		/// </summary>
		/// <returns></returns>
		private StringCollection GetSkinFilesNames()
		{
			StringCollection names = new StringCollection();
			names.Add("none");

			string dirToList = Path.GetDirectoryName(Application.ExecutablePath);
			DirectoryInfo dir = new DirectoryInfo( dirToList );

			foreach(FileSystemInfo fsi in dir.GetFileSystemInfos()) 
			{
				if (fsi is FileInfo)
				{
					FileInfo f = (FileInfo)fsi;
					String name = f.Name;
					if(name.IndexOf(".bmp") >= 0) 
					{
						names.Add(name);
					}
				}
			}
			return names;
		}


		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}


		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(ClocksForm));
			this.timer = new System.Windows.Forms.Timer(this.components);
			// 
			// timer
			// 
			this.timer.Interval = 1000;
			// 
			// ClocksForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.BackColor = System.Drawing.SystemColors.Control;
			this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
			this.ClientSize = new System.Drawing.Size(352, 137);
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
			this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
			this.Name = "ClocksForm";
			this.Text = "World Times";
			this.DoubleClick += new System.EventHandler(this.ClocksForm_DoubleClick);
			this.Closed += new System.EventHandler(this.ClocksForm_Closed);

		}

		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new ClocksForm());
		}


		/// <summary>
		/// Override OnPaint to paint the clocks
		/// </summary>
		/// <param name="e"></param>
		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint (e);
			for(int clockCounter = 0; clockCounter < m_clocks.Length; clockCounter++)
			{
				bool drawBorder = (m_appSettings.SkinFile == "none");
				m_clocks[clockCounter].Paint(e, drawBorder);
			}
		}

		/// <summary>
		/// Repaint the clocks with new time every timer interval
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void timer_Tick(object sender, EventArgs e)
		{
			//Refresh the Clock
			Invalidate();
		}


		/// <summary>
		/// Handle MouseDown
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ClocksForm_MouseDown(object sender, MouseEventArgs e)
		{
			int xOffset;
			int yOffset;

			if (e.Button == MouseButtons.Left) 
			{
				xOffset = -e.X;
				yOffset = -e.Y;
				mouseOffset = new Point(xOffset, yOffset);
				isMouseDown = true;
			}    
		}


		/// <summary>
		/// Handle MouseMove
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ClocksForm_MouseMove(object sender, MouseEventArgs e)
		{
			if (isMouseDown && m_appSettings.SkinFile != "none") 
			{
				Point mousePos = Control.MousePosition;
				mousePos.Offset(mouseOffset.X, mouseOffset.Y);
				Location = mousePos;
			}
		}

		/// <summary>
		/// Handle MouseUp
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ClocksForm_MouseUp(object sender, MouseEventArgs e)
		{
			isMouseDown = false;
		}

		/// <summary>
		/// Deal with double-click (Exit)
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ClocksForm_DoubleClick(object sender, EventArgs e)
		{
			if(!m_saved)
			{
				SaveSettings();
			}
			this.Close();
		}


		/// <summary>
		/// Save application settings
		/// </summary>
		private void SaveSettings()
		{
			string appPath = Path.GetDirectoryName(Application.ExecutablePath);
			m_appSettings.Save(appPath + "\\settings.xml");
			m_saved = true;
		}


		/// <summary>
		/// Deal with click on context menu
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void menuItem_Click(object sender, EventArgs e)
		{
			string fileName = (sender as MenuItem).Text;
			NewBackgroundSelected(fileName,false);
		}

		/// <summary>
		/// Save the settings when the form closes
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ClocksForm_Closed(object sender, System.EventArgs e)
		{
			if(!m_saved)
			{
				SaveSettings();
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions