OmegaChartのソースコードの保守
Rev. | abec95183e38adccdd3ae834f0e303862ebeff62 |
---|---|
サイズ | 17,923 バイト |
日時 | 2022-12-15 22:48:19 |
作者 | panacoran |
ログメッセージ | Yahooファイナンスからの株価取得が途中で止まるのを回避
|
/*
* Copyright (c) Daisuke OKAJIMA All rights reserved.
*
* $Id$
*/
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using Zanetti.Indicators;
using Zanetti.Data;
using Zanetti.Forms;
namespace Zanetti.UI
{
/// <summary>
/// </summary>
internal class ChartCanvas : System.Windows.Forms.UserControl
{
private AbstractBrand _brand;
private ChartDrawing _drawing;
private ChartTitle _title;
private System.Windows.Forms.HScrollBar _scrollBar;
private Label _complementaryLabel;
private int _diffX = 0;
private int _diffY = 0;
private int _destX = 0;
private int _pivotX = 0;
private int _destY = 0;
private int _pivotY = 0;
/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;
public ChartCanvas()
{
// この呼び出しは、Windows.Forms フォーム デザイナで必要です。
InitializeComponent();
// TODO: InitializeComponent 呼び出しの後に初期化処理を追加します。
this.BackColor = Env.Preference.BackBrush.Color;
this.SetStyle(ControlStyles.AllPaintingInWmPaint|ControlStyles.DoubleBuffer, true);
_drawing = new ChartDrawing(this);
}
/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region コンポーネント デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this._scrollBar = new System.Windows.Forms.HScrollBar();
_title = new ChartTitle();
this.SuspendLayout();
//
// _scrollBar
//
this._scrollBar.Dock = System.Windows.Forms.DockStyle.Bottom;
this._scrollBar.Enabled = false;
this._scrollBar.LargeChange = 2;
this._scrollBar.Location = new System.Drawing.Point(0, 83);
this._scrollBar.Maximum = 4;
this._scrollBar.Name = "_scrollBar";
this._scrollBar.Size = new System.Drawing.Size(100, 17);
this._scrollBar.TabIndex = 0;
this._scrollBar.ValueChanged += new System.EventHandler(this.OnScrollBarValueChanged);
_title.Location = new Point(0, 0);
_title.Size = new Size(this.Width, Env.Layout.HeaderHeight);
//
// ChartCanvas
//
this.Controls.Add(this._scrollBar);
this.Controls.Add(this._title);
this.MouseUp += new MouseEventHandler(OnMouseUp);
this.Name = "ChartCanvas";
this.Size = new System.Drawing.Size(100, 100);
this.ResumeLayout(false);
_title.BringToFront();
}
#endregion
public Label ComplementaryLabel {
get {
if(_complementaryLabel==null) {
_complementaryLabel = new Label();
_complementaryLabel.Visible = false;
_complementaryLabel.Font = Env.Preference.DefaultFont;
_complementaryLabel.TextAlign = ContentAlignment.MiddleLeft;
_complementaryLabel.BorderStyle = BorderStyle.FixedSingle;
_complementaryLabel.BackColor = Color.FromKnownColor(KnownColor.Info);
_complementaryLabel.ForeColor = Color.FromKnownColor(KnownColor.InfoText);
this.Controls.Add(_complementaryLabel);
}
return _complementaryLabel;
}
}
public ChartTitle ChartTitle {
get {
return _title;
}
}
public ChartDrawing DrawingEngine {
get {
return _drawing;
}
}
public int BodyHeight {
get {
return this.Height - _scrollBar.Height;
}
}
public void LoadBrand(AbstractBrand br, bool preserve_date) {
int date = -1;
if(preserve_date && _brand!=null) {
DataFarm f = _brand.ReserveFarm();
if(!f.IsEmpty) {
Debug.Assert(_drawing.FirstDateIndex>=0 && _drawing.FirstDateIndex<f.TotalLength);
if(_drawing.FirstDateIndex + Env.Layout.DisplayColumnCount >= f.TotalLength)
date = -1; //最終データが見えているときは「最後が見えている」状態を維持
else
date = f.GetByIndex(_drawing.FirstDateIndex).Date;
}
}
_brand = br;
AdjustScrollBar();
if(_scrollBar.Enabled) {
DataFarm f = br.ReserveFarm();
int v = date==-1? GetTotalDataLength() - Env.Layout.DisplayColumnCount : f.DateToIndex(date);
if(v<0) v = 0;
if(v>_scrollBar.Maximum-_scrollBar.LargeChange+1) v = _scrollBar.Maximum-_scrollBar.LargeChange+1;
_scrollBar.Value = v;
}
_drawing.SetBrand(br);
//_title.InitUI();
}
public AbstractBrand GetBrand() {
return _brand;
}
public int FirstDateIndex {
get {
return _drawing.FirstDateIndex;
}
}
public void MoveToLatest() {
AdjustScrollBar();
int v = 0;
if(_scrollBar.Enabled) v = GetTotalDataLength() - Env.Layout.DisplayColumnCount;
if(v<0) v = 0;
_scrollBar.Value = v;
Invalidate(false);
}
public void SetDateIndex(int first, int cursor) {
_scrollBar.Value = first;
DataFarm f = _brand.ReserveFarm();
if(f.IsEmpty)
_drawing.UpdateDateLineIndex(-1);
else
_drawing.UpdateDateLineIndex(Math.Min(cursor, f.FilledLength-1));
Invalidate(true);
}
public void ForceVisibleDate(int date, bool cut) {
DataFarm f = _brand.ReserveFarm();
if(f.IsEmpty) return;
int index = f.DateToIndex(date);
//スクロールしないと見えない
if(_drawing.FirstDateIndex>index || index>=_drawing.FirstDateIndex+Env.Layout.DisplayColumnCount || cut) {
int nv = index - Env.Layout.DisplayColumnCount/2; //大体真ん中に表示
if(nv<0) nv = 0;
if(nv>=f.TotalLength) nv = f.TotalLength-1;
_scrollBar.Value = nv;
}
_drawing.UpdateDateLineIndex(index);
Invalidate(false);
}
public void ReloadFromPreference() {
Preference pref = Env.Preference;
Color bc = pref.BackBrush.Color;
Color fc = pref.TextColor;
this.BackColor = bc;
this.ForeColor = fc;
if(_complementaryLabel!=null) _complementaryLabel.Font = pref.DefaultFont;
//InitOscillatorGroupUI();
_drawing.ClearScale();
}
public void ResetLayout() {
//_oscillatorGroup.Visible = Env.Options.ShowOscillator;
AdjustScrollBar(); //これは価格帯出来高の表示設定が変化したときだけでもよい
_drawing.ClearScale();
_title.InitUI();
}
//メッセージ処理がらみ
protected override void OnLoad(EventArgs e) {
base.OnLoad (e);
Preference pref = Env.Preference;
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint (e);
if(this.DesignMode || _brand==null) return;
_drawing.PaintMain(e.Graphics, e.ClipRectangle);
if(_currentFreeLine!=null && _currentFreeLine.PivotHasEnoughDistanceTo(this.PointToClient(Control.MousePosition))) {
IntPtr hdc = e.Graphics.GetHdc();
_currentFreeLine.Draw(Env.Layout.ChartBodyRect, hdc);
e.Graphics.ReleaseHdc(hdc);
}
}
protected override void OnResize(EventArgs e) {
base.OnResize (e);
if(!this.DesignMode && _drawing!=null && _brand!=null && Env.Frame.WindowState!=FormWindowState.Minimized) {
bool last_is_visible = !_scrollBar.Enabled || _scrollBar.Value+_scrollBar.LargeChange>=_scrollBar.Maximum;
_drawing.ClearScale();
AdjustScrollBar();
this.SuspendLayout();
Preference pref = Env.Preference;
//_oscillatorGroup.Top = this.BodyHeight - _oscillatorGroup.Height - 8;
//_oscillatorGroup.Left = this.Width - Env.Layout.RemarkAreaWidth+5;
if(!_brand.ReserveFarm().IsEmpty && last_is_visible) { //最新データ見えているときのリサイズはその状態を維持
int v = _brand.ReserveFarm().TotalLength - Env.Layout.DisplayColumnCount;
if(v<0) v = 0;
_scrollBar.Value = v; //このままValueChangedイベントも誘発
}
Invalidate(false);
this.ResumeLayout();
}
}
protected override void OnMouseMove(MouseEventArgs ev) {
base.OnMouseMove (ev);
if(_drawing==null) return;
Preference pref = Env.Preference;
//隠れてしまうIndicatorテキストの表示・非表示
Point p = new Point(ev.X, ev.Y);//this.PointToClient(Control.MousePosition);
if(_complementaryLabel!=null && _complementaryLabel.Visible) {
if(!new Rectangle(_complementaryLabel.Location, _complementaryLabel.Size).Contains(p))
_complementaryLabel.Visible = false;
}
else {
ArrayList ar = _drawing.TipEntries;
if(ar!=null) {
foreach(ComplementaryTextEntry e in ar) {
if(e.rect.Contains(p)) {
Label l = this.ComplementaryLabel;
l.Location = new Point(e.rect.X-2, e.rect.Y-1);
l.Size = new Size(e.rect.Size.Width+5, e.rect.Size.Height+2);
l.Text = e.text;
l.Visible = true;
l.BringToFront();
l.Invalidate();
break;
}
}
}
}
int offset = -1;
if(p.X >= 0 && p.X < Env.Layout.ChartAreaWidth) {
offset = (p.X-Env.Layout.CandleMiddleOffset) / Env.Layout.DatePitch;
DataFarm farm = _brand.ReserveFarm();
if(!farm.IsEmpty && _drawing.FirstDateIndex+offset>=farm.TotalLength) offset = -1;
}
//横線
if(Env.Preference.MouseTrackingLineMode==MouseTrackingLineMode.Full) {
int my = _drawing.NormalizeByYobine(ev.Y);
if(my!=_drawing.PriceLine._lastDrawn) {
int h = Env.Layout.DefaultTextHeight;
Rectangle yr = new Rectangle(0, _drawing.PriceLine._lastDrawn-h/2, this.Width, h);
Invalidate(yr, false);
yr = new Rectangle(0, my-h/2, this.Width, h);
Invalidate(yr, false);
}
_drawing.PriceLine._nextToBeDrawn = my;
}
//必要なエリアのInvalidate
int ld = _drawing.DateLine._lastDrawn;
if(offset==-1) {
if(ld!=-1) {
Rectangle r = Env.Layout.CurrentValueRect;
Invalidate(r, false);
int t = ld - _drawing.FirstDateIndex;
r = new Rectangle((t-1)*Env.Layout.DatePitch, 0, Env.Layout.DatePitch*2, this.Height);
Invalidate(r, false);
}
_drawing.UpdateDateLineIndex(-1);
}
else {
if(_drawing.FirstDateIndex+offset!=ld) {
Rectangle r = Env.Layout.CurrentValueRect;
//r.X += ChartDrawing.VALUEWINDOW_HEADER_WIDTH;
Invalidate(r, false);
//価格帯出来高
if(Env.Preference.ShowAccumulativeVolume)
Invalidate(Env.Layout.AccumulativeVolumeRect, false);
//節の数値のこともあるので広めにInvalidateする
if(ld!=-1) {
int t = ld - _drawing.FirstDateIndex;
//Debug.WriteLine(String.Format("prev offset={0}", t));
r = new Rectangle((t-1)*Env.Layout.DatePitch, 0, Env.Layout.DatePitch*2, this.Height);
Invalidate(r, false);
}
r = new Rectangle((offset-1)*Env.Layout.DatePitch, 0, Env.Layout.DatePitch*2, this.Height);
Invalidate(r, false);
}
_drawing.UpdateDateLineIndex(_drawing.FirstDateIndex + offset);
}
//今引いている直線の再描画
if(_currentFreeLine!=null) {
Invalidate(_currentFreeLine.GetInclusion(this.ClientRectangle), false);
_currentFreeLine.Destination = p;
}
//左クリックしながら、マウスを動かした場合、コピー中と見なす。
if (_diffX != 0 && _diffY != 0 && ev.Button == MouseButtons.Left && Win32.GetAsyncKeyState(System.Windows.Forms.Keys.ShiftKey) < 0 & 0x8000 != 0)
{
_currentFreeLine = new FreeLine(new Point(ev.X, ev.Y), new Point(ev.X - _diffX, ev.Y - _diffY));
}
//Controlキーを押しながら、マウスで左クリックしている時は、ピボット・コピー中と見なす。
if (_diffX != 0 && _diffY != 0 && ev.Button == MouseButtons.Left && Win32.GetAsyncKeyState(System.Windows.Forms.Keys.ControlKey) < 0 & 0x8000 != 0)
{
int x, y = 0;
if (_pivotX < _destX)//画面左から右へと引いたフリーライン
{
if ((_pivotX + _destX) / 2 > ev.X)//軸となる点は旧_dest
{
x = _destX;
y = _destY;
}
else//軸となる点は旧_pivot
{
x = _pivotX;
y = _pivotY;
}
}
else//画面右から左へと引いたフリーライン
{
if ((_pivotX + _destX) / 2 > ev.X)//軸となる点は旧_pivot
{
x = _pivotX;
y = _pivotY;
}
else//軸となる点は旧_dest
{
x = _destX;
y = _destY;
}
}
_currentFreeLine = new FreeLine(new Point(x, y), new Point(ev.X, ev.Y));
}
//接近した線があればそれをクリア
bool near_line_found = false;
foreach(FreeLine line in _drawing.FreeLines) {
double d = line.GetDistance(p);
FreeLine.LineDrawMode m = d<3? FreeLine.LineDrawMode.Hilight : FreeLine.LineDrawMode.Normal;
if(line.DrawMode!=m) {
line.DrawMode = m;
Invalidate(line.GetInclusion(this.ClientRectangle), false);
}
if(!near_line_found) near_line_found = m==FreeLine.LineDrawMode.Hilight;
}
this.Cursor = near_line_found? Cursors.Hand : Cursors.Default;
}
private void OnMouseUp(object sender, MouseEventArgs args) {
if(args.Button==MouseButtons.Right) {
ContextMenu m = Env.Frame.CreateContextMenu();
m.Show(this, new Point(args.X, args.Y));
}
else if(args.Button==MouseButtons.Left) {
if(_currentFreeLine!=null) {
if(_drawing.FreeLineCount==10) {
Util.Warning(Env.Frame, "線は1銘柄につき10本までしか引けません");
Invalidate();
}
else if(Env.FreeLines.Count==1000) {
Util.Warning(Env.Frame, "線は全部で1000本までしか引けません");
Invalidate();
}
else if(_currentFreeLine.PivotHasEnoughDistanceTo(_currentFreeLine.Destination)) {
_drawing.FixFreeLine(_currentFreeLine);
}
_currentFreeLine = null;
}
if(_drawing.RemoveHighlitedFreeLines()) Invalidate(); //削除されたやつがあればInvalidate
}
}
protected override bool IsInputChar(char charCode) {
return false;
}
private void AdjustScrollBar() {
if(_brand==null || _brand.ReserveFarm().IsEmpty) {
_scrollBar.Enabled = false;
}
else {
Preference pref = Env.Preference;
int total = GetTotalDataLength();
int display = Env.Layout.DisplayColumnCount;
if(display>=total) {
_scrollBar.Enabled = false;
_scrollBar.Value = 0;
_drawing.FirstDateIndex = 0;
}
else {
int v = _scrollBar.Value;
_scrollBar.LargeChange = display;
_scrollBar.Maximum = total-1;
//Debug.WriteLine(String.Format("Adjusted disp={0} all={1} v={2}", display, all, v));
if(v > _scrollBar.Maximum - display) _scrollBar.Value = _scrollBar.Maximum - display + 1;
_scrollBar.Enabled = true;
}
}
}
private int GetTotalDataLength() {
return _brand.ReserveFarm().TotalLength;
}
private void OnScrollBarValueChanged(object sender, EventArgs args) {
if(this.DesignMode) return;
int v = _scrollBar.Value;
_drawing.FirstDateIndex = v;
//Debug.WriteLine(String.Format("ValueChange max={0} lc={1} v={2}", _scrollBar.Maximum, _scrollBar.LargeChange, v));
_drawing.ClearScale();
Invalidate();
}
/*
private void OnOscillatorGroupCheckedChanged(object sender, EventArgs args) {
int i = _oscillatorGroupBoxes.IndexOf(sender);
Debug.Assert(i!=-1);
_drawing.OscillatorGroup = Env.CurrentIndicators.GetOscillatorGroupAt(i);
Invalidate();
}
*/
//FreeLine関係
private FreeLine _currentFreeLine;
protected override void OnMouseDown(MouseEventArgs e) {
base.OnMouseDown (e);
if(e.Button==MouseButtons.Left){
if(_brand.ReserveFarm().IsEmpty) return;
foreach (FreeLine line in _drawing.FreeLines)
{
if (line.DrawMode == FreeLine.LineDrawMode.Hilight && e.Button == MouseButtons.Left)
{
_diffX = line.Destination.X - line.Pivot.X;
_diffY = line.Destination.Y - line.Pivot.Y;
_destX = line.Destination.X;
_destY = line.Destination.Y;
_pivotX = line.Pivot.X;
_pivotY = line.Pivot.Y;
}
}
_currentFreeLine = new FreeLine(new Point(e.X, e.Y));
}
}
protected override void OnDoubleClick(EventArgs e)
{
base.OnDoubleClick(e);
var ev = (MouseEventArgs)e;
_currentFreeLine = new FreeLine(new Point(0, ev.Y), new Point(ev.X, ev.Y));
}
public void ClearCurrentFreeLine() {
if(_currentFreeLine!=null) {
Invalidate(_currentFreeLine.GetInclusion(Env.Layout.ChartBodyRect), false);
_currentFreeLine = null;
}
}
//DOJIMA用半日足修正
#if DOJIMA
protected override void OnDoubleClick(EventArgs e) {
base.OnDoubleClick (e);
if(Env.CurrentIndicators.Format!=ChartFormat.HalfDaily) return;
int index = _drawing.DateLine._lastDrawn;
DailyDataFarm f = _brand.ReserveFarm() as DailyDataFarm;
if(index<0 || index>=f.FilledLength) return;
Dojima.ModifyHalfDayData dlg = new Dojima.ModifyHalfDayData();
dlg.InitUI(f.GetByIndex(index), Dojima.DojimaUtil.HalfDailyDataFarmCache.Get(f), index);
if(dlg.ShowDialog(Env.Frame)==DialogResult.OK) {
Invalidate(true); //全画面再描画
}
}
#endif
}
}