--- nono/wx/wxscrollbar.cpp 2026/04/29 17:05:16 1.1.1.2 +++ nono/wx/wxscrollbar.cpp 2026/04/29 17:05:19 1.1.1.3 @@ -60,7 +60,6 @@ #define BORDER_LT (2) // 上(左) 側のフチのピクセル数 #define BORDER_RB (1) // 下(右) 側のフチのピクセル数 -#define THUMB_MIN (8) // つまみの最小サイズ (ピクセル) // 通知イベント。 // このコントロールがつまみの位置を変更した場合にイベントが発生する。 @@ -91,6 +90,8 @@ WXScrollBar::WXScrollBar(wxWindow *paren is_vertical = true; } + FontChanged(); + timer.SetOwner(this); } @@ -99,6 +100,41 @@ WXScrollBar::~WXScrollBar() { } +// フォントサイズ変更 +void +WXScrollBar::FontChanged() +{ + inherited::FontChanged(); + + int newpx; + switch (font_height) { + case 12: + newpx = 16; + break; + case 16: + newpx = 20; + break; + case 24: + newpx = 32; + break; + default: + PANIC("Unexpected font_height=%d", font_height); + } + + // つまみの最小サイズ。適当に幅の半分。 + thumbmin = newpx / 2; + + // コントロールの大きさを変更 + wxSize size = GetClientSize(); + if (is_vertical) { + size.x = newpx; + } else { + size.y = newpx; + } + SetClientSize(size); + SetMinClientSize(size); +} + // スクロールバーのパラメータを設定する。 // 通知イベントは送出しない。 // @@ -119,29 +155,20 @@ WXScrollBar::SetScrollParam(int pos_, in // つまみの位置を設定する。外部インタフェース。 // 通知イベントは送出しない。 -void +// つまみが移動すれば true を、移動しなければ false を返す。 +bool WXScrollBar::SetThumbPosition(int pos) { - thumbpos = pos; - DPRINTF("SetThumbPosition: %d\n", pos); - - // 単位位置の範囲チェック - if (thumbpos < 0) { - thumbpos = 0; - } else if (thumbpos > range - thumbsize) { - thumbpos = range - thumbsize; - } - - RefreshThumb(); -} - -// つまみの位置を計算して再描画。 -void -WXScrollBar::RefreshThumb() -{ // パラメータセット前に OnSize されるとここに来る if (range < 1) { - return; + return false; + } + + // 単位位置の範囲チェック + if (pos < 0) { + pos = 0; + } else if (pos > range - thumbsize) { + pos = range - thumbsize; } // 通常の描画座標は単位値とピクセル数の単純な比で求まる。 @@ -153,7 +180,7 @@ WXScrollBar::RefreshThumb() // +---+-----------------+---+ // // つまみが描画領域に対して小さすぎる場合、ある程度より小さくならないよう - // に抑制する (THUMB_MIN [px])。 + // に抑制する (thumbmin [px])。 // 例えばここで描画範囲が 50px の場合、つまみの最小サイズは 8px なので // 単位可動域 0-90 を 0-42 ピクセルにマッピングし直して描画する。 // @@ -162,20 +189,22 @@ WXScrollBar::RefreshThumb() // つまみが小さくなりすぎるのを防ぐ int thumbsize_px = thumbsize * range_px / range; - if (thumbsize_px < THUMB_MIN) { - thumbsize_px = THUMB_MIN; + if (thumbsize_px < thumbmin) { + thumbsize_px = thumbmin; } // range はスクロールバー領域全体の長さ (図の 100)。 // mrange はつまみの大きさを含まない可動域?の長さ (図の 90) とする。 // [p1, p2) がつまみのピクセル座標。 + int oldp1 = p1; + int oldp2 = p2; int mrange = range - thumbsize; if (mrange == 0) { // つまみが全体を占めていると可動域 mrange が 0 になる。 p1 = 0; } else { int mrange_px = range_px - thumbsize_px; - p1 = thumbpos * mrange_px / mrange; + p1 = pos * mrange_px / mrange; } p2 = p1 + thumbsize_px; @@ -183,20 +212,26 @@ WXScrollBar::RefreshThumb() p1 += BORDER_LT; p2 += BORDER_LT; - DPRINTF("RefreshThumb: p1=%d p2=%d\n", p1, p2); + // 移動していない (表示位置が変わっていない) なら false で帰る。 + // 目一杯を占めていて移動できないつまみをドラッグしてマウス移動 + // しても、つまみが移動しないのだから、スクロールも起こさないため。 + DPRINTF("SetThumbPosition: oldpos=%d newpos=%d oldp=%d-%d p=%d-%d\n", + thumbpos, pos, oldp1, oldp2, p1, p2); + if (p1 == oldp1 && p2 == oldp2) { + return false; + } + thumbpos = pos; + DPRINTF("SetThumbPosition: new pos=%d\n", thumbpos); Refresh(); + return true; } // つまみの位置を pos に設定し、移動すれば通知イベントを送出する。(内部用) void WXScrollBar::MoveThumb(int pos) { - int old = thumbpos; - - SetThumbPosition(pos); - - if (thumbpos != old) { + if (SetThumbPosition(pos)) { // Orientation は wx"SB_"VERTICAL ではなく wxVERTICAL のほう。 // (値は同じっぽいからいいけど、どうしてこうなった…) int orient = is_vertical ? wxVERTICAL : wxHORIZONTAL; @@ -206,6 +241,13 @@ WXScrollBar::MoveThumb(int pos) } } +// コントロールの主方向(スクロール方向)の最小ピクセル数を返す +int +WXScrollBar::GetMinLength() const +{ + return thumbmin + BORDER_LT + BORDER_RB; +} + // サイズイベント void WXScrollBar::OnSize(wxSizeEvent& event) @@ -223,7 +265,7 @@ WXScrollBar::OnSize(wxSizeEvent& event) } // range_px が変わったので再描画 - RefreshThumb(); + SetThumbPosition(thumbpos); } // マウスイベント