Beispiel #1
0
        /// <summary>
        /// 分岐棋譜の時だけ、「消分岐」「次分岐」ボタンを有効にする。
        /// </summary>
        private void UpdateButtonState()
        {
            using (var slb = new SuspendLayoutBlock(this))
            {
                var index = GetListViewSelectedIndex();
                var s     = index < 0 ? null : listView1.Items[index];
                if (s != null)
                {
                    var item = (s as ListViewItem).SubItems[0].Text;

                    // 本譜ボタン
                    var e = item.StartsWith(">");
                    button1.Enabled = e;

                    if (e)
                    {
                        item = item.Substring(1, 1); // 1文字目をskipして2文字目を取得
                    }
                    var e2 = item.StartsWith("+") || item.StartsWith("*");
                    button2.Enabled = e2;
                    button3.Enabled = e2;
                }
                // Items[0] == "開始局面"なので、そこ以降に指し手があればundo出来るのではないかと。(special moveであろうと)
                button4.Enabled = listView1.Items.Count > 1;
            }
        }
Beispiel #2
0
        // -- handlers

        /// <summary>
        /// [UI thread] : リストが1行追加されたときに呼び出されるハンドラ
        /// </summary>
        private void KifuListAdded(PropertyChangedEventArgs args)
        {
            using (var slb = new SuspendLayoutBlock(this))
            {
                // 増えた1行がargs.valueに入っているはず。
                var row = args.value as KifuListRow;

                listView1.ItemSelectionChanged -= listView1_ItemSelectionChanged;

                listView1.Items.Add(KifuListRowToListItem(row));

                ViewModel.KifuListCount = listView1.Items.Count;
                ViewModel.KifuList.Add(row); // ここも同期させておく。

                var lastIndex = listView1.Items.Count - 1;
                ViewModel.SetKifuListSelectedIndex(lastIndex);

                // 末尾の項目を選択しておく。
                SetListViewSelectedIndex(lastIndex);

                listView1.ItemSelectionChanged += listView1_ItemSelectionChanged;

                // item数が変化したはずなので、「消一手」ボタンなどを更新する。
                UpdateButtonState();
            }
        }
Beispiel #3
0
 /// <summary>
 /// ViewModel.InTheGameの値が変更になったときに呼び出されるハンドラ
 /// </summary>
 /// <param name="args"></param>
 private void InTheGameChanged(PropertyChangedEventArgs args)
 {
     using (var s = new SuspendLayoutBlock(this))
     {
         UpdateButtonLocation();
         UpdateButtonState();
     }
 }
Beispiel #4
0
        /// <summary>
        /// リサイズ。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void KifuControl_SizeChanged(object sender, EventArgs e)
        {
            if (TheApp.app.DesignMode)
            {
                return;
            }

            // メインウインドウに埋め込み時もフォント固定する。
            //if (ViewModel.DockState != DockState.InTheMainWindow)

            using (var slb = new SuspendLayoutBlock(this))
            {
                UpdateButtonLocation();
                UpdateListViewColumnWidth();
            }
        }
