OSDN Git Service

ステータスバーに各タブの更新回数(起動時からの回数)の表示を追加
[opentween/open-tween.git] / OpenTween / ToolStripAPIGauge.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2013 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
4 //
5 // This file is part of OpenTween.
6 //
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
10 // any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 // for more details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 #nullable enable
23
24 using System;
25 using System.Collections.Generic;
26 using System.ComponentModel;
27 using System.Drawing;
28 using System.Linq;
29 using System.Text;
30 using System.Windows.Forms;
31 using System.Windows.Forms.Design;
32 using OpenTween.Api;
33
34 namespace OpenTween
35 {
36     /// <summary>
37     /// API 実行回数制限に到達するまでの目安を表示する ToolStripItem
38     /// </summary>
39     [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All)]
40     public class ToolStripAPIGauge : ToolStripStatusLabel
41     {
42         public ToolStripAPIGauge()
43         {
44             this.UpdateText();
45
46             this.DisplayStyle = ToolStripItemDisplayStyle.Text;
47         }
48
49         /// <summary>
50         /// ゲージに表示される横棒グラフの幅
51         /// </summary>
52         [DefaultValue(8)]
53         [RefreshProperties(RefreshProperties.Repaint)]
54         public int GaugeHeight
55         {
56             get => this.gaugeHeight;
57             set
58             {
59                 this.gaugeHeight = value;
60
61                 this.UpdateGaugeBounds();
62                 this.Invalidate();
63             }
64         }
65
66         private int gaugeHeight = 8;
67
68         /// <summary>
69         /// API 実行回数制限の値
70         /// </summary>
71         [Browsable(false)]
72         public ApiLimit? ApiLimit
73         {
74             get => this.apiLimit;
75             private set
76             {
77                 this.apiLimit = value;
78
79                 this.UpdateRemainMinutes();
80                 this.UpdateText();
81                 this.UpdateGaugeBounds();
82                 this.Invalidate();
83             }
84         }
85
86         private ApiLimit? apiLimit = null;
87
88         /// <summary>
89         /// API エンドポイント名
90         /// </summary>
91         [Browsable(false)]
92         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
93         public string? ApiEndpoint
94         {
95             get => this.apiEndpoint;
96             set
97             {
98                 if (MyCommon.IsNullOrEmpty(value))
99                 {
100                     // リセット
101                     this.apiEndpoint = null;
102                     this.ApiLimit = null;
103                     return;
104                 }
105
106                 var apiLimit = MyCommon.TwitterApiInfo.AccessLimit[value];
107
108                 if (this.apiEndpoint != value)
109                 {
110                     // ApiEndpointが変更されているので更新する
111                     this.apiEndpoint = value;
112                     this.ApiLimit = apiLimit;
113                 }
114                 else
115                 {
116                     // ApiLimitが変更されていれば更新する
117                     if (this.apiLimit == null ||
118                         !this.apiLimit.Equals(apiLimit))
119                     {
120                         this.ApiLimit = apiLimit;
121                     }
122                 }
123             }
124         }
125
126         private string? apiEndpoint = null;
127
128         [Browsable(false)]
129         [EditorBrowsable(EditorBrowsableState.Never)]
130         public new string Text
131         {
132             get => base.Text;
133             set => base.Text = value;
134         }
135
136         [Browsable(false)]
137         [EditorBrowsable(EditorBrowsableState.Never)]
138         public new string ToolTipText
139         {
140             get => base.ToolTipText;
141             set => base.ToolTipText = value;
142         }
143
144         [DefaultValue(ToolStripItemDisplayStyle.Text)]
145         [RefreshProperties(RefreshProperties.Repaint)]
146         public new ToolStripItemDisplayStyle DisplayStyle
147         {
148             get => base.DisplayStyle;
149             set => base.DisplayStyle = value;
150         }
151
152         protected double remainMinutes = -1;
153
154         protected virtual void UpdateRemainMinutes()
155         {
156             if (this.apiLimit != null)
157                 this.remainMinutes = (this.apiLimit.AccessLimitResetDate - DateTimeUtc.Now).TotalMinutes;
158             else
159                 this.remainMinutes = -1;
160         }
161
162         protected override void OnPaint(PaintEventArgs e)
163         {
164             var g = e.Graphics;
165
166             if (this.ApiGaugeBounds != Rectangle.Empty)
167                 g.FillRectangle(Brushes.LightBlue, this.ApiGaugeBounds);
168
169             if (this.TimeGaugeBounds != Rectangle.Empty)
170                 g.FillRectangle(Brushes.LightPink, this.TimeGaugeBounds);
171
172             base.OnPaint(e);
173         }
174
175         #region from Tween v1.1.0.0
176
177         // The code in this region block is based on code written by the following authors:
178         //   (C) 2010 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
179         //   (C) 2010 Moz (@syo68k)
180
181         internal Rectangle ApiGaugeBounds = Rectangle.Empty;
182         internal Rectangle TimeGaugeBounds = Rectangle.Empty;
183
184         protected virtual void UpdateGaugeBounds()
185         {
186             if (this.apiLimit == null || this.gaugeHeight < 1)
187             {
188                 this.ApiGaugeBounds = Rectangle.Empty;
189                 this.TimeGaugeBounds = Rectangle.Empty;
190                 return;
191             }
192
193             var apiGaugeValue = (double)this.apiLimit.AccessLimitRemain / this.apiLimit.AccessLimitCount;
194             this.ApiGaugeBounds = new Rectangle(
195                 0,
196                 (this.Height - this.gaugeHeight * 2) / 2,
197                 (int)(this.Width * apiGaugeValue),
198                 this.gaugeHeight
199             );
200
201             var timeGaugeValue = this.remainMinutes >= 15 ? 1.00 : this.remainMinutes / 15;
202             this.TimeGaugeBounds = new Rectangle(
203                 0,
204                 this.ApiGaugeBounds.Top + this.gaugeHeight,
205                 (int)(this.Width * timeGaugeValue),
206                 this.gaugeHeight
207             );
208         }
209
210         protected virtual void UpdateText()
211         {
212             string remainCountText;
213             string maxCountText;
214             string minuteText;
215
216             if (this.apiLimit == null || this.remainMinutes < 0)
217             {
218                 remainCountText = "???";
219                 maxCountText = "???";
220                 minuteText = "???";
221             }
222             else
223             {
224                 remainCountText = this.apiLimit.AccessLimitRemain.ToString();
225                 maxCountText = this.apiLimit.AccessLimitCount.ToString();
226                 minuteText = Math.Ceiling(this.remainMinutes).ToString();
227             }
228
229             var endpointText = MyCommon.IsNullOrEmpty(this.apiEndpoint) ? "unknown" : this.apiEndpoint;
230
231             var textFormat = "API {0}/{1}";
232             this.Text = string.Format(textFormat, remainCountText, maxCountText);
233
234             var toolTipTextFormat =
235                 "API rest {0} {1}/{2}" + Environment.NewLine +
236                 "(reset after {3} minutes)";
237
238             this.ToolTipText = string.Format(toolTipTextFormat, endpointText, remainCountText, maxCountText, minuteText);
239         }
240
241         #endregion
242     }
243 }