using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Windows.Forms;
using TradeIdeas.XML;
using System.Drawing;
using TradeIdeas.Logging;
using WeifenLuo.WinFormsUI.Docking;
using System.ComponentModel;
/* Typically the main program would make one instance of the Layout Manager.
*
* Each window type is represented by a string. This string must be saved when you are
* saving a window, so we know which procedure to call when restoring a window. The
* rest is completely up to the window, but most windows will call SaveBase() and
* RestoreBase() to do the common things like the size and position of the window.
* The mechanism doesn't even require a form; you can choose to save other settings
* as part of the layout.
*
* If you want to be saved as part of the layout, you have two choices. You can
* implement ISaveLayout. When the user askes to save the layout, we iterate though
* all open windows looking for windows that implement that interface. That is ideal
* for classes which can support any number of windows. We also have our own list of
* windows named SpecialSaveLayout. This is useful for windows which are unique, and
* which might be hidden at the time we save the layout. These will still have the
* chance save their layout.
*
* Note that the callback for saving your layout gives you an XML node. That is the
* parent of any nodes you create. You should create one child per window that you
* want to save. This gives you the opportunity to decide at runtime not to save
* a specific window. Or to save more than one window in one callback.
*
* All restoring is done through AddRestoreRule(). The key is the name that we
* stored in the XML when we saved the layout. Each key points to a delegate. For
* a class which can support any number of windows, this delegate will typically
* call the class's constructor, then RestoreBase(), then anything specific for
* that window. For unique windows, the delegate will point directly to an existing
* window object, so there is no need to call the constructor. The delegate will
* immedately call RestoreBase() followed by anything specific to the object.
*
* Notice that we always store a list of windows. Presumably when you say to save
* a window, you will get a file with only that one window. However, there is
* no restriction, and when you say to load a window, you might get multiple windows.
* In fact, the only difference between loading a saved window and loading a saved
* layout is that before we restore an old layout, we close all the existing windows.
*
* Notice that there is a way to ignore the position when we restore a window. That
* makes a convenient way to duplicate a window. Save the window into memory, then
* restore everything but the position. Windows should ask the operating system to
* put them in the default position when they are first created. (For some reason
* there is no method to request the default position after a window has been
* created.) When you duplicate a window, you don't want the new to be on top of
* the old one. That's confusing to a user; it looks like nothing happened. The
* default position will be offset by a little bit each time you create a new window
* so you can see each window clearly.
*
* This code was specifically designed to know nothing about the specific windows
* in the program. It learns about them at runtime through callbacks. So many
* different main programs should all be able to use this library routine. This
* code is based loosely on a similar library I wrote for Delphi.
*/
namespace TradeIdeas.TIProGUI
{
///
/// This delegate works with . This allows
/// any class to participate in the layout. is an alternative.
/// This delegate works well with classes that are not forms, and with forms where you
/// want exactly 0 or 1 instance of each form to be visible.
///
///
/// This is the whole layout file. Create one new node for each window.
/// provides a good starting point for saving a window.
///
public delegate void SaveLayout(XmlNode parent);
///
/// A window should implement this interface if it wants to participate in the layout. In particular,
/// this is used when there can be 0 or more windows of a particular type. We iterate through the
/// list of visible windows looking for windows that implement this. is a
/// reasonable alternative.
///
public interface ISaveLayout
{
///
/// Add yourself to the layout.
/// provides a good starting point for saving a window.
///
///
/// This is the whole layout file. Create one new node for each window.
///
void SaveLayout(XmlNode parent);
///
/// Return the icon for the window. This should never be null.
/// can provide a reasonable default
/// if necessary. The icon name is probably more important than the actual
/// icon, because we are more likely to store that.
///
WindowIconCache WindowIconCache { get; }
bool Pinned { get; set; }
}
public delegate void LayoutRestoreCompleteHandler(bool replacedWindows);
// change parameters to accommodate dock panel changes - RVH20210402
//public delegate void RestoreLayout(XmlNode description, bool ignorePosition, bool cascadePosition);
public delegate void RestoreLayout(XmlNode description, bool ignorePosition, bool cascadePosition, bool dockPanelMode, string mainDockPanelName, string mainDockPanelTitle, string dockPanelID);
public enum ApplicationClosingState
{
LayoutSaved,
LayoutNotSaved,
Exception,
ShuttingDown,
Canceled
}
public interface IUpdateLayout
{
void UpdateLayout(XmlNode layout, ApplicationClosingState appstate);
}
public class LayoutManager
{
public static bool OddsMakerAvailable = false;
public static int OddsMakerTrials = 0;
public const string FORM_TYPE = "FORM_TYPE";
const string BASE = "BASE";
const int CASCADE_OFFSET = 20;
// define main dock form list - RVH20210328
private static List _mainDockFormList = new List();
// init _idCount - RVH20210409
private int _idCount = 0;
///
/// Controls whether multiple channels can be opened separately at the same time.
///
public bool MultiChannelEnabled { get; set; } = true;
private static MainDockForm _dockPanelFormFocused = null;
///
/// Gets and Sets the DockPanelForm that currently has focus.
///
public MainDockForm DockPanelFormFocused
{
get { return _dockPanelFormFocused; }
set { _dockPanelFormFocused = value; }
}
///
/// A list of the Dock Panel Forms.
///
public List MainDockFormList
{
get { return _mainDockFormList; }
}
// new method for adding forms to main dock form - RVH20210328
public static void AddFormToDockPanelForm(Form childForm, string docFormText, string mainFormName, string mainFormTitle, string docPanelID)
{
// find top dock panel form
MainDockForm findDockForm = _dockPanelFormFocused;
// find dock panel form
if (findDockForm == null)
findDockForm = _mainDockFormList.Find(x => x.Name == mainFormName && x.Text == mainFormTitle);
// Make sure this dock window is visible.
if (null != findDockForm && !findDockForm.IsDisposed && !GuiEnvironment.KeepRestoredFormsHidden)
MakeFullyVisible(findDockForm);
// create new main dock form if it doesn't exist
if (findDockForm == null)
{
findDockForm = new MainDockForm();
findDockForm.Name = mainFormName;
findDockForm.Text = mainFormTitle;
LayoutManager.Instance().SetFormDefaultSizeAndLocation(findDockForm);
findDockForm.Show();
// add to list of forms
_mainDockFormList.Add(findDockForm);
}
else
{
if (findDockForm.IsDisposed)
{
int dockFormIndex = _mainDockFormList.IndexOf(findDockForm);
findDockForm = null;
findDockForm = new MainDockForm();
findDockForm.Name = mainFormName;
findDockForm.Text = mainFormTitle;
LayoutManager.Instance().SetFormDefaultSizeAndLocation(findDockForm);
findDockForm.Show();
if (dockFormIndex < _mainDockFormList.Count && _mainDockFormList.Count > 0)
_mainDockFormList[dockFormIndex] = findDockForm;
else
_mainDockFormList.Add(findDockForm);
}
else
{
findDockForm.Show();
}
}
// see if dock form is minimized and show it
if (findDockForm.WindowState == FormWindowState.Minimized)
{
//findDockForm.MinimizeRestoreCharts(false);
findDockForm.WindowState = FormWindowState.Normal;
}
// add child form to the dock form
findDockForm.AddChildForm(childForm, docFormText, docPanelID);
}
// new method to create a new empty dock panel form - RVH20210421
public MainDockForm CreateDockPanelForm(string mainFormName, string mainFormTitle)
{
// make sure the form name is unique
string tempFormName = mainFormName;
bool keepLooping = true;
int loopCt = 0;
do
{
// find dock panel form
MainDockForm findDockForm = _mainDockFormList.Find(x => x.Name == tempFormName && x.Text == mainFormTitle);
if (findDockForm != null)
tempFormName = mainFormName + loopCt++.ToString();
else
keepLooping = false;
} while (keepLooping);
mainFormName = tempFormName;
// create new dock form
MainDockForm newDockForm = new MainDockForm();
newDockForm.Name = mainFormName;
newDockForm.Text = mainFormTitle;
SetFormDefaultSizeAndLocation(newDockForm);
newDockForm.Show();
// add to list of forms
_mainDockFormList.Add(newDockForm);
return newDockForm;
}
private void SetFormDefaultSizeAndLocation(MainDockForm mainDockForm)
{
int left = 0;
int top = 77;
int widthAdjust = 100;
int heightAdjust = 100;
foreach (Form form in Application.OpenForms.Cast