Annotation of nono/wx/wxscrollbar.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2021 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: //
        !             8: // 独自スクロールバー
        !             9: //
        !            10: 
        !            11: // GTK のスクロールバーが色々残念なので、独自コントロールを作る。
        !            12: //
        !            13: // pos、thumbsize、range、pagesize は wxScrollBar のそれと同じなのでそちら参照。
        !            14: // 例えば全体で100要素あるうち画面に10要素分だけ表示できる構成の場合、
        !            15: // range = 100、thumbsize = 10 となる。表示位置は、一番上(左)の要素から表示
        !            16: // している場合は pos = 0、一番下(右)の要素まで表示している場合は pos = 90。
        !            17: //
        !            18: //  0    10                90  100
        !            19: //  +---+-----------------+---+
        !            20: //
        !            21: // ピクセル座標では、上(左)に 2ピクセル、下(右)に1ピクセルのフチがある。
        !            22: // そのため range として使える領域は bitmap.GetHeight() (または GetWidth())
        !            23: // から 3 引いたサイズになる。
        !            24: //
        !            25: // 左フチ  つまみ     右フチ
        !            26: //  +--+  ●----○      ++
        !            27: //   0 1  p1    p2      h-1
        !            28: //  明□□□□□□□□□明
        !            29: //  明□□■■ □□□□明
        !            30: //  明□□■■ □□□□明
        !            31: //  明□□   □□□□明
        !            32: //  明明明明明明明明明明明
        !            33: //
        !            34: // 明明明明明 0   <- 上フチ
        !            35: // □□□□明 1   <- 上フチ
        !            36: // □□□□明
        !            37: // □■■ 明 p1 ●
        !            38: // □■■ 明    | つまみ
        !            39: // □   明    |
        !            40: // □□□□明 p2 ○
        !            41: // □□□□明
        !            42: // □□□□明
        !            43: // 明明明明明 h-1 <- 下フチ
        !            44: //
        !            45: // 明 = UD_LIGHT_GREY
        !            46: // □ = UD_GREY
        !            47: // ■ = BGPANEL
        !            48: //   = UD_BLACK
        !            49: 
        !            50: #include "wxscrollbar.h"
        !            51: #include "wxcolor.h"
        !            52: 
        !            53: //#define SCROLL_DEBUG 1
        !            54: 
        !            55: #if defined(SCROLL_DEBUG)
        !            56: #define DPRINTF(fmt...) printf(fmt)
        !            57: #else
        !            58: #define DPRINTF(fmt...) /**/
        !            59: #endif
        !            60: 
        !            61: #define BORDER_LT      (2)             // 上(左) 側のフチのピクセル数
        !            62: #define BORDER_RB      (1)             // 下(右) 側のフチのピクセル数
        !            63: #define THUMB_MIN      (8)             // つまみの最小サイズ (ピクセル)
        !            64: 
        !            65: // 通知イベント。
        !            66: // このコントロールがつまみの位置を変更した場合にイベントが発生する。
        !            67: // SetThumbPosition() などでコードが能動的に変更した場合は発生しない。
        !            68: // イベントの内容は概ね wxScrollEvent 準拠のはず。
        !            69: // ただし、引数は wxScrollEvent だが、イベントタイプは EVT_SCROLL_* では
        !            70: // なく wxCommandEvent の NONO_EVT_SCROLL を使用していること、
        !            71: // wxScrollBar と異なり自動的に親かだれかにイベントが飛んでこないので
        !            72: // 必要な人が適宜 Connect() する必要がある、ところが異なる。
        !            73: wxDEFINE_EVENT(NONO_EVT_SCROLL, wxScrollEvent);
        !            74: 
        !            75: // イベントテーブル
        !            76: wxBEGIN_EVENT_TABLE(WXScrollBar, inherited)
        !            77:        EVT_SIZE(WXScrollBar::OnSize)
        !            78:        EVT_MOUSE_EVENTS(WXScrollBar::OnMouse)
        !            79: wxEND_EVENT_TABLE()
        !            80: 
        !            81: // コンストラクタ
        !            82: //
        !            83: // style は wxSB_VERTICAL か wxSB_HORIZONTAL。
        !            84: // 本家の wxScrollBar は style のデフォルトが wxSB_HORIZONTAL だが、
        !            85: // うちではデフォルト引数にはしない。
        !            86: WXScrollBar::WXScrollBar(wxWindow *parent, wxWindowID id, long style)
        !            87:        : inherited(parent, id, wxSize(16, 16), 0)
        !            88: {
        !            89:        if (style == wxSB_VERTICAL) {
        !            90:                is_vertical = true;
        !            91:        }
        !            92: }
        !            93: 
        !            94: // デストラクタ
        !            95: WXScrollBar::~WXScrollBar()
        !            96: {
        !            97: }
        !            98: 
        !            99: // スクロールバーのパラメータを設定する。
        !           100: // 通知イベントは送出しない。
        !           101: //
        !           102: // 各パラメータは wxScrollBar::SetScrollbar() 準拠のはずなのでそちら参照。
        !           103: // SetScrollbar() は wxScrollBar ではなく wxWindow の仮想関数で、ここで定義
        !           104: // すると微妙に型が違うオーバーライドになってしまうため、名前を変えてある。
        !           105: void
        !           106: WXScrollBar::SetScrollParam(int pos_, int thumbsize_, int range_, int pagesize_)
        !           107: {
        !           108:        DPRINTF("SetScrollParam: pos=%d thumbsize=%d range=%d pagesize=%d\n",
        !           109:                pos_, thumbsize_, range_, pagesize_);
        !           110: 
        !           111:        thumbsize = thumbsize_;
        !           112:        range = range_;
        !           113:        pagesize = pagesize_;
        !           114:        SetThumbPosition(pos_);
        !           115: }
        !           116: 
        !           117: // つまみの位置を設定する。外部インタフェース。
        !           118: // 通知イベントは送出しない。
        !           119: void
        !           120: WXScrollBar::SetThumbPosition(int pos)
        !           121: {
        !           122:        thumbpos = pos;
        !           123:        DPRINTF("SetThumbPosition: %d\n", pos);
        !           124: 
        !           125:        // 単位位置の範囲チェック
        !           126:        if (thumbpos < 0) {
        !           127:                thumbpos = 0;
        !           128:        } else if (thumbpos > range - thumbsize) {
        !           129:                thumbpos = range - thumbsize;
        !           130:        }
        !           131: 
        !           132:        RefreshThumb();
        !           133: }
        !           134: 
        !           135: // つまみの位置を計算して再描画。
        !           136: void
        !           137: WXScrollBar::RefreshThumb()
        !           138: {
        !           139:        // パラメータセット前に OnSize されるとここに来る
        !           140:        if (range < 1) {
        !           141:                return;
        !           142:        }
        !           143: 
        !           144:        // 通常の描画座標は単位値とピクセル数の単純な比で求まる。
        !           145:        //
        !           146:        //  0    10                90  100 [unit]
        !           147:        //  +---+-----------------+---+
        !           148:        //
        !           149:        //  0    20                180 200 [px]
        !           150:        //  +---+-----------------+---+
        !           151:        //
        !           152:        // つまみが描画領域に対して小さすぎる場合、ある程度より小さくならないよう
        !           153:        // に抑制する (THUMB_MIN [px])。
        !           154:        // 例えばここで描画範囲が 50px の場合、つまみの最小サイズは 8px なので
        !           155:        // 単位可動域 0-90 を 0-42 ピクセルにマッピングし直して描画する。
        !           156:        //
        !           157:        //  0    5 8            42 45  50 [px]
        !           158:        //  +---+-+-------------+-+---+
        !           159: 
        !           160:        // つまみが小さくなりすぎるのを防ぐ
        !           161:        int thumbsize_px = thumbsize * range_px / range;
        !           162:        if (thumbsize_px < THUMB_MIN) {
        !           163:                thumbsize_px = THUMB_MIN;
        !           164:        }
        !           165: 
        !           166:        // range はスクロールバー領域全体の長さ (図の 100)。
        !           167:        // mrange はつまみの大きさを含まない可動域?の長さ (図の 90) とする。
        !           168:        // [p1, p2) がつまみのピクセル座標。
        !           169:        int mrange = range - thumbsize;
        !           170:        if (mrange == 0) {
        !           171:                // つまみが全体を占めていると可動域 mrange が 0 になる。
        !           172:                p1 = 0;
        !           173:        } else {
        !           174:                int mrange_px = range_px - thumbsize_px;
        !           175:                p1 = thumbpos * mrange_px / mrange;
        !           176:        }
        !           177:        p2 = p1 + thumbsize_px;
        !           178: 
        !           179:        // 可動域の上(左)に2ピクセルの枠がある
        !           180:        p1 += BORDER_LT;
        !           181:        p2 += BORDER_LT;
        !           182: 
        !           183:        DPRINTF("RefreshThumb: p1=%d p2=%d\n", p1, p2);
        !           184: 
        !           185:        Refresh();
        !           186: }
        !           187: 
        !           188: // つまみの位置を pos に設定し、移動すれば通知イベントを送出する。(内部用)
        !           189: void
        !           190: WXScrollBar::MoveThumb(int pos)
        !           191: {
        !           192:        int old = thumbpos;
        !           193: 
        !           194:        SetThumbPosition(pos);
        !           195: 
        !           196:        if (thumbpos != old) {
        !           197:                // Orientation は wx"SB_"VERTICAL ではなく wxVERTICAL のほう。
        !           198:                // (値は同じっぽいからいいけど、どうしてこうなった…)
        !           199:                int orient = is_vertical ? wxVERTICAL : wxHORIZONTAL;
        !           200:                wxScrollEvent newev(NONO_EVT_SCROLL, GetId(), thumbpos, orient);
        !           201:                newev.SetEventObject(this);
        !           202:                AddPendingEvent(newev);
        !           203:        }
        !           204: }
        !           205: 
        !           206: // サイズイベント
        !           207: void
        !           208: WXScrollBar::OnSize(wxSizeEvent& event)
        !           209: {
        !           210:        auto s __unused = event.GetSize();
        !           211:        DPRINTF("OnSize %d,%d\n", s.x, s.y);
        !           212: 
        !           213:        // 親クラス
        !           214:        inherited::OnSize(event);
        !           215: 
        !           216:        if (is_vertical) {
        !           217:                range_px = bitmap.GetHeight() - BORDER_LT - BORDER_RB;
        !           218:        } else {
        !           219:                range_px = bitmap.GetWidth() - BORDER_LT - BORDER_RB;
        !           220:        }
        !           221: 
        !           222:        // range_px が変わったので再描画
        !           223:        RefreshThumb();
        !           224: }
        !           225: 
        !           226: // マウスイベント
        !           227: void
        !           228: WXScrollBar::OnMouse(wxMouseEvent& event)
        !           229: {
        !           230:        wxPoint pos = event.GetPosition();
        !           231: 
        !           232:        event.Skip();
        !           233: 
        !           234:        int wheel = event.GetWheelRotation();
        !           235:        if (wheel != 0) {
        !           236:                DPRINTF("OnMouse: wheel=%d\n", wheel);
        !           237: 
        !           238:                // ホイールは1回で +-120 が飛んでくる。
        !           239:                // どこのルールか分からんけどだいたい3行分の移動としているようなので
        !           240:                // ここでも踏襲する。
        !           241:                MoveThumb(thumbpos - wheel / 40);
        !           242:        }
        !           243: 
        !           244:        if (event.LeftDown() || event.LeftDClick()) {
        !           245:                // 左クリック。間隔が速いとダブルクリックになる。
        !           246:                // ダブルクリックは LeftDown, LeftUp, LeftDClick, LeftUp の順で来る
        !           247:                // ので、LeftDown と LeftDClick を同列で扱っておく。
        !           248:                int r = PosCmp(pos);
        !           249:                if (r == 0) {
        !           250:                        // つまみ内左クリックでは何も起きないが、
        !           251:                        // ドラッグ用に左クリック開始時点の位置を保存。
        !           252:                        start_thumb = thumbpos;
        !           253:                        if (is_vertical) {
        !           254:                                start_px = pos.y;
        !           255:                        } else {
        !           256:                                start_px = pos.x;
        !           257:                        }
        !           258:                        DPRINTF("OnMouse: LeftDown start_pos=%d px=%d\n",
        !           259:                                start_thumb, start_px);
        !           260:                } else {
        !           261:                        // つまみ外の下地部分ならページアップ、ページダウン
        !           262:                        DPRINTF("OnMouse: LeftDown cmp=%d\n", r);
        !           263:                        MoveThumb(thumbpos + r * pagesize);
        !           264:                }
        !           265:        }
        !           266: 
        !           267:        if (event.Dragging()) {
        !           268:                // ドラッグ開始時からの差分を求めて..
        !           269:                int delta;
        !           270:                if (is_vertical) {
        !           271:                        delta = pos.y - start_px;
        !           272:                } else {
        !           273:                        delta = pos.x - start_px;
        !           274:                }
        !           275:                DPRINTF("OnMouse: Dragging delta=%d\n", delta);
        !           276: 
        !           277:                // ピクセルでの移動量を変換
        !           278:                MoveThumb(start_thumb + delta * range / range_px);
        !           279:        }
        !           280: }
        !           281: 
        !           282: // pt がつまみ内なら 0 を、つまみより上(左)なら -1、下(右)なら 1 を返す。
        !           283: int
        !           284: WXScrollBar::PosCmp(const wxPoint& pt) const
        !           285: {
        !           286:        int p;
        !           287: 
        !           288:        if (is_vertical) {
        !           289:                p = pt.y;
        !           290:        } else {
        !           291:                p = pt.x;
        !           292:        }
        !           293: 
        !           294:        if (p < p1) {
        !           295:                return -1;
        !           296:        }
        !           297:        if (p >= p2) {
        !           298:                return 1;
        !           299:        }
        !           300:        return 0;
        !           301: }
        !           302: 
        !           303: // 描画
        !           304: void
        !           305: WXScrollBar::Draw()
        !           306: {
        !           307:        const int& w = bitmap.GetWidth();
        !           308:        const int& h = bitmap.GetHeight();
        !           309: 
        !           310:        if (is_vertical) {
        !           311:                // 背景
        !           312:                bitmap.DrawLineH(UD_LIGHT_GREY, 0, 0, w);
        !           313:                bitmap.DrawLineH(UD_LIGHT_GREY, 0, h - 1, w);
        !           314:                bitmap.DrawLineV(UD_LIGHT_GREY, w - 1, 1, h - 1);
        !           315:                bitmap.FillRect(UD_GREY, 0, 1, w - 1, h - 2);
        !           316: 
        !           317:                // つまみ
        !           318:                bitmap.FillRect(BGPANEL, 1, p1, w - 4, p2 - p1 - 1);
        !           319:                bitmap.DrawLineH(UD_BLACK, 1, p2 - 1, w - 1);
        !           320:                bitmap.DrawLineV(UD_BLACK, w - 2, p1, p2);
        !           321:        } else {
        !           322:                // 背景
        !           323:                bitmap.DrawLineV(UD_LIGHT_GREY, 0, 0, h);
        !           324:                bitmap.DrawLineV(UD_LIGHT_GREY, w - 1, 0, h);
        !           325:                bitmap.DrawLineH(UD_LIGHT_GREY, 1, h - 1, w - 1);
        !           326:                bitmap.FillRect(UD_GREY, 1, 0, w - 2, h - 1);
        !           327: 
        !           328:                // つまみ
        !           329:                bitmap.FillRect(BGPANEL, p1, 1, p2 - p1 - 1, h - 4);
        !           330:                bitmap.DrawLineV(UD_BLACK, p2 - 1, 1, h - 1);
        !           331:                bitmap.DrawLineH(UD_BLACK, p1, h - 2, p2);
        !           332:        }
        !           333: }

unix.superglobalmegacorp.com

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