Beispiel #5
0
        /// <summary>
        /// ListViewの4列目(総消費時間)を残りいっぱいサイズにする。
        ///
        /// ※ 4列目を表示していない時は3列目が残り幅いっぱいになるようにする。
        /// </summary>
        private void UpdateListViewColumnWidth()
        {
            var col = listView1.Columns;

            // Column 生成前
            if (col.Count == 0)
            {
                return;
            }

            using (var sbc = new SuspendLayoutBlock(this))
            {
                var last = enable_total_time ? 3 : 2;
                var sum  = 0; //  listView1.Margin.Left + listView1.Margin.Right;
                foreach (var i in All.Int(last))
                {
                    sum += col[i].Width;
                }

                // これ、ちゃんと設定してやらないと水平スクロールバーが出てきてしまう。
                // ClientSizeはスクロールバーを除外したサイズ。
                // → スクロールバーが出ていない状態で計算して、
                // そのあとスクロールバーが出ると困るのだが…。押し戻す処理をするか。
                // スクロールバーを常に表示するモードがないので、スクロールバーが出ているならその分を控えて計算するか。

                // スクロールバーが10pxより小さいことはありえないので、それを超えているならスクロールバーが出ている。

                /*
                 * var scrollbar = listView1.Width - listView1.ClientSize.Width > 10;
                 * var width = scrollbar ?
                 *  listView1.ClientSize.Width :
                 *  listView1.ClientSize.Width - 22; // 実測でこれくらい high dpiだと変わるかも..
                 */
                // → これやめる。スクロールバーが出るとClientSizeが変化するのだから、そのときリサイズイベントが起きるのでは。

                var width    = listView1.ClientSize.Width;
                var newWidth = Math.Max(width - sum, 0);

                // Widthにはマイナスの値を設定しても0に補整される。この結果、上のMax()がないと、newWidthがマイナスだと
                // このifは成立してしまい、代入によってイベントが生起されるので無限再帰となる。
                if (col[last].Width != newWidth)
                {
                    col[last].Width = newWidth; //残りいっぱい分にする
                }
            }
        }
        // 持ち時間が減っていくときに、持ち時間の部分だけの再描画をしたいのでそのためのフラグ
        //public bool DirtyRestTime
        //{
        //    get { return ViewModel.dirtyRestTime; }
        //}

        /// <summary>
        /// [UI thread] : Formのリサイズに応じて棋譜コントロールの移動などを行う。
        /// </summary>
        public void ResizeKifuControl()
        {
            var kifu = kifuControl;

            if (kifu.ViewModel.DockState == DockState.InTheMainWindow)
            {
                using (var slb = new SuspendLayoutBlock(kifu))
                {
                    // (起動時) 先にLocationを移動させておかないとSizeの変更で変なところに表示されて見苦しい。
                    // ※ 理由はよくわからない。DockStyle.Noneにした影響か何か。
                    kifu.Size     = Size.Empty; // resizeイベントが生起するようにいったん(0,0)にする。
                    kifu.Location = CalcKifuWindowLocation();
                    kifu.Size     = CalcKifuWindowSize();
                }
            }

            // 駒台が縦長のモードのときは、このコントロールは非表示にする。
            // (何か別の方法で描画する)
            UpdateKifuControlVisibility();
        }
Beispiel #7
0
        /// <summary>
        /// 検討ウインドウのControlのサイズを調整。
        /// (このウインドウに埋め込んでいるとき)
        /// </summary>
        public void ResizeConsiderationControl(PropertyChangedEventArgs args = null)
        {
            if (first_tick)
            {
                return;
            }
            // first_tick前だとengineConsiderationMainControl == nullだったりしてまずいのだ。

            // 検討ウインドウをこのウインドウに埋め込んでいるときに、検討ウインドウをリサイズする。
            using (var slb1 = new SuspendLayoutBlock(this))
                using (var slb2 = new SuspendLayoutBlock(gameScreenControl1))
                {
                    int w = ClientSize.Width;
                    int h = ClientSize.Height - gameScreenControl1.Location.Y; // メニューとToolStripの高さを引き算する。

                    var config      = TheApp.app.Config;
                    var dockManager = config.EngineConsiderationWindowDockManager;

                    // 非表示のときはないものとして扱う。
                    // すなわち、DockWindow側にあるものとして、gameScreenControl1をDockStyle.Fillにする必要がある。

                    if (dockManager.DockState == DockState.InTheMainWindow && dockManager.Visible)
                    {
                        // メインウインドウに埋め込み時の検討ウインドウ高さの倍率
                        float height_rate = 1 + 0.25f * config.ConsiderationWindowHeightType;

                        // 検討ウインドウの縦幅
                        var ch = (int)(height_rate * h / 4);

                        DockUtility.Change(gameScreenControl1, DockStyle.None, new Size(w, h - ch), null /*いまの場所*/);
                        DockUtility.Change(engineConsiderationMainControl, DockStyle.None, new Size(w, ch), new Point(0, ClientSize.Height - ch));
                    }
                    else
                    {
                        DockUtility.Change(gameScreenControl1, DockStyle.Fill, new Size(w, h), null);
                        DockUtility.Change(engineConsiderationMainControl, DockStyle.Fill, null, null);
                    }
                }
        }
