Annotation of nono/wx/wxsubwindow.cpp, revision 1.1.1.11

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.7   root        7: //
                      8: // サブウィンドウ
                      9: //
1.1.1.11! root       10: // wxWindow::SetSizeHints() の挙動がアレなのに対応するハック付き。
1.1.1.7   root       11: 
1.1       root       12: #include "wxsubwindow.h"
1.1.1.7   root       13: #include "fontmanager.h"
1.1.1.2   root       14: #include "wxmainframe.h"
1.1.1.3   root       15: #include "wxtextscreen.h"
1.1       root       16: 
                     17: //
1.1.1.7   root       18: // サブウィンドウ (基本クラス)
1.1       root       19: //
                     20: 
1.1.1.11! root       21: //#define WINDOW_DEBUG 1
        !            22: 
        !            23: #if defined(WINDOW_DEBUG)
        !            24: #define DPRINTF(fmt...) printf(fmt)
        !            25: #else
        !            26: #define DPRINTF(fmt...) /**/
        !            27: #endif
        !            28: 
1.1       root       29: // イベントテーブル
                     30: wxBEGIN_EVENT_TABLE(WXSubWindow, inherited)
                     31:        EVT_CLOSE(WXSubWindow::OnClose)
                     32: wxEND_EVENT_TABLE()
                     33: 
1.1.1.5   root       34: // コンストラクタ
1.1       root       35: WXSubWindow::WXSubWindow(wxWindow *parent, wxWindowID id, const wxString& name,
                     36:        int style)
1.1.1.5   root       37:        : inherited(parent, id, name, wxDefaultPosition, wxDefaultSize, style)
1.1       root       38: {
                     39: }
                     40: 
                     41: // デストラクタ
                     42: WXSubWindow::~WXSubWindow()
                     43: {
                     44: }
                     45: 
                     46: // クローズイベント
                     47: void
                     48: WXSubWindow::OnClose(wxCloseEvent& event)
                     49: {
                     50:        // ウィンドウリストから自身を削除
1.1.1.9   root       51:        auto mainframe = dynamic_cast<WXMainFrame*>(GetParent());
                     52:        mainframe->DeleteWindow(this);
1.1       root       53: }
1.1.1.2   root       54: 
1.1.1.7   root       55: // フォントサイズ変更
1.1.1.3   root       56: void
1.1.1.7   root       57: WXSubWindow::FontChanged()
1.1.1.3   root       58: {
1.1.1.7   root       59:        // WXTextPanel 派生の子コントロールに対し FontChanged() を呼ぶ
                     60:        for (auto child : GetChildren()) {
                     61:                auto textpanel = dynamic_cast<WXTextPanel*>(child);
1.1.1.3   root       62:                if (textpanel) {
1.1.1.7   root       63:                        textpanel->FontChanged();
1.1.1.3   root       64:                }
                     65:        }
                     66: 
1.1.1.10  root       67:        Fit();
1.1.1.7   root       68: }
                     69: 
1.1.1.11! root       70: // 自前レイアウト方式を使うことを宣言する。
        !            71: // ついでに必要な SetAutoLayout() も実行しておく。
        !            72: // おそらくコンストラクタで使うことになるはず。
        !            73: void
        !            74: WXSubWindow::SetMyLayout()
        !            75: {
        !            76:        my_layout = true;
        !            77: 
        !            78:        SetAutoLayout(true);
        !            79: }
        !            80: 
        !            81: // 中身の状況に応じてこのウィンドウの大きさを変更。
        !            82: //  1) 自前方式か
        !            83: //  2) このウィンドウに top sizer が指定されているか
        !            84: //  3) 子コントロールが1つしかないか
        !            85: // のいずれかの場合に使える。
1.1.1.10  root       86: //
1.1.1.11! root       87: // コントロールが複数あって上記のいずれでもない場合は、コントロールを
        !            88: // どう配置するのか決定できないので、assert する。
