Annotation of nono/wx/wxscrollbar.cpp, revision 1.1.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.