Beispiel #8
0
        private void InitView()
        {
#if false
            var file_name =
                TheApp.app.Config.CommercialVersion == 0 ?
                "html/about_dialog_opensource_version.html" :
                "html/about_dialog_commercial_version.html";

            webBrowser1.Navigate(Path.Combine(Application.StartupPath, file_name).ToString());

            // -- バージョン文字列をJavaScript経由でインジェクションする。

            // 1回メッセージループを処理しないとNavigate()が終わらない。
            Application.DoEvents();

            var version_string = "MyShogi Version " + GlobalConfig.MYSHOGI_VERSION_STRING;
            webBrowser1.Document.InvokeScript("add_version_string", new string[] { version_string });
#endif

            // → Mac/Linuxで動作しないのでWebBrowserを使わない実装に変更。

            using (var slb = new SuspendLayoutBlock(this))
            {
                var commercial = TheApp.app.Config.CommercialVersion;
                var message1   = "MyShogi Version " + GlobalConfig.MYSHOGI_VERSION_STRING;
                var message2   =
                    commercial == 0 ?
                    "MyShogiは、2018年にマイナビ出版から発売する『将棋神やねうら王』用のGUIとして開発をスタートしました。" +
                    "オープンソースの将棋ソフト用GUIです。(ただし画面素材等の単体配布、流用は不可です。)\r\n" +
                    "MyShogi Project: https://github.com/yaneurao/MyShogi"
                    : "(C)2018 Mynavi Publishing Corporation / MyShogi Project\r\nMyShogi Project : https://github.com/yaneurao/MyShogi";

                label1.Text   = message1;
                textBox1.Text = message2;

                pictureBox1.Image = TheApp.app.ImageManager.GameLogo.image;
            }
        }
        /// <summary>
        /// 最後のDispatchした時刻。
        /// </summary>
        //private Stopwatch lastDispatchTime = new Stopwatch();

        /// <summary>
        /// [UI thread] : 一定時間ごとに(MainDialogなどのidle状態のときに)このメソッドを呼び出す。
        ///
        /// queueに積まれているUsiThinkReportMessageを処理する。
        /// </summary>
        public void OnIdle()
        {
#if false
            // 前回dispatch(≒表示)してから200[ms]以上経過するまでメッセージをbufferingしておく。
            // (このメソッドが呼び出されるごとに1つずつメッセージが増えているような状況は好ましくないため)
            if (lastDispatchTime.ElapsedMilliseconds < 200)
            {
                return;
            }
#endif

            var queue = thinkQuque.GetList();
            if (queue.Count > 0)
            {
                using (var slb = new SuspendLayoutBlock(this))
                {
                    // 子コントロールも明示的にSuspendLayout()~ResumeLayout()しないといけないらしい。
                    // Diagnosing Performance Problems with Layout : https://blogs.msdn.microsoft.com/jfoscoding/2005/03/04/suggestions-for-making-your-managed-dialogs-snappier/
                    foreach (var c in All.Int(2))
                    {
                        ConsiderationInstance(c).SuspendLayout();
                    }

                    // → これでも処理、間に合わないぎみ
                    // 以下、メッセージのシュリンクを行う。

                    // 要らない部分をskipDisplay == trueにしてしまう。
                    // j : 前回のNumberOfInstanceの位置(ここ以降しか見ない)

                    for (int i = 0, j = 0; i < queue.Count; ++i)
                    {
                        var e = queue[i];
                        switch (e.type)
                        {
                        case UsiEngineReportMessageType.NumberOfInstance:
                            // ここ以前のやつ要らん。
                            for (var k = j; k < i; ++k)
                            {
                                queue[k].skipDisplay = true;
                            }
                            j = i;
                            break;

                        case UsiEngineReportMessageType.SetRootSfen:
                            // rootが変わるので、以前のrootに対する思考内容は不要になる。
                            for (var k = j; k < i; ++k)
                            {
                                var q = queue[k];
                                var t = q.type;
                                if ((t == UsiEngineReportMessageType.SetRootSfen || t == UsiEngineReportMessageType.UsiThinkReport) &&
                                    q.number == e.number
                                    )
                                {
                                    q.skipDisplay = true;
                                }
                            }
                            j = i;
                            break;
                        }
                    }

                    foreach (var e in queue)
                    {
                        DispatchThinkReportMessage(e);
                    }

                    foreach (var c in All.Int(2))
                    {
                        ConsiderationInstance(c).ResumeLayout();
                    }
                }
            }

#if false
            // 次回に呼び出された時のためにDispatchした時刻からの時間を計測する。
            lastDispatchTime.Reset();
            lastDispatchTime.Start();
#endif
        }