1.1.1.7   root       89: void
1.1.1.10  root       90: WXSubWindow::Fit()
1.1.1.7   root       91: {
                     92:        wxSize csize;
                     93: 
1.1.1.11! root       94:        if (my_layout) {
        !            95:                // 1) 自前方式なら継承先がサイズを知っている。
        !            96:                csize = DoMySizeHints();
        !            97:                assert(csize.x > 0);
        !            98:                assert(csize.y > 0);
1.1.1.7   root       99:        } else {
1.1.1.11! root      100:                auto *topsizer = GetSizer();
        !           101:                if (topsizer) {
        !           102:                        // 2) Sizer があればそれがサイズを知っている。
        !           103:                        csize = topsizer->ComputeFittingClientSize(this);
        !           104:                } else {
        !           105:                        // 3) どちらでもない場合、子コントロールが1人なら対応出来る。
        !           106:                        // これはネイティブの Fit() と等価のはず。
        !           107:                        auto& children = GetChildren();
        !           108:                        assert(children.GetCount() == 1);
        !           109:                        auto child = children[0];
        !           110:                        csize = child->GetSize();
        !           111:                }
1.1.1.7   root      112:        }
                    113:        SetClientSize(csize);
1.1.1.3   root      114: }
1.1.1.11! root      115: 
        !           116: // サイズが変わった場合に呼ばれて、子コントロールの再配置を行う。
        !           117: bool
        !           118: WXSubWindow::Layout()
        !           119: {
        !           120:        if (my_layout) {
        !           121:                return MyLayout();
        !           122:        } else {
        !           123:                return inherited::Layout();
        !           124:        }
        !           125: }
        !           126: 
        !           127: // 自前方式の時の Layout()。
        !           128: // 何度か呼び出されて仕事をしないと適切なサイズになってくれないため。
        !           129: //
        !           130: // Layout() は何かしたら true を返すので、ここもそれに倣う。
        !           131: // MyLayout() が何かしたら true を返すので継承側は何もせずに true を返すこと。
        !           132: // MyLayout() が false を返したら、継承側は子コントロールを配置してよい。
        !           133: // その場合も呼び出し元には true を返すこと
        !           134: // つまり、継承側はこうなるはず。
        !           135: //  bool Children::Layout() {
        !           136: //    if (MyLayout() == false) {
        !           137: //      ここで子コントロールを配置。
        !           138: //    }
        !           139: //    return true;
        !           140: //  }
        !           141: bool
        !           142: WXSubWindow::MyLayout()
        !           143: {
        !           144:        wxSize client = GetClientSize();
        !           145:        const wxSize& win = GetSize();
        !           146:        const wxSize& border = win - client;
        !           147: 
        !           148:        if (border != prev_border) {
        !           149:                // ウィンドウマネージャ管轄のサイズが変わったので最小サイズを再設定。
        !           150:                my_layout_pass2 = true;
        !           151:                prev_border = border;
        !           152:                // ここでは出来ないのでこの関数を抜けた後 CallAfter 内で設定する。
        !           153:                CallAfter([this]() {
        !           154:                        DoMySizeHints();
        !           155:                });
        !           156:                return true;
        !           157: 
        !           158:        } else if (my_layout_pass2) {
        !           159:                // SetSizeHints() 後に呼ばれるところ。
        !           160:                // なぜか設定したサイズと変わっている(ことがある?)ので、その場合は
        !           161:                // 仕方ないのでここで元の要求サイズに再設定する。
        !           162:                // ウィンドウマネージャによっては表示サイズが変わらない(?)ので
        !           163:                // Hide()/Show() で叩き起こすと直るようだ??。
        !           164:                my_layout_pass2 = false;
        !           165:                DPRINTF("%s ClientSize(%d,%d)->", __method__, client.x, client.y);
        !           166:                GetMySizeHints(&client, NULL, NULL, NULL);
        !           167:                DPRINTF("(%d,%d)\n", client.x, client.y);
        !           168:                SetClientSize(client);
        !           169: 
        !           170:                Hide();
        !           171:                Show();
        !           172: 
        !           173:                DPRINTF("%s done(pass2)\n", __method__);
        !           174:                return true;
        !           175:        }
        !           176: 
        !           177:        // ここまで来るとようやくコントロールを再配置を継承側で行える。
        !           178:        // それを示すため false を返す。
        !           179:        // wxTopLevelWindow::Layout() は何かすれば true、
        !           180:        // sizer がないか子コントロールが複数あって何も出来ることがない場合は
        !           181:        // false を返すと書いてあるので都合よく借りておく。
        !           182:        DPRINTF("%s done false\n", __method__);
        !           183:        return false;
        !           184: }
        !           185: 
        !           186: // SetSizeHints() を実行して、希望するクライアントサイズを返す。
        !           187: // 自前方式に対応していない場合は何もせず wxDefaultSize を返す。
        !           188: wxSize
        !           189: WXSubWindow::DoMySizeHints()
        !           190: {
        !           191:        wxSize newsize;
        !           192:        wxSize minsize;
        !           193:        wxSize maxsize;
        !           194:        wxSize incsize;
        !           195: 
        !           196:        if (GetMySizeHints(&newsize, &minsize, &maxsize, &incsize)) {
        !           197:                wxSize minwin = ClientToWindowSize(minsize);
        !           198:                wxSize maxwin = ClientToWindowSize(maxsize);
        !           199:                SetSizeHints(minwin, maxwin, incsize);
        !           200:                return newsize;
        !           201:        } else {
        !           202:                // 対応していない。
        !           203:                return wxDefaultSize;
        !           204:        }
        !           205: }
        !           206: 
        !           207: // 自前方式のサイズに関する情報を取得する。
        !           208: // 継承先で用意すること。ここにあるのは継承しなかった時の何もしない版。
        !           209: //
        !           210: // 継承側はそれぞれ以下の値を書き戻して true を返す。
        !           211: // *newsz は希望するクライアントサイズ。子コントロールの配置とサイズで決まる。
        !           212: // *minsz は最小クライアントサイズ。指定しないなら (-1, -1)。
        !           213: // *maxsz は最大クライアントサイズ。指定しないなら (-1, -1)。
        !           214: // *incsz はウィンドウサイズ変更時の増減サイズ。
        !           215: // newsz, minsz, maxsz, incsz はいずれも NULL でなければ代入する。
        !           216: bool
        !           217: WXSubWindow::GetMySizeHints(wxSize *newsz, wxSize *minsz, wxSize *maxsz,
        !           218:        wxSize *incsz)
        !           219: {
        !           220:        return false;
        !           221: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.