OSDN Git Service

C# 8.0 のnull許容参照型を有効化
[opentween/open-tween.git] / OpenTween / OTBaseForm.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.Threading;
31 using System.Threading.Tasks;
32 using System.Windows.Forms;
33
34 namespace OpenTween
35 {
36     /// <summary>
37     /// OpenTween で使用する全てのフォームの基底となるクラス
38     /// </summary>
39     public class OTBaseForm : Form
40     {
41         /// <summary>
42         /// 全てのフォームで共通して使用する UI フォント
43         /// </summary>
44         /// <remarks>
45         /// SettingLocal.xml に FontUIGlobalStr 要素を追加する事で変更できます
46         /// </remarks>
47         public static Font? GlobalFont { get; set; }
48
49         /// <summary>
50         /// デザイン時のスケールと現在のスケールの比
51         /// </summary>
52         /// <remarks>
53         /// 例えば、デザイン時が 96 dpi (96.0, 96.0) で実行時が 120dpi (120.0, 120.0) の場合は 1.25, 1.25 が返ります
54         /// </remarks>
55         public SizeF CurrentScaleFactor { get; private set; }
56
57         private readonly SynchronizationContext synchronizationContext;
58
59         protected OTBaseForm()
60         {
61             this.CurrentScaleFactor = new SizeF(1.0f, 1.0f);
62             this.synchronizationContext = SynchronizationContext.Current;
63
64             this.Load += (o, e) =>
65             {
66                 // デフォルトの UI フォントを変更
67                 if (OTBaseForm.GlobalFont != null)
68                     this.Font = OTBaseForm.GlobalFont;
69             };
70         }
71
72         public Task InvokeAsync(Action x)
73             => this.InvokeAsync(new Func<int>(() => { x(); return 0; }));
74
75         public Task InvokeAsync(Func<Task> x)
76             => this.InvokeAsync<Task>(x).Unwrap();
77
78         public Task<T> InvokeAsync<T>(Func<Task<T>> x)
79             => this.InvokeAsync<Task<T>>(x).Unwrap();
80
81         /// <summary>
82         /// <see cref="Control.Invoke"/> メソッドのTask版みたいなやつ
83         /// </summary>
84         public Task<T> InvokeAsync<T>(Func<T> x)
85         {
86             var tcs = new TaskCompletionSource<T>();
87             this.synchronizationContext.Post(_ =>
88             {
89                 try
90                 {
91                     var ret = x();
92                     tcs.SetResult(ret);
93                 }
94                 catch (Exception ex)
95                 {
96                     tcs.SetException(ex);
97                 }
98             }, null);
99
100             return tcs.Task;
101         }
102
103         /// <summary>
104         /// source で指定されたフォントのスタイルを維持しつつ GlobalFont に置き換えた Font を返します
105         /// </summary>
106         protected Font ReplaceToGlobalFont(Font source)
107         {
108             if (OTBaseForm.GlobalFont == null)
109                 return source;
110
111             return new Font(OTBaseForm.GlobalFont.Name, source.Size, source.Style);
112         }
113
114         protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
115         {
116             base.ScaleControl(factor, specified);
117
118             const float baseDpi = 96.0f;
119
120             this.CurrentScaleFactor = new SizeF(
121                 this.CurrentAutoScaleDimensions.Width / baseDpi,
122                 this.CurrentAutoScaleDimensions.Height / baseDpi);
123         }
124
125         /// <summary>
126         /// 標準の ListView のスケーリングでは不十分な処理を補います
127         /// </summary>
128         public static void ScaleChildControl(ListView listview, SizeF factor)
129         {
130             // カラム幅
131             foreach (ColumnHeader col in listview.Columns)
132             {
133                 col.Width = ScaleBy(factor.Width, col.Width);
134             }
135         }
136
137         /// <summary>
138         /// 標準の VScrollBar のスケーリングでは不十分な処理を補います
139         /// </summary>
140         public static void ScaleChildControl(VScrollBar scrollBar, SizeF factor)
141             => scrollBar.Width = ScaleBy(factor.Width, scrollBar.Width);
142
143         /// <summary>
144         /// 標準の ImageList のスケーリングでは不十分な処理を補います
145         /// </summary>
146         public static void ScaleChildControl(ImageList imageList, SizeF factor)
147             => imageList.ImageSize = ScaleBy(factor, imageList.ImageSize);
148
149         public static Size ScaleBy(SizeF factor, Size size)
150             => Size.Round(new SizeF(size.Width * factor.Width, size.Height * factor.Height));
151
152         public static int ScaleBy(float factor, int size)
153             => (int)Math.Round(size * factor);
154     }
155 }