Beispiel #10
0
        /// <summary>
        /// [UI thread] : 内部状態が変わったのでボタンの有効、無効を更新するためのハンドラ。
        ///
        /// ViewModel.InTheGameが変更になった時に呼び出される。
        /// </summary>
        /// <param name="inTheGame"></param>
        private void UpdateButtonLocation()
        {
            // 最小化したのかな?
            if (Width == 0 || Height == 0 || listView1.ClientSize.Width == 0)
            {
                return;
            }

            using (var slb = new SuspendLayoutBlock(this))
            {
                UpdateListViewColumnWidth();

                var inTheGame = ViewModel.InTheGame;

                // 非表示だったものを表示したのであれば、これによって棋譜が隠れてしまう可能性があるので注意。
                //var needScroll = !button1.Visible && !inTheGame;

                // ボタンの表示は対局外のときのみ
                button1.Visible = !inTheGame;
                button2.Visible = !inTheGame;
                button3.Visible = !inTheGame;
                button4.Visible = !inTheGame;

                // フォントサイズ変更ボタンが有効か
                // 「+」「-」ボタンは、メインウインドウに埋め込んでいないときのみ
                // → やめよう メインウインドウ埋め込み時も有効にしよう。
                var font_button_enable = !inTheGame; // && ViewModel.DockState != DockState.InTheMainWindow;

                button5.Visible = font_button_enable;
                button6.Visible = font_button_enable;

                // -- ボタンなどのリサイズ

                // ボタン高さ

                // 対局中は非表示。
                int bh = button1.Height;
                int x  = font_button_enable ? Width / 5 : Width / 4;
                int y  = button1.Visible ? Height - bh : Height;

                listView1.Location = new Point(0, 0);
                listView1.Size     = new Size(Width, y);

                if (!inTheGame)
                {
                    button1.Location = new Point(x * 0, y);
                    button1.Size     = new Size(x, bh);
                    button2.Location = new Point(x * 1, y);
                    button2.Size     = new Size(x, bh);
                    button3.Location = new Point(x * 2, y);
                    button3.Size     = new Size(x, bh);
                    button4.Location = new Point(x * 3, y);
                    button4.Size     = new Size(x, bh);

                    button5.Location = new Point(x * 4, y);
                    button5.Size     = new Size(x / 2, bh);
                    button6.Location = new Point((int)(x * 4.5), y);
                    button6.Size     = new Size(x / 2, bh);
                }

                //if (needScroll)
                {
                    // 選択行が隠れていないことを確認しなければ..。
                    // SelectedIndexを変更すると、SelectedIndexChangedイベントが発生してしまうので良くない。
                    // 現在は、対局が終了した瞬間であるから、棋譜の末尾に移動して良い。
                    //SetListViewSelectedIndex(listView1.Items.Count - 1);
                    // → こことは限らない。DockWindow化しただけかも知れない。

                    var index = ViewModel.KifuListSelectedIndex;
                    EnsureVisible(index);
                }
            }
        }