CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Windows/GEDebugger/TabVertices.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include "Common/CommonWindows.h"18#include <commctrl.h>19#include "Common/CommonTypes.h"20#include "Common/Data/Encoding/Utf8.h"21#include "Common/StringUtils.h"22#include "Core/System.h"23#include "Windows/resource.h"24#include "Windows/InputBox.h"25#include "Windows/GEDebugger/GEDebugger.h"26#include "Windows/GEDebugger/TabVertices.h"27#include "Windows/W32Util/ContextMenu.h"28#include "GPU/Common/VertexDecoderCommon.h"29#include "GPU/GPUState.h"30#include "GPU/GeDisasm.h"31#include "GPU/Common/GPUDebugInterface.h"32#include "GPU/Debugger/Breakpoints.h"33#include "GPU/Debugger/Stepping.h"3435static const GenericListViewColumn vertexListCols[] = {36{ L"X", 0.1f },37{ L"Y", 0.1f },38{ L"Z", 0.1f },39{ L"U", 0.1f },40{ L"V", 0.1f },41{ L"Color", 0.1f },42{ L"NX", 0.1f },43{ L"NY", 0.1f },44{ L"NZ", 0.1f },45// TODO: weight, morph?46};4748GenericListViewDef vertexListDef = {49vertexListCols, ARRAY_SIZE(vertexListCols), NULL, false50};5152enum VertexListCols {53VERTEXLIST_COL_X,54VERTEXLIST_COL_Y,55VERTEXLIST_COL_Z,56VERTEXLIST_COL_U,57VERTEXLIST_COL_V,58VERTEXLIST_COL_COLOR,59VERTEXLIST_COL_NX,60VERTEXLIST_COL_NY,61VERTEXLIST_COL_NZ,62};6364static const GenericListViewColumn matrixListCols[] = {65{ L"", 0.03f },66{ L"Name", 0.21f },67{ L"0", 0.19f },68{ L"1", 0.19f },69{ L"2", 0.19f },70{ L"3", 0.19f },71};7273GenericListViewDef matrixListDef = {74matrixListCols, ARRAY_SIZE(matrixListCols), NULL, false75};7677enum MatrixListCols {78MATRIXLIST_COL_BREAKPOINT,79MATRIXLIST_COL_NAME,80MATRIXLIST_COL_0,81MATRIXLIST_COL_1,82MATRIXLIST_COL_2,83MATRIXLIST_COL_3,8485MATRIXLIST_COL_COUNT,86};8788enum MatrixListRows {89MATRIXLIST_ROW_WORLD_0,90MATRIXLIST_ROW_WORLD_1,91MATRIXLIST_ROW_WORLD_2,92MATRIXLIST_ROW_VIEW_0,93MATRIXLIST_ROW_VIEW_1,94MATRIXLIST_ROW_VIEW_2,95MATRIXLIST_ROW_PROJ_0,96MATRIXLIST_ROW_PROJ_1,97MATRIXLIST_ROW_PROJ_2,98MATRIXLIST_ROW_PROJ_3,99MATRIXLIST_ROW_TGEN_0,100MATRIXLIST_ROW_TGEN_1,101MATRIXLIST_ROW_TGEN_2,102MATRIXLIST_ROW_BONE_0_0,103MATRIXLIST_ROW_BONE_0_1,104MATRIXLIST_ROW_BONE_0_2,105MATRIXLIST_ROW_BONE_1_0,106MATRIXLIST_ROW_BONE_1_1,107MATRIXLIST_ROW_BONE_1_2,108MATRIXLIST_ROW_BONE_2_0,109MATRIXLIST_ROW_BONE_2_1,110MATRIXLIST_ROW_BONE_2_2,111MATRIXLIST_ROW_BONE_3_0,112MATRIXLIST_ROW_BONE_3_1,113MATRIXLIST_ROW_BONE_3_2,114MATRIXLIST_ROW_BONE_4_0,115MATRIXLIST_ROW_BONE_4_1,116MATRIXLIST_ROW_BONE_4_2,117MATRIXLIST_ROW_BONE_5_0,118MATRIXLIST_ROW_BONE_5_1,119MATRIXLIST_ROW_BONE_5_2,120MATRIXLIST_ROW_BONE_6_0,121MATRIXLIST_ROW_BONE_6_1,122MATRIXLIST_ROW_BONE_6_2,123MATRIXLIST_ROW_BONE_7_0,124MATRIXLIST_ROW_BONE_7_1,125MATRIXLIST_ROW_BONE_7_2,126127MATRIXLIST_ROW_COUNT,128};129130CtrlVertexList::CtrlVertexList(HWND hwnd)131: GenericListControl(hwnd, vertexListDef), raw_(false) {132decoder = new VertexDecoder();133Update();134}135136CtrlVertexList::~CtrlVertexList() {137delete decoder;138}139140void CtrlVertexList::GetColumnText(wchar_t *dest, int row, int col) {141if (row < 0 || row >= rowCount_ ) {142wcscpy(dest, L"Invalid");143return;144}145146if (!indices.empty()) {147if (row >= (int)indices.size()) {148swprintf(dest, 255, L"Invalid indice %d", row);149return;150}151row = indices[row];152}153154if (raw_) {155FormatVertColRaw(dest, row, col);156} else {157if (row >= (int)vertices.size()) {158swprintf(dest, 255, L"Invalid vertex %d", row);159return;160}161162FormatVertCol(dest, vertices[row], col);163}164}165166void CtrlVertexList::FormatVertCol(wchar_t *dest, const GPUDebugVertex &vert, int col) {167switch (col) {168case VERTEXLIST_COL_X: swprintf(dest, 255, L"%f", vert.x); break;169case VERTEXLIST_COL_Y: swprintf(dest, 255, L"%f", vert.y); break;170case VERTEXLIST_COL_Z: swprintf(dest, 255, L"%f", vert.z); break;171case VERTEXLIST_COL_U: swprintf(dest, 255, L"%f", vert.u); break;172case VERTEXLIST_COL_V: swprintf(dest, 255, L"%f", vert.v); break;173case VERTEXLIST_COL_COLOR:174swprintf(dest, 255, L"%02x%02x%02x%02x", vert.c[0], vert.c[1], vert.c[2], vert.c[3]);175break;176case VERTEXLIST_COL_NX: swprintf(dest, 255, L"%f", vert.nx); break;177case VERTEXLIST_COL_NY: swprintf(dest, 255, L"%f", vert.ny); break;178case VERTEXLIST_COL_NZ: swprintf(dest, 255, L"%f", vert.nz); break;179180default:181wcscpy(dest, L"Invalid");182break;183}184}185186void CtrlVertexList::FormatVertColRaw(wchar_t *dest, int row, int col) {187auto memLock = Memory::Lock();188if (!PSP_IsInited()) {189wcscpy(dest, L"Invalid");190return;191}192193// We could use the vertex decoder and reader, but those already do some minor adjustments.194// There's only a few values - let's just go after them directly.195const u8 *vert = Memory::GetPointer(gpuDebug->GetVertexAddress()) + row * decoder->size;196const u8 *pos = vert + decoder->posoff;197const u8 *tc = vert + decoder->tcoff;198const u8 *color = vert + decoder->coloff;199const u8 *norm = vert + decoder->nrmoff;200201switch (col) {202case VERTEXLIST_COL_X:203FormatVertColRawType(dest, pos, decoder->pos, 0);204break;205case VERTEXLIST_COL_Y:206FormatVertColRawType(dest, pos, decoder->pos, 1);207break;208case VERTEXLIST_COL_Z:209FormatVertColRawType(dest, pos, decoder->pos, 2);210break;211case VERTEXLIST_COL_U:212FormatVertColRawType(dest, tc, decoder->tc, 0);213break;214case VERTEXLIST_COL_V:215FormatVertColRawType(dest, tc, decoder->tc, 1);216break;217case VERTEXLIST_COL_COLOR:218FormatVertColRawColor(dest, color, decoder->col);219break;220221case VERTEXLIST_COL_NX: FormatVertColRawType(dest, norm, decoder->nrm, 0); break;222case VERTEXLIST_COL_NY: FormatVertColRawType(dest, norm, decoder->nrm, 1); break;223case VERTEXLIST_COL_NZ: FormatVertColRawType(dest, norm, decoder->nrm, 2); break;224225default:226wcscpy(dest, L"Invalid");227break;228}229}230231void CtrlVertexList::FormatVertColRawType(wchar_t *dest, const void *data, int type, int offset) {232switch (type) {233case 0:234wcscpy(dest, L"-");235break;236237case 1: // 8-bit238swprintf(dest, 255, L"%02x", ((const u8 *)data)[offset]);239break;240241case 2: // 16-bit242swprintf(dest, 255, L"%04x", ((const u16_le *)data)[offset]);243break;244245case 3: // float246swprintf(dest, 255, L"%f", ((const float *)data)[offset]);247break;248249default:250wcscpy(dest, L"Invalid");251break;252}253}254255void CtrlVertexList::FormatVertColRawColor(wchar_t *dest, const void *data, int type) {256switch (type) {257case GE_VTYPE_COL_NONE >> GE_VTYPE_COL_SHIFT:258wcscpy(dest, L"-");259break;260261case GE_VTYPE_COL_565 >> GE_VTYPE_COL_SHIFT:262case GE_VTYPE_COL_5551 >> GE_VTYPE_COL_SHIFT:263case GE_VTYPE_COL_4444 >> GE_VTYPE_COL_SHIFT:264swprintf(dest, 255, L"%04x", *(const u16_le *)data);265break;266267case GE_VTYPE_COL_8888 >> GE_VTYPE_COL_SHIFT:268swprintf(dest, 255, L"%08x", *(const u32_le *)data);269break;270271default:272wcscpy(dest, L"Invalid");273break;274}275}276277int CtrlVertexList::GetRowCount() {278auto memLock = Memory::Lock();279if (!PSP_IsInited()) {280return 0;281}282283if (!gpuDebug || !Memory::IsValidAddress(gpuDebug->GetVertexAddress())) {284rowCount_ = 0;285return rowCount_;286}287288// TODO: Maybe there are smarter ways? Also, is this the best place to recalc?289auto state = gpuDebug->GetGState();290rowCount_ = state.prim & 0xFFFF;291292// Override if we're on a prim command.293DisplayList list;294if (gpuDebug->GetCurrentDisplayList(list)) {295u32 cmd = Memory::Read_U32(list.pc);296if ((cmd >> 24) == GE_CMD_PRIM || (cmd >> 24) == GE_CMD_BOUNDINGBOX) {297rowCount_ = cmd & 0xFFFF;298} else if ((cmd >> 24) == GE_CMD_BEZIER || (cmd >> 24) == GE_CMD_SPLINE) {299u32 u = (cmd & 0x00FF) >> 0;300u32 v = (cmd & 0xFF00) >> 8;301rowCount_ = u * v;302}303}304305if (!gpuDebug->GetCurrentSimpleVertices(rowCount_, vertices, indices)) {306rowCount_ = 0;307}308VertexDecoderOptions options{};309// TODO: Maybe an option?310options.applySkinInDecode = true;311decoder->SetVertexType(state.vertType, options);312return rowCount_;313}314315TabVertices::TabVertices(HINSTANCE _hInstance, HWND _hParent)316: Dialog((LPCSTR)IDD_GEDBG_TAB_VERTICES, _hInstance, _hParent) {317values = new CtrlVertexList(GetDlgItem(m_hDlg, IDC_GEDBG_VERTICES));318}319320TabVertices::~TabVertices() {321delete values;322}323324void TabVertices::UpdateSize(WORD width, WORD height) {325struct Position {326int x,y;327int w,h;328};329330Position position;331static const int borderMargin = 5;332static const int checkboxSpace = 22;333334position.x = borderMargin;335position.y = borderMargin + checkboxSpace;336position.w = width - 2 * borderMargin;337position.h = height - 2 * borderMargin - checkboxSpace;338339HWND handle = GetDlgItem(m_hDlg, IDC_GEDBG_VERTICES);340MoveWindow(handle, position.x, position.y, position.w, position.h, TRUE);341}342343BOOL TabVertices::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {344switch (message) {345case WM_INITDIALOG:346return TRUE;347348case WM_SIZE:349UpdateSize(LOWORD(lParam), HIWORD(lParam));350return TRUE;351352case WM_COMMAND:353if (LOWORD(wParam) == IDC_GEDBG_RAWVERTS) {354values->SetRaw(IsDlgButtonChecked(m_hDlg, IDC_GEDBG_RAWVERTS) == BST_CHECKED);355values->Update();356}357return TRUE;358359case WM_NOTIFY:360switch (wParam)361{362case IDC_GEDBG_VERTICES:363SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, values->HandleNotify(lParam));364return TRUE;365}366break;367}368369return FALSE;370}371372CtrlMatrixList::CtrlMatrixList(HWND hwnd)373: GenericListControl(hwnd, matrixListDef) {374SetIconList(12, 12, { (HICON)LoadIcon(GetModuleHandle(nullptr), (LPCWSTR)IDI_BREAKPOINT_SMALL) });375Update();376}377378bool CtrlMatrixList::OnColPrePaint(int row, int col, LPNMLVCUSTOMDRAW msg) {379const auto state = gpuDebug->GetGState();380const auto lastState = GPUStepping::LastState();381382bool changed = false;383if (col < MATRIXLIST_COL_0) {384for (int c = MATRIXLIST_COL_0; c <= MATRIXLIST_COL_3; ++c) {385changed = changed || ColChanged(lastState, state, row, c);386}387} else {388changed = ColChanged(lastState, state, row, col);389}390391// At the column level, we have to reset the color back.392static int lastRow = -1;393static COLORREF rowDefaultText;394if (lastRow != row) {395rowDefaultText = msg->clrText;396lastRow = row;397}398399if (changed) {400msg->clrText = RGB(255, 0, 0);401return true;402} else if (msg->clrText != rowDefaultText) {403msg->clrText = rowDefaultText;404return true;405}406407return false;408}409410bool CtrlMatrixList::ColChanged(const GPUgstate &lastState, const GPUgstate &state, int row, int col) {411union {412float f;413uint32_t u;414} newVal, oldVal;415if (!GetValue(state, row, col, newVal.f) || !GetValue(lastState, row, col, oldVal.f))416return false;417418// If there's any difference in bits, highlight.419return newVal.u != oldVal.u;420}421422bool CtrlMatrixList::GetValue(const GPUgstate &state, int row, int col, float &val) {423if (!gpuDebug || row < 0 || row >= MATRIXLIST_ROW_COUNT || col < 0 || col >= MATRIXLIST_COL_COUNT)424return false;425426if (col < MATRIXLIST_COL_0)427col = MATRIXLIST_COL_0;428429if (row >= MATRIXLIST_ROW_BONE_0_0) {430int b = (row - MATRIXLIST_ROW_BONE_0_0) / 3;431int r = (row - MATRIXLIST_ROW_BONE_0_0) % 3;432int offset = b * 12 + r + (col - MATRIXLIST_COL_0) * 3;433434val = state.boneMatrix[offset];435return true;436} else if (row >= MATRIXLIST_ROW_TGEN_0) {437int r = row - MATRIXLIST_ROW_TGEN_0;438int offset = r + (col - MATRIXLIST_COL_0) * 3;439440val = state.tgenMatrix[offset];441return true;442} else if (row >= MATRIXLIST_ROW_PROJ_0) {443int r = row - MATRIXLIST_ROW_PROJ_0;444int offset = r + (col - MATRIXLIST_COL_0) * 4;445446val = state.projMatrix[offset];447return true;448} else if (row >= MATRIXLIST_ROW_VIEW_0) {449int r = row - MATRIXLIST_ROW_VIEW_0;450int offset = r + (col - MATRIXLIST_COL_0) * 3;451452val = state.viewMatrix[offset];453return true;454}455456int r = row - MATRIXLIST_ROW_WORLD_0;457int offset = r + (col - MATRIXLIST_COL_0) * 3;458459val = state.worldMatrix[offset];460return true;461}462463void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) {464if (col == MATRIXLIST_COL_BREAKPOINT) {465wcscpy(dest, L" ");466return;467}468469float val;470if (!GetValue(gpuDebug->GetGState(), row, col, val)) {471wcscpy(dest, L"Invalid");472return;473}474475if (row >= MATRIXLIST_ROW_BONE_0_0) {476int b = (row - MATRIXLIST_ROW_BONE_0_0) / 3;477int r = (row - MATRIXLIST_ROW_BONE_0_0) % 3;478switch (col) {479case MATRIXLIST_COL_NAME:480swprintf(dest, 255, L"Bone #%d row %d", b, r);481break;482483default:484swprintf(dest, 255, L"%f", val);485break;486}487} else if (row >= MATRIXLIST_ROW_TGEN_0) {488int r = row - MATRIXLIST_ROW_TGEN_0;489switch (col) {490case MATRIXLIST_COL_NAME:491swprintf(dest, 255, L"Texgen %d", r);492break;493494default:495swprintf(dest, 255, L"%f", val);496break;497}498} else if (row >= MATRIXLIST_ROW_PROJ_0) {499int r = row - MATRIXLIST_ROW_PROJ_0;500switch (col) {501case MATRIXLIST_COL_NAME:502swprintf(dest, 255, L"Proj %d", r);503break;504505default:506swprintf(dest, 255, L"%f", val);507break;508}509} else if (row >= MATRIXLIST_ROW_VIEW_0) {510int r = row - MATRIXLIST_ROW_VIEW_0;511switch (col) {512case MATRIXLIST_COL_NAME:513swprintf(dest, 255, L"View %d", r);514break;515516default:517swprintf(dest, 255, L"%f", val);518break;519}520} else {521int r = row - MATRIXLIST_ROW_WORLD_0;522switch (col) {523case MATRIXLIST_COL_NAME:524swprintf(dest, 255, L"World %d", r);525break;526527default:528swprintf(dest, 255, L"%f", val);529break;530}531}532}533534int CtrlMatrixList::GetRowCount() {535if (!gpuDebug) {536return 0;537}538539return MATRIXLIST_ROW_COUNT;540}541542struct MatrixCmdPair {543MatrixListRows row;544GECommand numCmd;545GECommand cmd;546};547static constexpr MatrixCmdPair matrixCmds[] = {548{ MATRIXLIST_ROW_WORLD_0, GE_CMD_WORLDMATRIXNUMBER, GE_CMD_WORLDMATRIXDATA },549{ MATRIXLIST_ROW_VIEW_0, GE_CMD_VIEWMATRIXNUMBER, GE_CMD_VIEWMATRIXDATA },550{ MATRIXLIST_ROW_PROJ_0, GE_CMD_PROJMATRIXNUMBER, GE_CMD_PROJMATRIXDATA },551{ MATRIXLIST_ROW_TGEN_0, GE_CMD_TGENMATRIXNUMBER, GE_CMD_TGENMATRIXDATA },552{ MATRIXLIST_ROW_BONE_0_0, GE_CMD_BONEMATRIXNUMBER, GE_CMD_BONEMATRIXDATA },553{ MATRIXLIST_ROW_COUNT, GE_CMD_NOP },554};555556static const MatrixCmdPair *FindCmdPair(int row) {557for (int i = 0; i < ARRAY_SIZE(matrixCmds) - 1; ++i) {558if (row < matrixCmds[i].row || row >= matrixCmds[i + 1].row)559continue;560561return &matrixCmds[i];562}563return nullptr;564}565566void CtrlMatrixList::ToggleBreakpoint(int row) {567const MatrixCmdPair *info = FindCmdPair(row);568if (!info)569return;570571// Okay, this command is in range. Toggle the actual breakpoint.572bool state = !GPUBreakpoints::IsCmdBreakpoint(info->cmd);573if (state) {574GPUBreakpoints::AddCmdBreakpoint(info->cmd);575} else {576if (GPUBreakpoints::GetCmdBreakpointCond(info->cmd, nullptr)) {577int ret = MessageBox(GetHandle(), L"This breakpoint has a custom condition.\nDo you want to remove it?", L"Confirmation", MB_YESNO);578if (ret != IDYES)579return;580}581GPUBreakpoints::RemoveCmdBreakpoint(info->cmd);582}583584for (int r = info->row; r < (info + 1)->row; ++r) {585SetItemState(r, state ? 1 : 0);586}587}588589void CtrlMatrixList::PromptBreakpointCond(int row) {590const MatrixCmdPair *info = FindCmdPair(row);591if (!info)592return;593594std::string expression;595GPUBreakpoints::GetCmdBreakpointCond(info->cmd, &expression);596if (!InputBox_GetString(GetModuleHandle(NULL), GetHandle(), L"Expression", expression, expression))597return;598599std::string error;600if (!GPUBreakpoints::SetCmdBreakpointCond(info->cmd, expression, &error))601MessageBox(GetHandle(), ConvertUTF8ToWString(error).c_str(), L"Invalid expression", MB_OK | MB_ICONEXCLAMATION);602}603604void CtrlMatrixList::OnDoubleClick(int row, int column) {605if (row >= GetRowCount())606return;607608if (column == MATRIXLIST_COL_BREAKPOINT) {609ToggleBreakpoint(row);610return;611}612613float val;614if (!GetValue(gpuDebug->GetGState(), row, column, val))615return;616617std::string strvalue = StringFromFormat("%f", val);618bool res = InputBox_GetString(GetModuleHandle(NULL), GetHandle(), L"Column value", strvalue, strvalue);619if (!res)620return;621622if (sscanf(strvalue.c_str(), "%f", &val) == 1) {623auto prevState = gpuDebug->GetGState();624auto setCmdValue = [&](u32 op) {625SendMessage(GetParent(GetParent(GetHandle())), WM_GEDBG_SETCMDWPARAM, op, NULL);626};627628union {629float f;630u32 u;631} temp = { val };632633for (int i = 0; i < ARRAY_SIZE(matrixCmds) - 1; ++i) {634if (row < matrixCmds[i].row || row >= matrixCmds[i + 1].row)635continue;636637// Everything is 3 except the projection matrix, which is 4.638int sz = matrixCmds[i + 1].row - matrixCmds[i].row == 4 ? 4 : 3;639// Always zero except for bones.640int b = (row - matrixCmds[i].row) / sz;641int r = (row - matrixCmds[i].row) % sz;642int c = column >= MATRIXLIST_COL_0 ? column - MATRIXLIST_COL_0 : 0;643644// Okay, now set the number, then data.645int n = b * 12 + r + c * sz;646setCmdValue((matrixCmds[i].numCmd << 24) | n);647setCmdValue((matrixCmds[i].cmd << 24) | (temp.u >> 8));648649// Done, revert the number.650setCmdValue(prevState.cmdmem[matrixCmds[i].numCmd]);651Update();652}653}654}655656void CtrlMatrixList::OnRightClick(int row, int column, const POINT &point) {657if (row >= GetRowCount())658return;659const MatrixCmdPair *info = FindCmdPair(row);660661POINT screenPt(point);662ClientToScreen(GetHandle(), &screenPt);663664HMENU subMenu = GetContextMenu(ContextMenuID::GEDBG_MATRIX);665SetMenuDefaultItem(subMenu, ID_REGLIST_CHANGE, FALSE);666EnableMenuItem(subMenu, ID_GEDBG_SETCOND, info && GPUBreakpoints::IsCmdBreakpoint(info->cmd) ? MF_ENABLED : MF_GRAYED);667668switch (TriggerContextMenu(ContextMenuID::GEDBG_MATRIX, GetHandle(), ContextPoint::FromClient(point))) {669case ID_DISASM_TOGGLEBREAKPOINT:670ToggleBreakpoint(row);671break;672673case ID_GEDBG_SETCOND:674PromptBreakpointCond(row);675break;676677case ID_DISASM_COPYINSTRUCTIONDISASM:678{679float val;680if (GetValue(gpuDebug->GetGState(), row, column, val)) {681wchar_t dest[512];682swprintf(dest, 511, L"%f", val);683W32Util::CopyTextToClipboard(GetHandle(), dest);684}685break;686}687688case ID_GEDBG_COPYALL:689CopyRows(0, GetRowCount());690break;691692case ID_REGLIST_CHANGE:693OnDoubleClick(row, MATRIXLIST_COL_0);694break;695}696}697698TabMatrices::TabMatrices(HINSTANCE _hInstance, HWND _hParent)699: Dialog((LPCSTR)IDD_GEDBG_TAB_MATRICES, _hInstance, _hParent) {700values = new CtrlMatrixList(GetDlgItem(m_hDlg, IDC_GEDBG_MATRICES));701}702703TabMatrices::~TabMatrices() {704delete values;705}706707void TabMatrices::UpdateSize(WORD width, WORD height) {708struct Position {709int x,y;710int w,h;711};712713Position position;714static const int borderMargin = 5;715716position.x = borderMargin;717position.y = borderMargin;718position.w = width - 2 * borderMargin;719position.h = height - 2 * borderMargin;720721HWND handle = GetDlgItem(m_hDlg, IDC_GEDBG_MATRICES);722MoveWindow(handle, position.x, position.y, position.w, position.h, TRUE);723}724725BOOL TabMatrices::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) {726switch (message) {727case WM_INITDIALOG:728return TRUE;729730case WM_SIZE:731UpdateSize(LOWORD(lParam), HIWORD(lParam));732return TRUE;733734case WM_NOTIFY:735switch (wParam)736{737case IDC_GEDBG_MATRICES:738SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, values->HandleNotify(lParam));739return TRUE;740}741break;742}743744return FALSE;745}746747748