using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using TradeIdeas.XML;
using TradeIdeas.TIProData;
using TradeIdeas.TIProData.Configuration;
using System.Threading;
using TradeIdeas.TIProGUI.CBT;
using System.Windows.Interop;
using System.Runtime.InteropServices;
namespace TIProDevExtension
{
///
/// Interaction logic for EarningsDate.xaml
///
///
public enum RangeOutput { Premarket, MarketHours, PostMarket }
public partial class EarningsDate : UserControl
{
//we need to tag the cells in the grid
//We'll "name" the cells from - 27 to + 27
//excluding any weekend cells as well as cells
//in the very first row (weekday title cells)
//we'll need this to start painting...
int _cellTagNumber = -27;
private IContainer _container;
private TIRanges tiRanges = new TIRanges();
//This list holds the references to all of the tagged cells(rectangles) in the grid
private List _refGrid = new List();
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
public EarningsDate()
{
InitializeComponent();
//set the grid lines by adding rectangles to each grid position. Each rectangle has a border,
//thus giving the appearance of a calendar grid.
for (int i = 0; i < calendarGrid.RowDefinitions.Count; i++)
{
for (int j = 0; j < calendarGrid.ColumnDefinitions.Count; j++)
{
Rectangle rect = new Rectangle();
rect.Stroke = Brushes.Silver; //border
if (i != 0 && j != 0 && j != 6)
{
rect.Tag = _cellTagNumber.ToString(); //using rect.Name = _cellTagNumber.ToString() throws exception
_refGrid.Add(rect);
_cellTagNumber++;
}
Grid.SetColumn(rect, j);
Grid.SetRow(rect, i);
calendarGrid.Children.Add(rect);
}
}
lblMin.Content = "0.00";
lblMax.Content = "0.00";
}
private BitmapSource ToWpfImage(System.Drawing.Bitmap img)
{
if (img == null)
return null;
lock (img)
{
IntPtr hBitmap = img.GetHbitmap();
try
{
//code snippet courtesy of: http://www.codeproject.com/Articles/104929/Bitmap-to-BitmapSource
BitmapSource bitmapSource =
Imaging.CreateBitmapSourceFromHBitmap(
img.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
return bitmapSource;
}
finally
{
DeleteObject(hBitmap);
}
}
}
public void setContainer(IContainer container) //this method is called from the WinForm constructor(ConfigWDemoEarningsDate.cs)
{
_container = container;
_container.MinTextBox.TextChanged += new EventHandler(MinTextBox_TextChanged);
_container.MaxTextBox.TextChanged += new EventHandler(MaxTextBox_TextChanged);
minPictureBox.Source = ToWpfImage(container.ConnectionMaster.ImageCacheManager.GetFilter("MinEarningD"));
maxPictureBox.Source = ToWpfImage(container.ConnectionMaster.ImageCacheManager.GetFilter("MaxEarningD"));
}
void MaxTextBox_TextChanged(object sender, EventArgs e)
{
updateTrackBar(maxSlider, _container.MaxValue);
updateCalendar();
}
void MinTextBox_TextChanged(object sender, EventArgs e)
{
updateTrackBar(minSlider, _container.MinValue);
updateCalendar();
}
private void minSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
{
lblMin.Content = String.Format("{0:0.00}", minSlider.Value); //for debugging...hidden on form
trackBarScroll(_container.MinTextBox, minSlider);
}
private void maxSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
{
lblMax.Content = String.Format("{0:0.00}", maxSlider.Value); //for debugging...hidden on form
trackBarScroll(_container.MaxTextBox, maxSlider);
}
///
/// From Phil:
/// This means that we are updating the min or max value. Normally,
/// when a user types in the text box, that changes the track bar, and
/// when the user changes the track bar, that changes the tex box.
/// This keeps us from an infinate loop. What's more, If a user enters
/// a number that does not perfectly match the track bar, the track
/// bar should update to the closest position, but the text box should
/// stay the same. If the user uses a slider, the text box will only
/// display one of a small number of possible values.
///
private bool _internalTrackBarChange = false;
public void trackBarScroll(System.Windows.Forms.TextBox textBox, Slider trackBar)
{
if (_internalTrackBarChange)
{ //a change already in progress
//changed the trackbar to match the text boxes
return;
}
_internalTrackBarChange = true;
textBox.Text = trackBar.Value.ToString();
_internalTrackBarChange = false;
}
private void updateTrackBar(Slider trackBar,double? value)
{
if (_internalTrackBarChange)
// A change is already in progress.
return;
_internalTrackBarChange = true;
if (null == value)
{
}
else
{
double rounded = Math.Round(value.Value);
if (rounded > trackBar.Maximum)
// This is higher than the highest value the track bar can represent.
// So set the track bar to its highest value.
trackBar.Value = trackBar.Maximum;
else if (rounded < trackBar.Minimum)
trackBar.Value = trackBar.Minimum;
else
trackBar.Value = (double)rounded;
}
_internalTrackBarChange = false;
}
private void drawRectangle(Rectangle rect, double a, double b, double c, double d, Color color)
{
LinearGradientBrush myBrush = new LinearGradientBrush();
myBrush.StartPoint = new Point(0.5, 0);
myBrush.EndPoint = new Point(0.5, 1);
myBrush.GradientStops.Add(new GradientStop(color, a));
myBrush.GradientStops.Add(new GradientStop(color, b));
myBrush.GradientStops.Add(new GradientStop(Colors.White, c));
myBrush.GradientStops.Add(new GradientStop(Colors.White, d));
rect.Fill = myBrush;
}
private void updateCalendar()
{
double? min = null;
double? max = null;
min = _container.MinValue;
max = _container.MaxValue;
// Do this just once each time the gui changes.
tiRanges.Min = min;
tiRanges.Max = max;
foreach (Rectangle rect in _refGrid)
{
//In this loop, we go through each of the cells that are tagged,
//then determine how/whether that cell should be painted.
int dayNumber = Convert.ToInt32(rect.Tag);
Color color = checkColor(dayNumber);
//Color color = Colors.Lime; //for testing purposes
HashSet selections = tiRanges.WhatToShow(dayNumber);
if (selections.Contains(RangeOutput.MarketHours) && selections.Contains(RangeOutput.Premarket) && selections.Contains(RangeOutput.PostMarket))
{
SolidColorBrush s = new SolidColorBrush(color);
rect.Fill = s;
}
else if (selections.Contains(RangeOutput.MarketHours) && selections.Contains(RangeOutput.Premarket))
{
drawRectangle(rect, 0.0, 0.60, 0.62, 1.0, color);
}
else if (selections.Contains(RangeOutput.MarketHours) && selections.Contains(RangeOutput.PostMarket))
{
drawRectangle(rect, 1.0, 0.34, 0.32, 0.0, color);
}
else if (selections.Contains(RangeOutput.Premarket))
{
drawRectangle(rect, 0, 0.32, 0.34, 1.0, color);
}
else if (selections.Contains(RangeOutput.PostMarket))
{
drawRectangle(rect, 1.0, 0.62, 0.60, 0, color);
}
else
rect.Fill = Brushes.Transparent;
}
}
public Color checkColor(int day)
{
if (_container.MaxValue >= _container.MinValue)
{
return Color.FromRgb(79, 96, 192);
}
if (_container.MinValue > _container.MaxValue )
{
if (day > _container.MaxValue)
{
return Color.FromRgb(158, 0, 192);
}
else if (day < _container.MinValue)
{
return Color.FromRgb(0, 192, 192);
}
}
if (_container.MinValue != null && _container.MaxValue == null)
{
return Color.FromRgb(0, 192, 192);
}
if (_container.MinValue == null && _container.MaxValue != null)
{
return Color.FromRgb(158, 0, 192);
}
return Colors.Transparent;
}
}
public class SimpleRange
{
private const double BIG_VALUE = 1000000;
private const double SMALL_VALUE = -BIG_VALUE;
public double Min;
public double Max;
public void NoMax()
{
Max = BIG_VALUE;
}
public void NoMin()
{
Min = SMALL_VALUE;
}
public bool Included(double value)
{
System.Diagnostics.Debug.Assert(Min <= Max);
return (value >= Min) && (value <= Max);
}
public SimpleRange()
{
NoMin();
NoMax();
}
}
public class TIRanges
{
private List _simpleRanges = new List();
private bool Included(double value)
{
// Included() for the whole set in the union of Included() for each item.
foreach (SimpleRange simpleRange in _simpleRanges)
{
if (simpleRange.Included(value))
return true;
}
return false;
}
private double? _min;
private double? _max;
public double? Min
{
get { return _min; }
set
{
_min = value;
Rebuild();
}
}
public double? Max
{
get { return _max; }
set
{
_max = value;
Rebuild();
}
}
public TIRanges()
{
Rebuild();
}
private void Rebuild()
{
_simpleRanges.Clear(); // Start fresh!
if ((!_min.HasValue) && (!_max.HasValue))
{ // No filters -- Everything is included.
_simpleRanges.Add(new SimpleRange());
}
else if (!_min.HasValue)
{ // Only a max.
SimpleRange simpleRange = new SimpleRange();
simpleRange.Max = _max.Value;
_simpleRanges.Add(simpleRange);
}
else if (!_max.HasValue)
{ // Only a min.
SimpleRange simpleRange = new SimpleRange();
simpleRange.Min = _min.Value;
_simpleRanges.Add(simpleRange);
}
else if (_max.Value < _min.Value)
{ // Max < Min. In Phil-world that means two seperate ranges.
// The union of what's below the max and what's above the min.
SimpleRange lowerRange = new SimpleRange();
lowerRange.Max = _max.Value;
_simpleRanges.Add(lowerRange);
SimpleRange upperRange = new SimpleRange();
upperRange.Min = _min.Value;
_simpleRanges.Add(upperRange);
}
else
{ // Max >= Min. So a single point or a simple range.
// We treat a single point as a simple range.
SimpleRange simpleRange = new SimpleRange();
simpleRange.Min = _min.Value;
simpleRange.Max = _max.Value;
_simpleRanges.Add(simpleRange);
}
}
public HashSet WhatToShow(int dayNumber)
{
HashSet result = new HashSet();
if (Included(dayNumber + 0.25))
result.Add(RangeOutput.Premarket);
if (Included(dayNumber + 0.5))
result.Add(RangeOutput.MarketHours);
if (Included(dayNumber + 0.75))
result.Add(RangeOutput.PostMarket);
return result;
}
}
}