--- nono/wx/wxdumpmonitor.cpp 2026/04/29 17:04:28 1.1 +++ nono/wx/wxdumpmonitor.cpp 2026/04/29 17:05:44 1.1.1.16 @@ -1,82 +1,259 @@ // // nono -// Copyright (C) 2019 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // -#include "wxheader.h" -#include "wxdumpmonitor.h" -#include "wxtextscreen.h" -#include "mystring.h" -#include "bus.h" - // // メモリダンプウィンドウ // +#include "wxdumpmonitor.h" +#include "mainapp.h" +#include "mainbus.h" +#include "monitor.h" +#include "mpu680x0.h" + enum { - ID_TEXT, - ID_PREV, - ID_NEXT, + ID_TEXT = IDGROUP_MEMDUMP, + ID_PREVLINE, + ID_PREVPAGE, + ID_NEXTLINE, + ID_NEXTPAGE, + ID_FORMAT, + + ID_EDIT, + + ID_local_end, // 最後に置く (チェック用) }; +static_assert(ID_local_end - 1 <= (int)IDGROUP_MEMDUMP_END, "ID exceeded"); // イベントテーブル wxBEGIN_EVENT_TABLE(WXMemdumpWindow, inherited) EVT_TEXT_ENTER(ID_TEXT, WXMemdumpWindow::OnTextEnter) - EVT_BUTTON(ID_PREV, WXMemdumpWindow::OnPrev) - EVT_BUTTON(ID_NEXT, WXMemdumpWindow::OnNext) - EVT_TIMER(wxID_ANY, WXMemdumpWindow::OnTimer) + EVT_COMMAND(ID_PREVLINE, NONO_EVT_BUTTON, WXMemdumpWindow::OnPrevLine) + EVT_COMMAND(ID_PREVPAGE, NONO_EVT_BUTTON, WXMemdumpWindow::OnPrevPage) + EVT_COMMAND(ID_NEXTLINE, NONO_EVT_BUTTON, WXMemdumpWindow::OnNextLine) + EVT_COMMAND(ID_NEXTPAGE, NONO_EVT_BUTTON, WXMemdumpWindow::OnNextPage) + EVT_CHOICE(ID_FORMAT, WXMemdumpWindow::OnFormat) wxEND_EVENT_TABLE() // コンストラクタ -WXMemdumpWindow::WXMemdumpWindow(wxWindow *parent, wxWindowID id) - : inherited(parent, id, "メモリダンプ") +// (タイトルは UpdateAddr() でセットする) +WXMemdumpWindow::WXMemdumpWindow(wxWindow *parent, int monid_) + : inherited(parent, wxID_ANY, wxEmptyString, + DEFAULT_STYLE | wxRESIZE_BORDER) { - col = 76; - row = 16; - // 最初に不一致を起こさせて再描画させるため - last_addr = 0xffffffff; - - wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); - - // 上枠 - wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL); - vbox->Add(hbox); + monid = monid_; + if (IS_MONITOR_XPMEMDUMP(monid)) { + myidx = monid - ID_MONITOR_XPMEMDUMP0; + } else { + myidx = monid - ID_MONITOR_MEMDUMP0; + } + + // ↓ topsizer + // +--------------------------------------------+ + // |上枠 → | + // |+-----+------+-----+----------+-----+------+| + // ||余白 | "<<" | "<" | アドレス | ">" | ">>" || + // |+-----+------+-----+----------+-----+------+| + // +--------------------------------------------+ + // | TextScreen | + // +--------------------------------------------+ + + auto *topsizer = new wxBoxSizer(wxVERTICAL); + + // 上枠用の下敷きパネル + auto *ctrlpanel = new wxPanel(this); + ctrlpanel->SetName("WXMemdumpWindow.CtrlPanel"); + topsizer->Add(ctrlpanel, 0, wxEXPAND); + + // 上枠用の横 sizer + ctrlbox = new wxBoxSizer(wxHORIZONTAL); // アドレスコントロール - addrctrl = new wxTextCtrl(this, ID_TEXT, + addrctrl = new wxTextCtrl(ctrlpanel, ID_TEXT, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); - hbox->Add(addrctrl); - hbox->AddSpacer(20); + buttons[0] = new WXButton(ctrlpanel, ID_PREVPAGE, wxDefaultSize, "<<"); + buttons[1] = new WXButton(ctrlpanel, ID_PREVLINE, wxDefaultSize, "<"); + buttons[2] = new WXButton(ctrlpanel, ID_NEXTLINE, wxDefaultSize, ">"); + buttons[3] = new WXButton(ctrlpanel, ID_NEXTPAGE, wxDefaultSize, ">>"); + + ctrlbox->AddSpacer(3); + ctrlbox->Add(buttons[0], 0, wxALIGN_CENTER); + ctrlbox->Add(buttons[1], 0, wxALIGN_CENTER); + ctrlbox->AddSpacer(3); + ctrlbox->Add(addrctrl, 0, wxALIGN_CENTER); + ctrlbox->AddSpacer(3); + ctrlbox->Add(buttons[2], 0, wxALIGN_CENTER); + ctrlbox->Add(buttons[3], 0, wxALIGN_CENTER); + ctrlbox->AddSpacer(3); + + // 表示形式 (機種によって選択肢と名前が異なる) + if (gMainApp.Has(VMCap::M68K)) { + auto mpu680x0 = GetMPU680x0Device(GetMPUDevice()); + fmts.emplace_back(Memdump::Byte, _("Byte")); + fmts.emplace_back(Memdump::Word, _("Word")); + fmts.emplace_back(Memdump::Long, _("Long Word")); + switch (mpu680x0->GetMPUType()) { + case m680x0MPUType::M68030: + fmts.emplace_back(Memdump::M68030PageShort, + _("MMU Descriptor (Short Format)")); + break; + case m680x0MPUType::M68040: + fmts.emplace_back(Memdump::M68040TableDesc, + _("MMU Table Descriptor")); + fmts.emplace_back(Memdump::M68040PageDesc, + _("MMU Page Descriptor")); + break; + default: + break; + } + fmts.emplace_back(Memdump::M680x0Disasm, _("680x0 Disassemble")); + } else { + fmts.emplace_back(Memdump::Byte, _("Byte")); + fmts.emplace_back(Memdump::Word, _("Half Word")); + fmts.emplace_back(Memdump::Long, _("Word")); + fmts.emplace_back(Memdump::M88200Page, _("88200 Descriptor")); + fmts.emplace_back(Memdump::M88100Disasm, _("88100 Disassemble")); + } + if (gMainApp.Has(VMCap::LUNA)) { + fmts.emplace_back(Memdump::HD64180Disasm, _("HD64180 Disassemble")); + } + + // fmts から名前だけの配列を作る + std::vector fmt_choice; + for (auto p : fmts) { + fmt_choice.push_back(p.second); + } + fmtctrl = new wxChoice(ctrlpanel, ID_FORMAT, + wxDefaultPosition, wxDefaultSize, + fmt_choice.size(), &fmt_choice[0]); + ctrlbox->Add(fmtctrl, 0, wxALIGN_CENTER); + + // 上枠の sizer と下敷きを紐付ける + ctrlpanel->SetSizer(ctrlbox); + ctrlbox->SetSizeHints(ctrlpanel); + + screen = new WXMonitorPanel(this, gMonitorManager->Get(monid)); + topsizer->Add(screen, 1, wxEXPAND); + + SetSizer(topsizer); + + // ウィンドウサイズを確定させる + FontChanged(); + + // パネルに来るマウスイベントをこっちに回す + screen->Connect(wxEVT_MOUSEWHEEL, + wxMouseEventHandler(WXMemdumpWindow::OnMouseWheel), NULL, this); + screen->Connect(wxEVT_LEFT_DCLICK, + wxMouseEventHandler(WXMemdumpWindow::OnDClick), NULL, this); + + // メモリダンプオブジェクトを取得 + auto mon = screen->GetMonitor(); + memdump = dynamic_cast(mon->obj); + assert(memdump); + + // 初期値をコントロールに設定 + auto fmt = memdump->GetFormat(); + fmtctrl->SetSelection(Format2Selection(fmt)); + DoFormat(fmt); + UpdateAddr(); +} + +// デストラクタ +WXMemdumpWindow::~WXMemdumpWindow() +{ +} - // △ボタン - // XXX とりあえずね - prev_btn = new wxButton(this, ID_PREV, wxT("△")); - next_btn = new wxButton(this, ID_NEXT, wxT("▽")); - hbox->Add(prev_btn); - hbox->Add(next_btn); - - // XXX TODO 初期フォーカスをテキストコントロールに移したい - - // テキストスクリーン - monitor.Init(col, row); - screen = new WXTextScreen(this, col, row, monitor.GetBuf()); - vbox->Add(screen, 0, wxEXPAND); +void +WXMemdumpWindow::FontChanged() +{ + for (auto *btn : buttons) { + // ボタンサイズを先に一旦リセット。 + btn->SetMinSize(wxSize(1, 1)); + btn->SetSize(wxSize(1, 1)); + + // 各ボタンコントロールに伝搬。 + btn->FontChanged(); + + // ボタンを正方形に固定する (テキストは1文字か2文字と知っている)。 + // 押しやすくするため、最小 24x24 にしてみる。 + wxSize size = btn->GetSize(); + if (size.y < 24) { + size.y = 24; + } + size.x = size.y; + + // 勝手にベストサイズに戻らないように最小サイズごと固定する。 + btn->SetSize(size); + btn->SetMinSize(size); + } - SetSizer(vbox); + screen->FontChanged(); - Layout(); Fit(); +} - // メモリが高速で変わるのを目で追う必要もないと思うので - // 30Hz くらいでどうか。 - timer.SetOwner(this); - timer.Start(33); +void +WXMemdumpWindow::Fit() +{ + // inherited::Fit() は呼ばずに自力で行う。 + + wxSize newsize = DoSizeHints(); + SetClientSize(newsize); } -// デストラクタ -WXMemdumpWindow::~WXMemdumpWindow() +bool +WXMemdumpWindow::Layout() +{ + // wxmonitor.cpp の WXScrollMonitorWindow::Layout() のコメント参照。 + wxSize client = GetClientSize(); + const wxSize win = GetSize(); + const wxSize margin = win - client; + const wxSize ctrlsize = ctrlbox->GetSize(); + const wxSize monsize = screen->GetSize(); + + if (oldmargin != margin) { + layout_pass2 = true; + oldmargin = margin; + CallAfter([this]() { + DoSizeHints(); + }); + return true; + } else if (layout_pass2) { + layout_pass2 = false; + client.y = ctrlsize.y + monsize.y; + SetClientSize(client); + Hide(); + Show(); + return true; + } + + // Sizer 使ってるのでその処理は任せる。 + return inherited::Layout(); +} + +// クライアントサイズと最大/最小サイズを計算する。 +// SetSizeHints() を実行し、設定すべきクライアントサイズを返す。 +wxSize +WXMemdumpWindow::DoSizeHints() { + // この後の Fit() でリサイズに使われる大きさを取得。 + wxSize fitsize = GetSizer()->ComputeFittingClientSize(this); + wxSize ctrlsize = ctrlbox->ComputeFittingClientSize(this); + + // 高さの最小は (コントロールパネル分と) TextScreen 1行分にしておく。 + int min_y = ctrlsize.y + screen->GetScreenHeight(1); + int new_y = ctrlsize.y + screen->GetSize().y; + wxSize minsize(fitsize.x, min_y); + wxSize maxsize(fitsize.x, GetMaxClientSize().y); + wxSize incsize(0, screen->GetFontHeight()); + SetSizeHints(ClientToWindowSize(minsize), ClientToWindowSize(maxsize), + incsize); + + return wxSize(fitsize.x, new_y); } // テキスト入力イベント @@ -84,127 +261,415 @@ void WXMemdumpWindow::OnTextEnter(wxCommandEvent& event) { // 入力文字列(16進文字列)を数値に変換 - wxString wstr = event.GetString(); - const char *cstr = (const char *)wstr.mb_str(); - uint32 val = strtoul(cstr, NULL, 16); + const wxString& wstr = event.GetString(); + uint32 val = strtoul((const char *)wstr.mb_str(), NULL, 16); - // 16 に整列 - val &= ~15; + // アドレスを更新 + memdump->SetAddr(val); + UpdateAddr(); +} - input_addr = val; +// "<"(前行) ボタン押下イベント +void +WXMemdumpWindow::OnPrevLine(wxCommandEvent& event) +{ + // 1行戻る + memdump->Offset(memdump->GetLineOffset(-1)); + + UpdateAddr(); } -// △(PREV) ボタン押下イベント +// "<<"(前ページ) ボタン押下イベント void -WXMemdumpWindow::OnPrev(wxCommandEvent& event) +WXMemdumpWindow::OnPrevPage(wxCommandEvent& event) { - input_addr -= 0x100; + // 1ページ戻る + memdump->Offset(memdump->GetPageOffset(-1)); + + UpdateAddr(); } -// ▽(NEXT) ボタン押下イベント +// ">"(次行) ボタン押下イベント void -WXMemdumpWindow::OnNext(wxCommandEvent& event) +WXMemdumpWindow::OnNextLine(wxCommandEvent& event) { - input_addr += 0x100; + // 1行進む + memdump->Offset(memdump->GetLineOffset(1)); + + UpdateAddr(); } -// タイマーイベント +// ">>"(次ページ) ボタン押下イベント void -WXMemdumpWindow::OnTimer(wxTimerEvent& event) +WXMemdumpWindow::OnNextPage(wxCommandEvent& event) { - if (input_addr != last_addr) { - // EVT_TEXT を起こさず変更する - addrctrl->ChangeValue(wxString(string_format("%08x", input_addr))); - last_addr = input_addr; + // 1ページ進む + memdump->Offset(memdump->GetPageOffset(1)); - // カーソルを末尾に - addrctrl->SetInsertionPointEnd(); + UpdateAddr(); +} + +// アドレス欄の表示を更新する +void +WXMemdumpWindow::UpdateAddr() +{ + int width; + std::string title; + if (IS_MONITOR_XPMEMDUMP(monid)) { + width = 5; + title = _("XP Memory Dump"); + } else { + width = 8; + title = _("Main Memory Dump"); } - // テキストスクリーンを更新 - Update(); - screen->Refresh(); + uint32 addr = memdump->GetAddr().Addr(); + std::string addrstr = strhex(addr, width); + + // EVT_TEXT を起こさず変更する + addrctrl->ChangeValue(addrstr); + + // カーソルを末尾に + addrctrl->SetInsertionPointEnd(); + + // タイトルを変更 + title += string_format(" %d: $", myidx); + title += addrstr; + SetTitle(title); + + // 即更新 + Refresh(); } -// フォントサイズ変更 +// 表示フォーマット変更イベント void -WXMemdumpWindow::SetFontSize(fontsize_t fontsize) +WXMemdumpWindow::OnFormat(wxCommandEvent& event) { - screen->SetFontSize(fontsize); + int idx = event.GetSelection(); + DoFormat(Selection2Format(idx)); +} - Layout(); - Fit(); +// 表示フォーマット変更処理 +void +WXMemdumpWindow::DoFormat(Memdump::Format fmt) +{ + memdump->SetFormat(fmt); + + // SetFormat() によってアドレスが切り捨てられる場合があるので + // アドレス欄の表示ごと更新。 + UpdateAddr(); } -// テキストスクリーンを更新 +// マウスホイールイベント void -WXMemdumpWindow::Update() +WXMemdumpWindow::OnMouseWheel(wxMouseEvent& event) +{ + int delta = event.GetWheelRotation(); + + // 1回の変化で +/-120 が来る。 + // たいていのアプリケーションで3行ずつの移動に換算することが多いようだが + // ここはメモリダンプなので 4行ずつにする。 + + if (delta != 0) { + memdump->Offset(memdump->GetLineOffset(-delta / 30)); + UpdateAddr(); + } +} + +// ダブルクリックイベント +void +WXMemdumpWindow::OnDClick(wxMouseEvent& event) +{ + event.Skip(); + + auto fmt = memdump->GetFormat(); + + // テキストの桁数、行数にする + wxPoint tpos = screen->GetTextPosition(event.GetPosition()); + int x = tpos.x; + int y = tpos.y; + + // ウィンドウサイズを変えた時に出来る下の空き地にはヒットさせない + if (y >= screen->GetRow()) { + return; + } + + // アドレス部分は常に除外でいいか + if (x < 19) { + return; + } + + // 現在のフォーマットでのクリック位置のアドレスを求める + int len = 0; + uint64 addr = -1; + switch (fmt) { + case Memdump::Byte: + len = 1; + addr = GetAddrAtHexdump(x, y, len); + break; + case Memdump::Word: + len = 2; + addr = GetAddrAtHexdump(x, y, len); + break; + case Memdump::Long: + len = 4; + addr = GetAddrAtHexdump(x, y, len); + break; + case Memdump::M68030PageShort: + case Memdump::M88200Page: + len = 4; + addr = GetAddrAtPageShort(x, y); + break; + + case Memdump::M68030PageLong: + PANIC("not supported"); + break; + + case Memdump::M680x0Disasm: + len = 2; + addr = GetAddrAtDisasm(x, y, len); + break; + + case Memdump::M88100Disasm: + len = 4; + addr = GetAddrAtDisasm(x, y, len); + break; + + case Memdump::HD64180Disasm: + len = 1; + addr = GetAddrAtDisasm(x, y, len); + break; + + default: + break; + } + if ((int64)addr < 0) { + return; + } + addr &= ~(len - 1); + + // このアドレスが編集可能 (≒メモリ) か? + if (memdump->CanPoke(addr) == false) { + ::wxMessageBox(_("Can not edit here"), _("Memory Edit"), + wxICON_EXCLAMATION | wxOK | wxOK_DEFAULT, this); + return; + } + + // 出来ればここをハイライトとかしたい + + // 現在値を(再)取得。 + uint32 val = memdump->Peek(addr, len); + + // sizestr は表示形式ではなく単なるサイズ。(DescShort なら Long) + std::string sizestr; + switch (len) { + case 1: + sizestr = Format2String(Memdump::Byte); + break; + case 2: + sizestr = Format2String(Memdump::Word); + break; + case 4: + sizestr = Format2String(Memdump::Long); + break; + default: + PANIC("corrupted len=%d", len); + } + + // 編集 + auto dlg = new MemEditDialog(this, addr, val, len, sizestr); + if (dlg->ShowModal() == wxID_OK) { + uint32 data = dlg->GetData(); + + // 更新 + if (memdump->Poke(addr, data, len) == false) { + ::wxMessageBox(_("Could not edit"), _("Memory Edit"), + wxICON_EXCLAMATION | wxOK | wxOK_DEFAULT, this); + } + } +} + +// 16進ダンプ画面のテキスト座標 (x, y) に対応するアドレスを返す。 +// 対応するアドレスがない場合は (uint64)-1 を返す。 +uint64 +WXMemdumpWindow::GetAddrAtHexdump(int x, int y, int len) +{ + if (x < 68) { + // 16進ダンプ部分 + + // 空白部分なら除外 + x -= 19; + if (x % (len * 2 + 1) == len * 2) { + return (uint64)-1; + } + x = (x / (len * 2 + 1)) * len; + } else { + // 文字ダンプ部分 + x -= 68; + } + + if (x > 15) { + return (uint64)-1; + } + + return memdump->GetAddr().Addr() + (y * memdump->GetStride()) + x; +} + +// 32bit ページテーブル画面のテキスト座標 (x, y) に対応するアドレスを返す。 +// 対応するアドレスがない場合は (uint64)-1 を返す。 +uint64 +WXMemdumpWindow::GetAddrAtPageShort(int x, int y) { - uint32 laddr; - uint64 paddr; + // 32bit ページテーブルなら1行で1ロングワード。 + // 16進の場合との親和性のため、ダンプ値のところだけ反応。 + if (x >= 19 + 8) { + return (uint64)-1; + } + return memdump->GetAddr().Addr() + y * 4; +} + +// 逆アセンブル画面のテキスト座標 (x, y) に対応するアドレスを返す。 +// minlen は命令の最小バイト数。 +// 対応するアドレスがない場合は (uint64)-1 を返す。 +uint64 +WXMemdumpWindow::GetAddrAtDisasm(int x, int y, int minlen) +{ + // 先頭から y 行目のアドレス + uint32 yaddr = memdump->GetLineOffset(y); + + // y 行目の命令のバイト数 + uint32 y1addr = memdump->GetLineOffset(y + 1); + uint32 bytes = y1addr - yaddr; + + // 空白部分なら除外 + x -= 19; + + if (x % (minlen * 2 + 1) == minlen * 2) { + return (uint64)-1; + } + x = (x / (minlen * 2 + 1)) * minlen; + + if (x >= bytes) { + return (uint64)-1; + } - monitor.Clear(); + return memdump->GetAddr().Addr() + yaddr + x; +} - laddr = input_addr; - paddr = 0; // shut up gcc - for (int y = 0; y < row; y++) { - if (is_logical) { - } else { - // 物理アドレス - paddr = laddr; - } - - // アドレス作成 - std::string addrstr = string_format("%08x", laddr); - if (is_logical == false) { - // 物理アドレス - addrstr += ":"; - } else if ((int64)paddr < 0) { - // MMU 時点でバスエラー - addrstr += ":BusErr"; - } else if (paddr == laddr) { - // PA==VA - addrstr += "=PA"; - } else { - // PA!=VA - addrstr += string_format(":%08x:", (uint32)paddr); - } - monitor.Print(0, y, "%s", addrstr.c_str()); - - // ダンプ作成 - std::string hexstr; - std::string chrstr; - for (int x = 0; x < 8; x++) { - uint64 b1 = m68030_phys_peek_8(paddr); - uint64 b2 = m68030_phys_peek_8(paddr + 1); - - // 偶数バイト目 - if ((int64)b1 < 0) { - hexstr += "--"; - chrstr += " "; - } else { - uint32 c1 = (uint32)b1; - hexstr += string_format("%02x", c1); - chrstr += string_format("%c", - (0x20 <= c1 && c1 <= 0x7e) ? c1 : '.'); - } - // 奇数バイト目 - if ((int64)b2 < 0) { - hexstr += "--"; - chrstr += " "; - } else { - uint32 c2 = (uint32)b2; - hexstr += string_format("%02x", c2); - chrstr += string_format("%c", - (0x20 <= c2 && c2 <= 0x7e) ? c2 : '.'); - } - hexstr += " "; +// セレクション番号からフォーマット番号への変換 +Memdump::Format +WXMemdumpWindow::Selection2Format(int idx) +{ + assert(idx < fmts.size()); + return fmts[idx].first; +} - laddr += 2; - paddr += 2; +// フォーマット番号からセレクション番号への変換 +int +WXMemdumpWindow::Format2Selection(Memdump::Format fmt_) +{ + for (int idx = 0, end = fmts.size(); idx < end; idx++) { + auto p = fmts[idx]; + if (fmt_ == p.first) { + return idx; + } + } + // ? + return 0; +} + +// フォーマット番号から文字列への変換 +wxString +WXMemdumpWindow::Format2String(Memdump::Format fmt_) +{ + for (int idx = 0, end = fmts.size(); idx < end; idx++) { + auto p = fmts[idx]; + if (fmt_ == p.first) { + return p.second; } + } + // ? + return wxEmptyString; +} + + +// +// 編集ダイアログ +// + +wxBEGIN_EVENT_TABLE(MemEditDialog, inherited) + EVT_TEXT_ENTER(ID_EDIT, MemEditDialog::OnTextEnter) +wxEND_EVENT_TABLE() + +// コンストラクタ +MemEditDialog::MemEditDialog(wxWindow *parent, uint32 addr, uint32 oldval, + int len, const std::string& sizestr) + : inherited(parent, wxID_ANY, _("Edit memory")) +{ + auto topsizer = new wxBoxSizer(wxVERTICAL); + + auto gridsizer = new wxFlexGridSizer(2); + topsizer->Add(gridsizer, 0, wxEXPAND | wxALL, 3); + + gridsizer->Add(new wxStaticText(this, wxID_ANY, _("Address:")), + 0, wxEXPAND); + + std::string addrstr = "$"; + addrstr += strhex(addr); + auto addrctrl = new wxStaticText(this, wxID_ANY, addrstr, + wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN); + gridsizer->Add(addrctrl, 0, wxEXPAND); + + gridsizer->Add(new wxStaticText(this, wxID_ANY, _("Size:")), + 0, wxEXPAND); + gridsizer->Add(new wxStaticText(this, wxID_ANY, sizestr), + 0, wxEXPAND); + + gridsizer->Add(new wxStaticText(this, wxID_ANY, _("Data:")), + 0, wxEXPAND); + + std::string oldstr = strhex(oldval, len * 2); + datactrl = new wxTextCtrl(this, ID_EDIT, oldstr, + wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + gridsizer->Add(datactrl, 0, wxEXPAND); + + topsizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), + 0, wxEXPAND | wxALL, 3); + + SetSizer(topsizer); + wxSize sz = topsizer->Fit(this); + SetClientSize(sz); + SetMinClientSize(sz); +} + +// デストラクタ +MemEditDialog::~MemEditDialog() +{ +} + +// テキスト入力 +void +MemEditDialog::OnTextEnter(wxCommandEvent& event) +{ + EndModal(wxID_OK); +} + +// テキストコントロールの値を返す。 +// 変換できなければ (uint64)-1 を返す。 +uint64 +MemEditDialog::GetData() const +{ + unsigned long int ul; + char *end; - monitor.Print(19, y, "%s", hexstr.c_str()); - monitor.Print(60, y, "%s", chrstr.c_str()); + // wxString だと地味にめんどい + wxString wtext = datactrl->GetValue(); + std::string text((const char *)wtext.mb_str()); + + errno = 0; + ul = strtoul(&text[0], &end, 16); + if (end == &text[0] || *end != '\0' || errno != 0) { + return (uint64)-1; } + return (uint32)ul; }