using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using System.Xml; using TradeIdeas.TIProData; using TradeIdeas.TIProData.Configuration; using TradeIdeas.TIProData.Interfaces; using TradeIdeas.XML; namespace TradeIdeas.TIProGUI { public partial class TopListColorChooser : Form { /// /// These need to be set by the current top list before displaying the top list color chooser window. /// public GradientColorChooser GradientColorChooser; private IConnectionMaster _connectionMaster; private ImageCacheManager _imageCacheManager; private volatile bool _imageUpdatePending = false; private IList _allFilters = new List(); private string _initialColumn; private GradientInfo _initialColors; private FontManager _fontManager; private const float DEFAULT_FONT_SIZE = 9.75F; // Support image for menu items public static readonly WindowIconCache WindowIconCache = new WindowIconCache("TOPLIST_COLOR"); /*This is the "key" that corresponds to a particular row-Each row comprising of 3 colors. Each of these colors needn't all be the same.*/ private double _colorKey; // This includes space for the border. By setting these //in advance, rather than waiting for the icon to come in from // the server, we can do the layout immediately. private const int ICON_WIDTH = 44; private const int ICON_HEIGHT = 24; //Start location of colorChooser window when first brought up... //private static int _colorLocation_X = 50; //private static int _colorLocation_Y = 50; //for saving height // private static int _colorHeight = -1; //private static int _colorWidth = -1; //String "iD" is used as internal code (_gradientColorChooser.FieldInternalCode) and //its default is _initialColumn private string _iD = ""; //below three are for keeping track of recent changes... private List _recentColors = new List(); private bool _recentContainsSuggested = false; private void AddToRecentColors(GradientInfo change, bool isSuggested = false) { //If it's already there, move to top if (change.Map.Count > 0) { if (isSuggested && _recentContainsSuggested) _recentColors.RemoveAt(0); else _recentColors.Remove(change); if (!isSuggested && !GuiEnvironment.RecentColors.Contains(change)) GuiEnvironment.RecentColors.Add(change); _recentColors.Insert(0, change); //Don't let list get too long while (_recentColors.Count > 15) _recentColors.RemoveAt(_recentColors.Count - 1); _recentContainsSuggested = isSuggested; } } private GradientInfo.ColorForPoint _ptColors = new GradientInfo.ColorForPoint(); //Tester...for connection status////////////// private bool _disconnected = false; //Translations... private List _commonPhrases; private List _topListColor; /// /// If this is null, show all filters. /// ColumnInfo _limitToColumn; public void LimitToColumn(ColumnInfo column) { _limitToColumn = column; } private bool _displayOnlyShownColumns = true; public bool DisplayOnlyShownColumns { get { return _displayOnlyShownColumns; } set { _displayOnlyShownColumns = value; } } private readonly ConfigurationWindowManager _configManager = new ConfigurationWindowManager(); /// /// Controls whether filters are to be displayed. /// private bool _noFilterNeededMode = false; //THe below two are used for keeping an edited or added color //strategy within the visible portion of the currentColorsPanel private bool _wasAddDone = false; /// /// Constructor /// /// Constructor's single argument public TopListColorChooser(IConnectionMaster connectionMaster, bool noFilterNeededMode = false) { /* The other way to get all columns available would be, of course configurationWindowManager.FiltersInOrder. However, attempting to Load configurationWindowManager.LoadFromServer(args) didn't load anything on the first shot. Attempting this command again did populate the filtersInOrder, however it resulted in an Assertion Error in Phil's code. Apparently it was designed to have the "LoadFromServer" command called only once. So, as a somewhat sneaky maneuver, a static list declaration was placed within Config.cs(for some reason I cannot get to TIPro.MainForm, hence the selection of TIPro.TickPanel.) */ // TODO It would be nice if this updated more frequently. this.StartPosition = FormStartPosition.CenterParent; //Visible = false; WindowIconCache.SetIcon(this); _connectionMaster = connectionMaster; _noFilterNeededMode = noFilterNeededMode; if (_noFilterNeededMode) InitializeWindow(); else { _configManager.LoadFromServer(_connectionMaster, ConfigurationType.Alerts, OnConfigLoaded); _loadingLabel = new Label(); _loadingLabel.Dock = DockStyle.Fill; _loadingLabel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top; _loadingLabel.Text = "Please Wait..."; Controls.Add(_loadingLabel); } _recentColors = new List(GuiEnvironment.RecentColors); //Activated += TopListColorChooser_Activated; } //void TopListColorChooser_Activated(object sender, EventArgs e) //{ // SizeAndPositionControls(); //} private Label _loadingLabel; private void OnConfigLoaded(ConfigurationWindowManager configManager) { if (!SingleColumnMode()) // Show all _allFilters = configManager.FiltersInOrder; else { // Find the requested filter. (Convert from a ColumnInfo to a Filter.) _allFilters = new List(1); string internalCode = _limitToColumn.InternalCode; foreach (Filter f in configManager.FiltersInOrder) if (f.InternalCode == internalCode) { _allFilters.Add(f); break; } } InitializeWindow(); } private void InitializeWindow() { this.InvokeIfRequired(delegate { _imageCacheManager = _connectionMaster.ImageCacheManager; this.StartPosition = FormStartPosition.CenterParent; InitializeComponent(); MinimizeBox = false; if (_noFilterNeededMode) { filterSearchComboBox.Visible = false; } else { filterSearchComboBox.Items.Add(Category.ALL_FILTERS); filterSearchComboBox.SelectedIndex = 0; if (SingleColumnMode()) { // Disable the search feature. filterSearchComboBox.Enabled = false; filterSearchWatermarkTextBox.Enabled = false; } else { foreach (String forSearch in _configManager.CategoriesFilters) filterSearchComboBox.Items.Add(new Category(forSearch)); } Controls.Remove(_loadingLabel); } _commonPhrases = GuiEnvironment.XmlConfig.Node("COMMON_PHRASES"); _topListColor = GuiEnvironment.XmlConfig.Node("TOPLIST_COLOR_PICKER").Node("PHRASES"); _connectionMaster.ConnectionBase.ConnectionStatusUpdate += _ConnectionBase_ConnectionStatusUpdate; _imageCacheManager.CachedImageAvailable += new CachedImageAvailable(_imageCacheManager_CachedImageAvailable); Disposed += OnDisposed; // if (_colorWidth == -1 && _colorHeight == -1) // { // _colorWidth = Width; // _colorHeight = Height; // } _fontManager = new FontManager(this, DEFAULT_FONT_SIZE); LoadDefaultColumnColors(); LoadColorSetChoices(); //Visible = true; LoadWindowContents(); //Visible = true; //SizeAndPositionControls(); }); } private void OnDisposed(Object sender, EventArgs e) { _connectionMaster.ConnectionBase.ConnectionStatusUpdate -= _ConnectionBase_ConnectionStatusUpdate; _imageCacheManager.CachedImageAvailable -= _imageCacheManager_CachedImageAvailable; } private delegate void DoUpdate(); void _imageCacheManager_CachedImageAvailable() { if (InvokeRequired) { if (!_imageUpdatePending) { _imageUpdatePending = true; BeginInvoke((MethodInvoker)_imageCacheManager_CachedImageAvailable); } } else { if (IsDisposed) { return; } _imageUpdatePending = false; ReDisplayselectFilterPanel(); } } private void _ConnectionBase_ConnectionStatusUpdate(ConnectionBase source, ConnectionStatusCallbackArgs args) { /*This method checks the connection status. If there's a lost connection, we wouldn't be able to access any column information. In a case like this, the user can pick colors but not columns. Once the connection is lost, a column will not be highlighted if the user clicks on it. Once the connection is brought back, the user will have the ability to highlight a column..thus selecting it.*/ if (InvokeRequired) BeginInvoke((MethodInvoker)delegate { _ConnectionBase_ConnectionStatusUpdate(source, args); }); else { if (args.message == "") { _disconnected = true; recolorLabels(selectFilterPanel); } else if (args.isServerDisconnect) { _disconnected = true; recolorLabels(selectFilterPanel); } else { _disconnected = false; } } } private void ReDisplayselectFilterPanel() { foreach (Control control in selectFilterPanel.Controls) { DoUpdate changes = control.Tag as DoUpdate; if (null != changes) { changes(); } } } private bool SingleColumnMode() { return _limitToColumn != null; } private string _lastSearchText; private string _lastSearchCategory; private void selectFilterPanelSetUp() { string searchText = filterSearchWatermarkTextBox.Text; string searchCategory = ((Category)filterSearchComboBox.SelectedItem).ForSearch; if ((searchText != _lastSearchText) || (searchCategory != _lastSearchCategory)) { // Something actually changed. (The GUI frequently sends unnecessary events.) _lastSearchText = searchText; _lastSearchCategory = searchCategory; selectFilterPanelSetUp(searchText, searchCategory); } } private void selectFilterPanelSetUp(String searchText, String searchCategory) { HashSet matchingFilters = _configManager.Search(searchText, searchCategory); List toDisplay = new List(); foreach (Filter f in _allFilters) if (f.InternalCode == _iD) // This is the selected item. Display it first. // Always display it regardless of the search condition. toDisplay.Insert(0, f); else if (matchingFilters.Contains(f)) toDisplay.Add(f); try { ExtensionMethods.Clear(selectFilterPanel.Controls, true); selectFilterPanel.SuspendLayout(); int top = 10; int labelTop = (int)(10.0 + (double)ICON_HEIGHT / 5.0); bool singleColumnMode = SingleColumnMode(); if (toDisplay.Count != 0) { foreach (Filter f in toDisplay) { loadTheSelectFilterPanel(f, ref top, ref labelTop); } top += 10; if (!singleColumnMode && !_displayOnlyShownColumns) createSeparator(top); top += 10; } if (!singleColumnMode && !_displayOnlyShownColumns) { foreach (Filter filter in toDisplay) { labelTop = top + (int)((double)ICON_HEIGHT / 5.0); loadTheSelectFilterPanel(filter, ref top, ref labelTop); } } ReDisplayselectFilterPanel(); selectFilterPanel.ResumeLayout(); } catch (NullReferenceException) { } recolorLabels(selectFilterPanel); highLightLabels(selectFilterPanel); } private void loadTheSelectFilterPanel(Filter filter, ref int top, ref int labelTop) { PictureBox pictureBox = new PictureBox(); pictureBox.MouseClick += new MouseEventHandler(selectFilterPanel_MouseClick); pictureBox.Left = 10; pictureBox.Visible = true; pictureBox.Height = ICON_HEIGHT; pictureBox.Width = ICON_WIDTH; pictureBox.SizeMode = PictureBoxSizeMode.CenterImage; pictureBox.BorderStyle = BorderStyle.None; pictureBox.Top = top; Filter saveFilter = filter; pictureBox.Tag = (DoUpdate)delegate { pictureBox.Image = _imageCacheManager.GetFilter(saveFilter.MinCode); }; pictureBox.Name = saveFilter.InternalCode; //Now set up the labels for each icon.... /*Add the description label to the text box...*/ Label lblFilter = new Label(); lblFilter.MouseClick += new MouseEventHandler(selectFilterPanel_MouseClick); lblFilter.Left = 55; lblFilter.AutoSize = true; lblFilter.TextAlign = ContentAlignment.TopLeft; lblFilter.Text = saveFilter.Description.ToString() + " (" + saveFilter.Units.ToString() + ")"; lblFilter.Width = (int)getLabelStringLength(lblFilter); lblFilter.Height = 17; //needed so that when label is highlighted, color is evenly distributed around label! lblFilter.Top = labelTop; lblFilter.Name = filter.InternalCode; if (GuiEnvironment.FontSettings.Height >= (ICON_HEIGHT - 4)) { lblFilter.Top = top + 4; top += lblFilter.Height + 2; } else { //all of these wild adjustments are to try to reduce the spacing between //filter icons. This will vary greatly with font. I tried to tailor as much //as possible for the Sans Serif as well as Arial. There's really no way to //adjust for all fonts. Two fonts may have the same size, however their appearance //can vary greatly. And fonts will actually affect the appearance of the filter icons themselves. For //examle, Arial Narrow will actually cut off some of the filter icon. !! Actually, // I personally find the Microsoft Sans Serif font to be the easiest for tailoring, //no matter what the fontsize. lblFilter.Top = labelTop; labelTop += pictureBox.Height + (int)((double)pictureBox.Height / 9.0) + (int)(GuiEnvironment.FontSettings.Size / 10); } selectFilterPanel.Controls.Add(pictureBox); selectFilterPanel.Controls.Add(lblFilter); if (GuiEnvironment.FontSettings.Height < (ICON_HEIGHT - 4)) { top += pictureBox.Height + (int)((double)pictureBox.Height / 9.0) + (int)(GuiEnvironment.FontSettings.Size / 10); } } private void createSeparator(int top) { Label lblBevel = new Label(); lblBevel.Top = top; lblBevel.Left = 0; lblBevel.Name = "separator"; lblBevel.Width = selectFilterPanel.Width * 2; lblBevel.Anchor = (AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right); lblBevel.AutoSize = false; lblBevel.BackColor = Color.LightGray; lblBevel.Height = 5; lblBevel.BorderStyle = BorderStyle.Fixed3D; selectFilterPanel.Controls.Add(lblBevel); } private void selectFilterPanel_MouseClick(object sender, MouseEventArgs e) { if (_disconnected == false) { Panel p; Label label = null; PictureBox columnChosen = null; Filter chosenFilter; if (sender as PictureBox != null) { columnChosen = (PictureBox)sender; chosenFilter = getFilter(columnChosen.Name); _iD = chosenFilter.InternalCode; } else { label = (Label)sender; chosenFilter = getFilter(label.Name); _iD = chosenFilter.InternalCode; } p = selectFilterPanel; recolorLabels(p); highLightLabels(p, chosenFilter); GradientColorChooser.FieldInternalCode = _iD; GradientInfo suggestedGradientInfo = GetDefaultColumnColor(); if (null != suggestedGradientInfo && !suggestedGradientInfo.Empty()) AddToRecentColors(suggestedGradientInfo, true); else if (_recentContainsSuggested) { _recentColors.RemoveAt(0); _recentContainsSuggested = false; } loadRecentColors(); } } private float getLabelStringLength(Label label) { /*This method calculates the length of the label text within the currentColumns panel. If the returned value exceeds the width of that panel, then and only then will a horizontal scroll bar appear. Otherwise it is absent.*/ Graphics graphics = this.CreateGraphics(); SizeF textSize = graphics.MeasureString(label.Text, GuiEnvironment.FontSettings); graphics.Dispose(); return (textSize.Width + label.Width); } private Filter getFilter(string internalCode) { Filter desired = null; foreach (Filter f in _allFilters) { if (f.InternalCode == internalCode) { desired = f; break; } } return desired; } private void highLightLabels(Panel p, Filter f) { /*This method highlights selected labels in the Columns and Sort panels...*/ foreach (Control c in p.Controls) { if (c as Label != null) { if (f.InternalCode == c.Name) { Label lbl = (Label)c; lbl.BackColor = Color.LightSkyBlue; break; } } } } private void highLightLabels(Panel p) { foreach (Control c in p.Controls) { if (c is Label) { if (_iD == c.Name) { Label lbl = (Label)c; lbl.BackColor = Color.LightSkyBlue; break; } } } } private void recolorLabels(Panel panel) { /*This method resets background colors of labels to transparent..*/ if (panel.Controls.Count != 0) { foreach (Control c in panel.Controls) { if (c as Label != null) { Label label = (Label)c; if (c.Name != "separator") { label.BackColor = Color.Transparent; } } } } } private void loadCurrentColors(GradientInfo gInfo) { ExtensionMethods.Clear(pnlCurrentColor.Controls, true); pnlCurrentColor.SuspendLayout(); int top = 0; foreach (KeyValuePair kvp in gInfo.Map) { int left = 0; PictureBox pbBelow = new PictureBox(); pbBelow.MouseClick += new MouseEventHandler(colorBox_MouseClick); pbBelow.Name = kvp.Key.ToString(); pbBelow.Left = left; pbBelow.Height = Font.Height; pbBelow.Width = Font.Height-3; pbBelow.Top = top; pbBelow.BackColor = kvp.Value.Below; pnlCurrentColor.Controls.Add(pbBelow); left += pbBelow.Width + 2; PictureBox pbAt = new PictureBox(); pbAt.MouseClick += new MouseEventHandler(colorBox_MouseClick); pbAt.Name = kvp.Key.ToString(); pbAt.Paint += new PaintEventHandler(putText); pbAt.Left = left; pbAt.Height = Font.Height; pbAt.Width = getStringLength(kvp.Key.ToString(), Font.Height + 12); pbAt.Top = top; pbAt.BackColor = kvp.Value.At; pnlCurrentColor.Controls.Add(pbAt); left += pbAt.Width + 2; PictureBox pbAbove = new PictureBox(); pbAbove.MouseClick += new MouseEventHandler(colorBox_MouseClick); pbAbove.Name = kvp.Key.ToString(); pbAbove.Left = left; pbAbove.Height = Font.Height; pbAbove.Width = Font.Height - 3; pbAbove.Top = top; pbAbove.BackColor = kvp.Value.Above; pnlCurrentColor.Controls.Add(pbAbove); left += pbAbove.Width; PictureBox pbArrow = new PictureBox(); pbArrow.Name = kvp.Key.ToString() + "_1"; pbArrow.Height = Font.Height; pbArrow.Width = Font.Height + 12; pbArrow.BackColor = Color.Transparent; pbArrow.Top = top; pbArrow.Left = left; pnlCurrentColor.Controls.Add(pbArrow); top += Font.Height + 2; } pnlCurrentColor.ResumeLayout(); if (_wasAddDone) { /* Here we wish to keep whatever colorstrategy that has been either edited or added within the visible portion of the panel.*/ int index = 0; for (int i = 0; i < pnlCurrentColor.Controls.Count; i++) { if (pnlCurrentColor.Controls[i].Name == _colorKey.ToString()) { index = i; break; } } _wasAddDone = false; pnlCurrentColor.Controls[index].Focus(); } } private void colorBox_MouseClick(object sender, EventArgs e) { /*Selecting colors in the CurrentColors panel*/ btnAdd.Enabled = true; btnDelete.Enabled = true; Panel p; PictureBox colorChosen = null; if (sender as PictureBox != null) { colorChosen = (PictureBox)sender; _colorKey = Convert.ToDouble(colorChosen.Name); } p = pnlCurrentColor; resetLabels(p); markLabels(p, colorChosen); txtValue.Text = _colorKey.ToString(); GradientInfo.ColorForPoint cp = getColorForPoint(_colorKey); btnBelow.BackColor = cp.Below; btnBelow.ForeColor = GradientInfo.AltColor(btnBelow.BackColor);//new btnAt.BackColor = cp.At; btnAt.ForeColor = GradientInfo.AltColor(btnAt.BackColor);//new btnAbove.BackColor = cp.Above; btnAbove.ForeColor = GradientInfo.AltColor(btnAbove.BackColor);//new } private void recentText(object sender, PaintEventArgs e) { /*This method positions the numerical value within the square picture box in recent changes panel.*/ using (Font myFont = new Font(GuiEnvironment.FontSettings.Name, GuiEnvironment.FontSettings.Size)) { int offset; //keep the numbers lined up.. PictureBox pic = (PictureBox)sender; string[] name = pic.Name.Split('_'); if (name[0].Length > 1 && name[0].Length < 4) { offset = 1; } else { offset = 2; } Color foreground = GradientInfo.AltColor(pic.BackColor); SolidBrush b = new SolidBrush(foreground); e.Graphics.DrawString(name[0], myFont, b, new Point(offset, 2)); b.Dispose(); } } private void putText(object sender, PaintEventArgs e) { /*This method positions the numerical value within the current-colors picture box*/ using (Font myFont = new Font(GuiEnvironment.FontSettings.Name, GuiEnvironment.FontSettings.Size)) { int offset = 0; //keep the numbers lined up.. PictureBox pic = (PictureBox)sender; if (pic.Name.Length > 1) { if (pic.Name.Length == 2 && pic.Name.Contains("-")) { offset = 6; } else { offset = 2; } } else { offset = 10; } Color foreground = GradientInfo.AltColor(pic.BackColor); SolidBrush b = new SolidBrush(foreground); e.Graphics.DrawString(pic.Name, myFont, b, new Point(offset, 2)); b.Dispose(); } } private void resetLabels(Panel panel) { /*This method clears any pic-box images*/ if (panel.Controls.Count != 0) { foreach (Control c in panel.Controls) { if (c as PictureBox != null) { PictureBox pic = (PictureBox)c; if (pic.Image != null) { pic.Image = null; } } } } } private void markLabels(Panel p, PictureBox box) { /*This method marks the selected row shown within the * CurrentColors Panel with an arrow...*/ foreach (Control c in p.Controls) { if (c as PictureBox != null) { if (c.Name == box.Name + "_1") { PictureBox pic = (PictureBox)c; pic.Image = imageList1.Images[0]; break; } } } } private void loadRecentColors() { ExtensionMethods.Clear(pnlRecentColor.Controls, true); pnlRecentColor.SuspendLayout(); int endSpace = 0; int top = 0; int objectCount = 0; foreach (GradientInfo gI in _recentColors) { int left = 0; foreach (KeyValuePair kvp in gI.Map) { if (kvp.Value.Below != kvp.Value.At) { PictureBox pbBelow = new PictureBox(); pbBelow.MouseClick += new MouseEventHandler(settingsBox_MouseClick); pbBelow.Name = "<" + kvp.Key.ToString() + "_" + objectCount.ToString(); pbBelow.Paint += new PaintEventHandler(recentText); pbBelow.Left = left; pbBelow.Height = Font.Height; pbBelow.Width = getStringLength("<" + kvp.Key.ToString(), Font.Height); pbBelow.Top = top; pbBelow.BackColor = kvp.Value.Below; pnlRecentColor.Controls.Add(pbBelow); left += pbBelow.Width + 2; } PictureBox pbAt = new PictureBox(); pbAt.MouseClick += new MouseEventHandler(settingsBox_MouseClick); pbAt.Name = kvp.Key.ToString() + "_" + objectCount.ToString(); pbAt.Paint += new PaintEventHandler(recentText); pbAt.Left = left; pbAt.Height = Font.Height; pbAt.Width = getStringLength(kvp.Key.ToString(), Font.Height); pbAt.Top = top; pbAt.BackColor = kvp.Value.At; pnlRecentColor.Controls.Add(pbAt); endSpace = pbAt.Width + 2; if (kvp.Value.Above != kvp.Value.At) { left += pbAt.Width + 2; PictureBox pbAbove = new PictureBox(); pbAbove.MouseClick += new MouseEventHandler(settingsBox_MouseClick); pbAbove.Name = ">" + kvp.Key.ToString() + "_" + objectCount.ToString(); pbAbove.Paint += new PaintEventHandler(recentText); pbAbove.Left = left; pbAbove.Height = Font.Height; pbAbove.Width = getStringLength(">" + kvp.Key.ToString(), Font.Height); pbAbove.Top = top; pbAbove.BackColor = kvp.Value.Above; pnlRecentColor.Controls.Add(pbAbove); endSpace = pbAbove.Width + 2; } left += endSpace; } top += Font.Height + 2; objectCount++; } pnlRecentColor.ResumeLayout(); } private bool isSelected() { /*Addresses a bug where a new row is added, then upon hitting Delete button, that row is deleted, although it is not selected with the arrow-marker*/ foreach (Control c in pnlCurrentColor.Controls) { if (c as PictureBox != null) { PictureBox p = (PictureBox)c; if (p.Image != null) { return true; } } } return false; } private GradientInfo.ColorForPoint getColorForPoint(double key) { /*Return a ColorForPoint object(struct) so we can have access to the three color components...*/ GradientInfo.ColorForPoint g = new GradientInfo.ColorForPoint(); foreach (KeyValuePair kvp in GradientColorChooser.GradientInfo.Map) { if (key == kvp.Key) { g = kvp.Value; break; } } return g; } private bool SetColor(Button button) //sets button_color { colorDialog1.Color = button.BackColor; if (colorDialog1.ShowDialog() == DialogResult.OK) { button.BackColor = colorDialog1.Color; button.ForeColor = GradientInfo.AltColor(button.BackColor); return true; } return false; } private void btnBelow_Click(object sender, EventArgs e) { if (SetColor(btnBelow)) _ptColors.Below = btnBelow.BackColor; } private void btnAt_Click(object sender, EventArgs e) { if (SetColor(btnAt)) { btnBelow.BackColor = btnAbove.BackColor = btnAt.BackColor; btnBelow.ForeColor = btnAbove.ForeColor = btnAt.ForeColor = GradientInfo.AltColor(btnAt.BackColor); _ptColors.Below = _ptColors.At = _ptColors.Above = btnAt.BackColor; } } private void btnAbove_Click(object sender, EventArgs e) { if (SetColor(btnAbove)) _ptColors.Above = btnAbove.BackColor; } private void settingsBox_MouseClick(object sender, EventArgs e) { /*Selecting colors in the recent settings panel*/ int rowNumber; PictureBox rowChosen = null; if (sender as PictureBox != null) { rowChosen = (PictureBox)sender; /*Now we must fetch the row number..The row number will ultimately enable us to exctract the proper object from the List. (The row number corresponds with the index number in the List).*/ string[] name = rowChosen.Name.Split('_'); rowNumber = Convert.ToInt32(name[1]); GradientInfo gr = fetchInfo(rowNumber); GradientColorChooser.GradientInfo = gr; loadCurrentColors(gr); } } private GradientInfo fetchInfo(int index) { if ((index < 0) || (index >= _recentColors.Count)) return new GradientInfo(); else return _recentColors[index]; } private int getStringLength(string text, int ideal) { /*This method calculates the length of the text string * on the colored boxes within the recentColors panel. */ //The parameter "ideal" is the initial ideal width of the colorbox //that we see in the recent colors panel.(perfect square with //the height, and visually appealing when we see more than one //row within that panel). However if the text exceeds "textWidth" //the width,ofcourse, of the colored box must be increased to the //new size . Height will always stay the same at 18. int testWidth = ideal; Graphics graphics = this.CreateGraphics(); SizeF textSize = graphics.MeasureString(text, this.Font); if ((int)textSize.Width >= testWidth) { graphics.Dispose(); return (int)textSize.Width; } graphics.Dispose(); return testWidth; } private void ColorChooser_Layout(object sender, LayoutEventArgs e) { //SizeAndPositionControls(); } private void SizeAndPositionControls() { /*this.InvokeIfRequired(delegate() { //Needed this code to make both panels resize smoothly //and proportionately... and maintaining the same "gap" between // the right edge of the left-hand boxes and the left edge // of the right-hand panel... tableLayoutPanelChangeColors.Left = pnlCurrentColor.Right + 10; pnlSort.Left = tableLayoutPanelChangeColors.Right + 10; pnlSort.Width = (pnlDecor.Width - 50) / 3; pnlCurrentColor.Width = (pnlDecor.Width - 50) / 3; pnlRecentColor.Width = (pnlDecor.Width - 97) / 2; tableLayoutPanelChangeColors.Width = (pnlDecor.Width - 50) / 3; labelChangeColors.Left = tableLayoutPanelChangeColors.Left; }); */ } private void btnCancel_Click(object sender, EventArgs e) { GradientColorChooser.GradientInfo = _initialColors; GradientColorChooser.FieldInternalCode = _initialColumn; _iD = _initialColumn; this.Hide(); } private void btnDelete_Click(object sender, EventArgs e) { if (isSelected()) { GradientInfo gr = GradientColorChooser.GradientInfo; gr.Remove(_colorKey); GradientColorChooser.GradientInfo = gr; txtValue.Text = ""; btnDelete.Enabled = false; loadCurrentColors(GradientColorChooser.GradientInfo); } } private void btnAdd_Click(object sender, EventArgs e) { try { _colorKey = Convert.ToDouble(txtValue.Text); GradientInfo.ColorForPoint colors = new GradientInfo.ColorForPoint(); colors.Below = btnBelow.BackColor; colors.At = btnAt.BackColor; colors.Above = btnAbove.BackColor; _wasAddDone = true; GradientInfo gr = GradientColorChooser.GradientInfo; gr.Add(_colorKey, colors); GradientColorChooser.GradientInfo = gr; loadCurrentColors(gr); } catch (FormatException) { MessageBox.Show ( "Data Invalid or Missing! Please enter a valid number in text box.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1 ); } } private void PopulateStrings() { this.Text = _topListColor.Node("TITLE").PropertyForCulture("TEXT", "***"); btnOK.Text = _commonPhrases.Node("OK").PropertyForCulture("TEXT", "***"); btnCancel.Text = _commonPhrases.Node("CANCEL").PropertyForCulture("TEXT", "***"); btnDelete.Text = _topListColor.Node("DELETE").PropertyForCulture("TEXT", "***"); btnAdd.Text = _topListColor.Node("ADD_EDIT").PropertyForCulture("TEXT", "***"); lblCurrentColors.Text = _topListColor.Node("CURRENT_COLORS").PropertyForCulture("TEXT", "***"); lblRecentColors.Text = _topListColor.Node("RECENT_SETTINGS").PropertyForCulture("TEXT", "***"); } private void btnOK_Click(object sender, EventArgs e) { DialogResult = System.Windows.Forms.DialogResult.OK; this.Hide(); } private void TopListColorCHooser_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { // This window should be reusable, like a dialog box. e.Cancel = true; Hide(); } } private void TopListColorChooser_VisibleChanged(object sender, EventArgs e) { //LoadWindowContents(); //AddToRecentColors(GradientColorChooser.GradientInfo); } private void LoadWindowContents() { //if (!this.Visible) //{ // Note GradientColorChooser made the deep copy for us. //AddToRecentColors(GradientColorChooser.GradientInfo); //Save the location of this window on the screen. //When made visible, this window will assume the position //_colorLocation_X = Location.X; //_colorLocation_Y = Location.Y; //save the size of this window...should user resize. // _colorHeight = Height; // _colorWidth = Width; //} //else //{ //Location = new Point(_colorLocation_X, _colorLocation_Y); // Size = new Size(_colorWidth, _colorHeight); PopulateStrings(); bool flag = false; _initialColors = GradientColorChooser.GradientInfo; _initialColumn = GradientColorChooser.FieldInternalCode; // Always display the colors we start with at the top of the list. // That way the user can see his changes, and he can quickly undo // them by clicking on the top row. AddToRecentColors(GradientColorChooser.GradientInfo); if ((null == _iD) || (_iD == "")) // Only do this the first time. _iD is what we're currently showing, // and what you get if you hit OK. _initialColumn is what you get if // you hit cancel. _iD = _initialColumn; _searchIsReady = true; StartSearchSoon(); Filter fg = getFilter(_iD); recolorLabels(selectFilterPanel); try { foreach (Filter f in _allFilters) { if (f.InternalCode == fg.InternalCode) { highLightLabels(selectFilterPanel, fg); flag = true; break; } } if (flag == false) { /*This is where the blue highlight selection will default to, should the user(in Config window) remove a column that was highlighted within this TopListColor Chooser window.*/ Filter f = _allFilters[0]; highLightLabels(selectFilterPanel, getFilter(f.InternalCode)); // Mark this as a change. Tell the color chooser that something changed. // Make sure that the colors in the top list window and the colors in the // color chooser match. GradientColorChooser.FieldInternalCode = f.InternalCode; } } catch (NullReferenceException) { } catch (ArgumentOutOfRangeException) { } if (null == GradientColorChooser.GradientInfo || GradientColorChooser.GradientInfo.Map.Count == 0) GradientColorChooser.GradientInfo = GetDefaultColumnColor(); GradientInfo suggestedGradientInfo = GetDefaultColumnColor(); if (null != suggestedGradientInfo && !suggestedGradientInfo.Empty()) AddToRecentColors(suggestedGradientInfo, true); else if (_recentContainsSuggested) { _recentColors.RemoveAt(0); _recentContainsSuggested = false; } if (!isSelected()) { btnDelete.Enabled = false; } else { btnDelete.Enabled = true; } _fontManager.selectTheFont(); loadCurrentColors(GradientColorChooser.GradientInfo); loadRecentColors(); // Resize the form height to fit within the working area of current monitor. Screen screen = Screen.FromControl(this); if (this.Height > screen.WorkingArea.Height) { // Retrieve the working rectangle from the Screen class // using the PrimaryScreen and the WorkingArea properties. Rectangle workingRectangle = screen.WorkingArea; // Set the size of the form slightly less in height // but keeping it's width. this.Size = new Size( this.Size.Width, workingRectangle.Height - 10); //pnlDecor.Height = Height - 150; //btnOK.Top = pnlDecor.Bottom + 5; // TODO: Understand the following logic stops working starting at font sizes of 24. // At that point the OK and Cancel buttons are hidden from view. btnCancel.Top = btnOK.Top; pnlCurrentColor.Height = pnlRecentColor.Height; btnDelete.Top = pnlCurrentColor.Bottom + 5; buttonFlipColors.Top = btnDelete.Top; buttonDeleteAll.Top = lblRecentColors.Top - (lblRecentColors.Top - btnDelete.Bottom - 15); btnBelow.Top = lblRecentColors.Top - (lblRecentColors.Top - buttonDeleteAll.Bottom - 15); btnAt.Top = btnAbove.Top = txtValue.Top = btnBelow.Top; btnAdd.Top = btnBelow.Bottom + 5; // Set the location so the entire form is visible. this.Location = new Point(screen.Bounds.X + 5, screen.Bounds.Y + 5); } // Move the window from the bottom and right to keep it in the working area. // TODO: This logic does not work well if form is stradling between monitors of different resolutions. if (this.Bounds.Bottom > screen.WorkingArea.Bottom) { this.Location = new Point(this.Location.X, this.Location.Y - (this.Bounds.Bottom - screen.WorkingArea.Bottom)); } if (this.Bounds.Right > screen.WorkingArea.Right) { this.Location = new Point(this.Location.X - (this.Bounds.Right - screen.WorkingArea.Right), this.Location.Y); } //} } private GradientInfo GetDefaultColumnColor() { string internalCode; if (_allFilters.Count == 0) internalCode = ""; else internalCode = _allFilters.First().InternalCode; if ((_limitToColumn == null) && _iD != "") internalCode = _iD; if (_defaultColumnColors.ContainsKey(internalCode)) return _defaultColumnColors[internalCode]; else return new GradientInfo(); } private Dictionary _defaultColumnColors = new Dictionary(); private List> _colorSetChoices = new List>(); private const int COLOR_SET_COUNT = 5; private void LoadColorSetChoices() { List filterColorSets = GuiEnvironment.XmlConfig.Node("FILTER_COLOR_SETS"); foreach (XmlElement colorsNode in filterColorSets.Enum()) { List colorSet = new List(); foreach (XmlElement colorNode in colorsNode.Enum()) { Color color = colorNode.Property("VALUE", XmlHelper.InvalidColor); if (color != XmlHelper.InvalidColor) colorSet.Add(color); } if (colorSet.Count == 5) _colorSetChoices.Add(colorSet); } tableLayoutPanelChangeColors.Controls.Clear(); tableLayoutPanelChangeColors.RowCount = COLOR_SET_COUNT; tableLayoutPanelChangeColors.ColumnCount = _colorSetChoices.Count; tableLayoutPanelChangeColors.ColumnStyles.Clear(); tableLayoutPanelChangeColors.RowStyles.Clear(); for (int i = 0; i < 5; i++) { RowStyle rowStyle = new RowStyle(); rowStyle.SizeType = SizeType.Percent; rowStyle.Height = 100 / COLOR_SET_COUNT; tableLayoutPanelChangeColors.RowStyles.Add(rowStyle); } for (int i = 0; i < _colorSetChoices.Count; i++) { ColumnStyle columnStyle = new ColumnStyle(); columnStyle.SizeType = SizeType.Percent; columnStyle.Width = 100 / _colorSetChoices.Count; tableLayoutPanelChangeColors.ColumnStyles.Add(columnStyle); } for (int i = 0; i < _colorSetChoices.Count; i++) { List colorSet = _colorSetChoices[i]; for (int j = 0; j < COLOR_SET_COUNT; j++) { Color color = colorSet[j]; ColorSetLabel colorLabel = new ColorSetLabel(); colorLabel.First = j == 0; colorLabel.Last = j == COLOR_SET_COUNT - 1; colorLabel.BackColor = color; colorLabel.Tag = colorSet; colorLabel.Dock = DockStyle.Fill; colorLabel.Click += colorLabel_Click; tableLayoutPanelChangeColors.Controls.Add(colorLabel, i, j); } } } void colorLabel_Click(object sender, EventArgs e) { Label colorLabel = sender as Label; if (null != colorLabel) { List colorSet = colorLabel.Tag as List; if (null != colorSet) { int colorCount = GradientColorChooser.GradientInfo.Map.Count; List colorsToApply = new List(); if (colorCount == 1) colorsToApply.Add(colorSet[0]); else if (colorCount == 2) { colorsToApply.Add(colorSet[0]); colorsToApply.Add(colorSet[COLOR_SET_COUNT - 1]); } else if (colorCount == 3) { colorsToApply.Add(colorSet[0]); colorsToApply.Add(colorSet[2]); colorsToApply.Add(colorSet[COLOR_SET_COUNT - 1]); } else if (colorCount == 4) { colorsToApply.Add(colorSet[0]); colorsToApply.Add(colorSet[1]); colorsToApply.Add(colorSet[2]); colorsToApply.Add(colorSet[COLOR_SET_COUNT - 1]); } else if (colorCount >= 5) colorsToApply = new List(colorSet); int i = 0; GradientInfo gr = GradientColorChooser.GradientInfo; foreach (KeyValuePair kvp in GradientColorChooser.GradientInfo.Map) { double value = kvp.Key; GradientInfo.ColorForPoint originalColorForPoint = kvp.Value; if (i < colorsToApply.Count) { GradientInfo.ColorForPoint colorForPoint = new GradientInfo.ColorForPoint(); colorForPoint.Above = colorsToApply[i]; colorForPoint.Below = colorsToApply[i]; colorForPoint.At = colorsToApply[i]; gr.Add(value, colorForPoint); } else gr.Add(value, originalColorForPoint); i++; } GradientColorChooser.GradientInfo = gr; loadCurrentColors(GradientColorChooser.GradientInfo); } } } private void LoadDefaultColumnColors() { List filterDefaultColors = GuiEnvironment.XmlConfig.Node("FILTER_DEFAULT_COLORS"); foreach (XmlElement node in filterDefaultColors.Enum()) { string internalCode = node.Property("COLUMN", ""); if (internalCode != "") { GradientInfo gradientInfo = new GradientInfo(node.FirstChild); if (_defaultColumnColors.ContainsKey(internalCode)) _defaultColumnColors[internalCode] = gradientInfo; else _defaultColumnColors.Add(internalCode, gradientInfo); } } } private void buttonFlipColors_Click(object sender, EventArgs e) { GradientInfo gr = new GradientInfo(); IList gradientLevels = GradientColorChooser.GradientInfo.Map.Keys; for (int i = 0; i < gradientLevels.Count; i++) { double gradientLevel = gradientLevels[i]; double flippedIndex = gradientLevels[gradientLevels.Count - 1 - i]; GradientInfo.ColorForPoint colorForPoint = GradientColorChooser.GradientInfo.Map[flippedIndex]; gr.Add(gradientLevel, colorForPoint); } GradientColorChooser.GradientInfo = gr; loadCurrentColors(GradientColorChooser.GradientInfo); } private void buttonDeleteAll_Click(object sender, EventArgs e) { GradientInfo gr = GradientColorChooser.GradientInfo; gr.Map.Clear(); GradientColorChooser.GradientInfo = gr; loadCurrentColors(GradientColorChooser.GradientInfo); } private class Category { public readonly String HumanReadable; public readonly String ForSearch; public Category(String forSearch) { HumanReadable = ConfigWindow.GetPleasingCategoryString(forSearch); ForSearch = forSearch; } private static string AllFiltersText() { // TODO. This should be read from the XML file. Note that ConfigWindow.cs already does this // using "ALL_FILTERS" as the name of this item. return "All Filters"; } private Category(String forSearch, String humanReadable) { HumanReadable = humanReadable; ForSearch = forSearch; } public static readonly Category ALL_FILTERS = new Category(null, AllFiltersText()); public override string ToString() { return HumanReadable; } } private void StartSearchSoon(object sender, EventArgs e) { StartSearchSoon(); } private bool _searchPanelHasBeenInitialized = false; private bool _searchIsReady = false; /// /// Schedule a reload of the list of filters. Note that we always use search to fill /// that panel in. Sometimes the search is just set to be completely open, the "where" /// conition is "true". But this same routine does that. /// /// Use a timer (except for the first time) to make things smoother. We fill in the /// search as the user is typing, and as he's selecting from the list of categories. /// Search can take a brief but noticible moment, espeically when a lot of filters are /// visible before or after the search. You don't want the GUI to lock up briefly /// each time the user types something. Wait for a pause in the user's typing. /// private void StartSearchSoon() { if (!_searchIsReady) // The _iD field hasn't been initialized yet. return; if (!_searchPanelHasBeenInitialized) { // Do it immeidately. Don't show the user an empty search panel. selectFilterPanelSetUp(); _searchPanelHasBeenInitialized = true; } else { // Do it soon. If a request was already pending, delay that request a // little bit. If someone types quickly enough in the search box, this // could be delayed for a long time. timer1.Stop(); timer1.Start(); //DateTime now = DateTime.Now; //System.Diagnostics.Debug.WriteLine("StartSearchSoon() at " + now + " and " + DateTime.Now.Millisecond + " milliseconds"); } } private void StartSearchNow(object sender, EventArgs e) { // called in timer tick //DateTime now = DateTime.Now; //System.Diagnostics.Debug.WriteLine("StartSearchNow() at " + now + " and " + DateTime.Now.Millisecond + " milliseconds"); timer1.Enabled = false; StartSearchNow(); } private void StartSearchNow() { selectFilterPanelSetUp(); } } public class ColorSetLabel : Label { public bool First { get; set; } public bool Last { get; set; } public ColorSetLabel() { Paint += ColorSetLabel_Paint; } void ColorSetLabel_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; int topBorder = 0; if (First) topBorder = 1; int bottomBorder = 0; if (Last) bottomBorder = 1; ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.Black, 1, ButtonBorderStyle.Solid, Color.Black, topBorder, ButtonBorderStyle.Solid, Color.Black, 1, ButtonBorderStyle.Solid, Color.Black, bottomBorder, ButtonBorderStyle.Solid); } } }