|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2022 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // 独自ボタン
9: //
10:
11: #include "wxbutton.h"
12: #include "wxcolor.h"
13:
14: // 通知イベント。
15: // このボタンが押された時にイベントが発生する。
16: // 引数は wxCommandEvent だが、イベントタイプは EVT_BUTTON ではなく
17: // NONO_EVT_BUTTON を使用していることが異なる。
18: wxDEFINE_EVENT(NONO_EVT_BUTTON, wxCommandEvent);
19:
20: // イベント
21: wxBEGIN_EVENT_TABLE(WXButton, inherited)
1.1.1.2 ! root 22: EVT_SIZE(WXButton::OnSize)
1.1 root 23: EVT_MOUSE_EVENTS(WXButton::OnMouse)
24: EVT_TIMER(wxID_ANY, WXButton::OnTimer)
25: wxEND_EVENT_TABLE()
26:
27: // コンストラクタ
28: WXButton::WXButton(wxWindow *parent, wxWindowID id,
29: const wxSize& size, const wxString& text, const wxPoint& position)
30: : inherited(parent, id, position, size)
31: {
1.1.1.2 ! root 32: SetName("Button[" + text + "]");
! 33:
1.1 root 34: // テキストを SJIS に変換し std::string として保存しておく
35: wxCSConv conv("SJIS");
36: sjistext = text.mb_str(conv);
37:
38: timer.SetOwner(this);
39:
40: FontChanged();
41: }
42:
43: // デストラクタ
44: WXButton::~WXButton()
45: {
46: }
47:
48: bool
49: WXButton::Enable(bool enable_)
50: {
51: // 無効にするとイベントが来なくなるため、
52: // 押し下げた状態で無効にする場合は押し下げを解放してからにする。
53: if (enable_ == false && IsPressed()) {
54: Press(false);
55: }
56:
57: return inherited::Enable(enable_);
58: }
59:
60: void
61: WXButton::FontChanged()
62: {
63: inherited::FontChanged();
64:
1.1.1.2 ! root 65: // テキスト部分のメトリックはここで決まる。
1.1 root 66: textsize.x = sjistext.size() * font_width;
67: textsize.y = font_height;
68:
1.1.1.2 ! root 69: Fit();
! 70:
! 71: // テキストサイズが変わったのでキャンバスを一旦破棄。
1.1 root 72: Fill();
1.1.1.2 ! root 73: Refresh();
! 74: }
! 75:
! 76: void
! 77: WXButton::Fit()
! 78: {
! 79: // 現在のテキストが入る最小サイズを求める。
! 80: // テキストの上下左右 2ピクセルずつがボタン描画用のスペース。
! 81: wxSize minsize(textsize.x + 2 + 2, textsize.y + 2 + 2);
! 82:
! 83: // バックバッファのサイズを固定。
! 84: SetMinBitmapSize(minsize);
! 85:
! 86: // 最小サイズの影響を受けさせる。
! 87: SetMinSize(minsize);
! 88: wxSize size = GetSize();
! 89: size.x = std::max(size.x, minsize.x);
! 90: size.y = std::max(size.y, minsize.y);
! 91: if (size != GetSize()) {
! 92: SetSize(size);
! 93: }
! 94: }
! 95:
! 96: void
! 97: WXButton::OnSize(wxSizeEvent& event)
! 98: {
! 99: // サイズが変わったらセンタリングを維持。
! 100: const wxSize size = event.GetSize();
! 101: textpos.x = (size.x - textsize.x) / 2;
! 102: textpos.y = (size.y - textsize.y) / 2;
! 103:
! 104: event.Skip();
1.1 root 105: }
106:
107: void
108: WXButton::OnMouse(wxMouseEvent& event)
109: {
110: if (event.LeftDown() || event.LeftDClick()) {
111: // ボタンを押して..
112: Press(true);
113:
114: // 押しっぱなし判定のためタイマーを開始。
115: timer.Start(500);
116: }
117: if (event.LeftUp()) {
118: Press(false);
119: }
120: }
121:
122: // タイマーイベント
123: void
124: WXButton::OnTimer(wxTimerEvent& event)
125: {
126: if (IsPressed()) {
127: // 左クリックが続いていたらもう一度
128: Press(true);
129:
130: // キーリピートと同じ要領で2回目以降は短くする。
131: timer.Start(100);
132: } else {
133: // 左クリックが終わっていたら終了
134: timer.Stop();
135: }
136: }
137:
138: // ボタンを押したか離したときの処理
139: void
140: WXButton::Press(bool pressed_)
141: {
142: // 状態が変化すれば再描画
143: if (pressed != pressed_) {
144: Refresh();
145: }
146:
147: // 代入
148: pressed = pressed_;
149:
150: // 状態変化に関わらず、今押していればイベント発行
151: if (IsPressed()) {
152: wxCommandEvent newev(NONO_EVT_BUTTON, GetId());
153: newev.SetEventObject(this);
154: AddPendingEvent(newev);
155: }
156: }
157:
158: void
159: WXButton::Draw()
160: {
1.1.1.2 ! root 161: // 起きないはずだけど一応。
! 162: if (__predict_false(fixedsize.x < 1 || fixedsize.y < 1)) {
1.1 root 163: return;
164: }
165:
166: // 文字
167: Color c = IsEnabled() ? UD_BLACK : UD_GREY;
168: DrawStringSJIS(c, textpos.x, textpos.y, sjistext.c_str());
169:
1.1.1.2 ! root 170: // ボタンの枠はバックバッファではなく表示枠に合わせて描画する。
! 171: // ただし枠の描画には最低でも 4x4 ピクセルが必要なので、
! 172: // 足りない時は仕方ないのでバックバッファのサイズで描画するか。
! 173: wxSize size = GetSize();
! 174: if (size.x < 4) {
! 175: size.x = fixedsize.x;
! 176: }
! 177: if (size.y < 4) {
! 178: size.y = fixedsize.y;
! 179: }
! 180:
1.1 root 181: int l = 0;
182: int t = 0;
1.1.1.2 ! root 183: int r = size.x - 1;
! 184: int b = size.y - 1;
1.1 root 185:
186: if (__predict_true(IsPressed() == false)) {
187: // この場合外寸 7x7、内寸 3x3。
188: // 空白「 」のところが内側。
189: // 「・」は背景色で塗りつぶす (オンオフ逆側の陰影があるため)
190: //
191: // □□□□□□■ <- (1)
192: // □・・・・灰■ <- (2)
193: // □・ 灰■
194: // □・ 灰■
195: // □・ 灰■
196: // □灰灰灰灰灰■ <- (3)
197: // ■■■■■■■ <- (4)
198: // ^ ^ ^ ^
199: //(5)(6) (7)(8)
200:
201: bitmap.DrawLineH(UD_WHITE, l, t, r); // (1)
202: bitmap.DrawLineH(BGPANEL, l + 1, t + 1, r -1); // (2)
203: bitmap.DrawLineH(UD_GREY, l + 1, b - 1, r); // (3)
204: bitmap.DrawLineH(UD_BLACK, l, b, r + 1); // (4)
205: bitmap.DrawLineV(UD_WHITE, l, t + 1, b); // (5)
206: bitmap.DrawLineV(BGPANEL, l + 1, t + 2, b - 1); // (6)
207: bitmap.DrawLineV(UD_GREY, r - 1, t + 1, b - 1); // (7)
208: bitmap.DrawLineV(UD_BLACK, r, t, b); // (8)
209: } else {
210: // ■■■■■■□ <- (1)
211: // ■灰灰灰灰灰□ <- (2)
212: // ■灰 ・□
213: // ■灰 ・□
214: // ■灰 ・□
215: // ■灰・・・・□ <- (3)
216: // □□□□□□□ <- (4)
217: // ^ ^ ^ ^
218: //(5)(6) (7)(8)
219: bitmap.DrawLineH(UD_BLACK, l, t, r); // (1)
220: bitmap.DrawLineH(UD_GREY, l + 1, t + 1, r); // (2)
221: bitmap.DrawLineH(BGPANEL, l + 2, b - 1, r); // (3)
222: bitmap.DrawLineH(UD_WHITE, l, b, r + 1); // (4)
223: bitmap.DrawLineV(UD_BLACK, l, t + 1, b); // (5)
224: bitmap.DrawLineV(UD_GREY, l + 1, t + 1, b); // (6)
225: bitmap.DrawLineV(BGPANEL, r - 1, t + 2, b); // (7)
226: bitmap.DrawLineV(UD_WHITE, r, t, b); // (8)
227: }
228: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.