diff options
Diffstat (limited to 'src/osd/modules/debugger/win/debugviewinfo.cpp')
-rw-r--r-- | src/osd/modules/debugger/win/debugviewinfo.cpp | 492 |
1 files changed, 380 insertions, 112 deletions
diff --git a/src/osd/modules/debugger/win/debugviewinfo.cpp b/src/osd/modules/debugger/win/debugviewinfo.cpp index 97238ff8862..8f3f05c16d2 100644 --- a/src/osd/modules/debugger/win/debugviewinfo.cpp +++ b/src/osd/modules/debugger/win/debugviewinfo.cpp @@ -2,7 +2,7 @@ // copyright-holders:Aaron Giles, Vas Crabb //============================================================ // -// debugview.c - Win32 debug window handling +// debugviewinfo.cpp - Win32 debug window handling // //============================================================ @@ -12,12 +12,20 @@ #include "debugwininfo.h" #include "uimetrics.h" #include "debugger.h" + +#include "debug/debugcon.h" #include "debug/debugcpu.h" +#include "util/xmlfile.h" + #include "strconv.h" #include "winutil.h" +#include <mmsystem.h> + + +namespace osd::debugger::win { // debugger view styles #define DEBUG_VIEW_STYLE WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN @@ -45,14 +53,15 @@ debugview_info::debugview_info(debugger_windows_interface &debugger, debugwin_in m_view(nullptr), m_wnd(nullptr), m_hscroll(nullptr), - m_vscroll(nullptr) + m_vscroll(nullptr), + m_contextmenu(nullptr) { register_window_class(); // create the child view m_wnd = CreateWindowEx(DEBUG_VIEW_STYLE_EX, TEXT("MAMEDebugView"), nullptr, DEBUG_VIEW_STYLE, 0, 0, 100, 100, parent, nullptr, GetModuleHandleUni(), this); - if (m_wnd == nullptr) + if (!m_wnd) goto cleanup; // create the scroll bars @@ -60,27 +69,27 @@ debugview_info::debugview_info(debugger_windows_interface &debugger, debugwin_in 0, 0, 100, CW_USEDEFAULT, m_wnd, nullptr, GetModuleHandleUni(), this); m_vscroll = CreateWindowEx(VSCROLL_STYLE_EX, TEXT("SCROLLBAR"), nullptr, VSCROLL_STYLE, 0, 0, CW_USEDEFAULT, 100, m_wnd, nullptr, GetModuleHandleUni(), this); - if ((m_hscroll == nullptr) || (m_vscroll == nullptr)) + if (!m_hscroll || !m_vscroll) goto cleanup; // create the debug view m_view = machine().debug_view().alloc_view(type, &debugview_info::static_update, this); - if (m_view == nullptr) + if (!m_view) goto cleanup; return; cleanup: - if (m_hscroll != nullptr) + if (m_hscroll) DestroyWindow(m_hscroll); m_hscroll = nullptr; - if (m_vscroll != nullptr) + if (m_vscroll) DestroyWindow(m_vscroll); m_vscroll = nullptr; - if (m_wnd != nullptr) + if (m_wnd) DestroyWindow(m_wnd); m_wnd = nullptr; - if (m_view != nullptr) + if (m_view) machine().debug_view().free_view(*m_view); m_view = nullptr; } @@ -88,7 +97,9 @@ cleanup: debugview_info::~debugview_info() { - if (m_wnd != nullptr) + if (m_contextmenu) + DestroyMenu(m_contextmenu); + if (m_wnd) DestroyWindow(m_wnd); if (m_view) machine().debug_view().free_view(*m_view); @@ -111,14 +122,14 @@ uint32_t debugview_info::maxwidth() { uint32_t max = m_view->total_size().x; debug_view_source const *const cursource = m_view->source(); - for (const debug_view_source &source : m_view->source_list()) + for (auto &source : m_view->source_list()) { - m_view->set_source(source); + m_view->set_source(*source); uint32_t const chars = m_view->total_size().x; if (max < chars) max = chars; } - if (cursource != nullptr) + if (cursource) m_view->set_source(*cursource); return (max * metrics().debug_font_width()) + metrics().vscroll_width(); } @@ -163,27 +174,35 @@ void debugview_info::send_vscroll(int delta) void debugview_info::send_pageup() { if (m_vscroll) - { SendMessage(m_wnd, WM_VSCROLL, SB_PAGELEFT, (LPARAM)m_vscroll); - } } void debugview_info::send_pagedown() { if (m_vscroll) - { SendMessage(m_wnd, WM_VSCROLL, SB_PAGERIGHT, (LPARAM)m_vscroll); +} + + +int debugview_info::source_index() const +{ + if (m_view) + { + debug_view_source const *const source = m_view->source(); + if (source) + return m_view->source_index(*source); } + return -1; } char const *debugview_info::source_name() const { - if (m_view != nullptr) + if (m_view) { debug_view_source const *const source = m_view->source(); - if (source != nullptr) + if (source) return source->name(); } return ""; @@ -192,10 +211,10 @@ char const *debugview_info::source_name() const device_t *debugview_info::source_device() const { - if (m_view != nullptr) + if (m_view) { debug_view_source const *const source = m_view->source(); - if (source != nullptr) + if (source) return source->device(); } return nullptr; @@ -204,10 +223,10 @@ device_t *debugview_info::source_device() const bool debugview_info::source_is_visible_cpu() const { - if (m_view != nullptr) + if (m_view) { const debug_view_source *const source = m_view->source(); - return (source != nullptr) && (machine().debugger().cpu().get_visible_cpu() == source->device()); + return source && (machine().debugger().console().get_visible_cpu() == source->device()); } return false; } @@ -215,10 +234,10 @@ bool debugview_info::source_is_visible_cpu() const bool debugview_info::set_source_index(int index) { - if (m_view != nullptr) + if (m_view) { - const debug_view_source *const source = m_view->source_list().find(index); - if (source != nullptr) + const debug_view_source *const source = m_view->source(index); + if (source) { m_view->set_source(*source); return true; @@ -230,10 +249,10 @@ bool debugview_info::set_source_index(int index) bool debugview_info::set_source_for_device(device_t &device) { - if (m_view != nullptr) + if (m_view) { const debug_view_source *const source = m_view->source_for_device(&device); - if (source != nullptr) + if (source) { m_view->set_source(*source); return true; @@ -245,8 +264,8 @@ bool debugview_info::set_source_for_device(device_t &device) bool debugview_info::set_source_for_visible_cpu() { - device_t *const curcpu = machine().debugger().cpu().get_visible_cpu(); - if (curcpu != nullptr) + device_t *const curcpu = machine().debugger().console().get_visible_cpu(); + if (curcpu) return set_source_for_device(*curcpu); else return false; @@ -264,7 +283,7 @@ HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata) // populate the combobox debug_view_source const *const cursource = m_view->source(); int maxlength = 0; - for (debug_view_source const *source = m_view->first_source(); source != nullptr; source = source->next()) + for (auto &source : m_view->source_list()) { int const length = strlen(source->name()); if (length > maxlength) @@ -272,9 +291,9 @@ HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata) auto t_name = osd::text::to_tstring(source->name()); SendMessage(result, CB_ADDSTRING, 0, (LPARAM)t_name.c_str()); } - if (cursource != nullptr) + if (cursource) { - SendMessage(result, CB_SETCURSEL, m_view->source_list().indexof(*cursource), 0); + SendMessage(result, CB_SETCURSEL, m_view->source_index(*cursource), 0); SendMessage(result, CB_SETDROPPEDWIDTH, ((maxlength + 2) * metrics().debug_font_width()) + metrics().vscroll_width(), 0); m_view->set_source(*cursource); } @@ -282,6 +301,165 @@ HWND debugview_info::create_source_combobox(HWND parent, LONG_PTR userdata) } +void debugview_info::restore_configuration_from_node(util::xml::data_node const &node) +{ + if (m_view->cursor_supported()) + { + util::xml::data_node const *const selection = node.get_child(NODE_WINDOW_SELECTION); + if (selection) + { + debug_view_xy pos = m_view->cursor_position(); + m_view->set_cursor_visible(0 != selection->get_attribute_int(ATTR_SELECTION_CURSOR_VISIBLE, m_view->cursor_visible() ? 1 : 0)); + selection->get_attribute_int(ATTR_SELECTION_CURSOR_X, pos.x); + selection->get_attribute_int(ATTR_SELECTION_CURSOR_Y, pos.y); + m_view->set_cursor_position(pos); + } + } + + util::xml::data_node const *const scroll = node.get_child(NODE_WINDOW_SCROLL); + if (scroll) + { + debug_view_xy origin = m_view->visible_position(); + origin.x = scroll->get_attribute_int(ATTR_SCROLL_ORIGIN_X, origin.x * metrics().debug_font_width()) / metrics().debug_font_width(); + origin.y = scroll->get_attribute_int(ATTR_SCROLL_ORIGIN_Y, origin.y * metrics().debug_font_height()) / metrics().debug_font_height(); + m_view->set_visible_position(origin); + } +} + + +void debugview_info::save_configuration_to_node(util::xml::data_node &node) +{ + if (m_view->cursor_supported()) + { + util::xml::data_node *const selection = node.add_child(NODE_WINDOW_SELECTION, nullptr); + if (selection) + { + debug_view_xy const pos = m_view->cursor_position(); + selection->set_attribute_int(ATTR_SELECTION_CURSOR_VISIBLE, m_view->cursor_visible() ? 1 : 0); + selection->set_attribute_int(ATTR_SELECTION_CURSOR_X, pos.x); + selection->set_attribute_int(ATTR_SELECTION_CURSOR_Y, pos.y); + } + } + + util::xml::data_node *const scroll = node.add_child(NODE_WINDOW_SCROLL, nullptr); + if (scroll) + { + debug_view_xy const origin = m_view->visible_position(); + scroll->set_attribute_int(ATTR_SCROLL_ORIGIN_X, origin.x * metrics().debug_font_width()); + scroll->set_attribute_int(ATTR_SCROLL_ORIGIN_Y, origin.y * metrics().debug_font_height()); + } +} + + +void debugview_info::add_items_to_context_menu(HMENU menu) +{ + AppendMenu(menu, MF_ENABLED, ID_CONTEXT_COPY_VISIBLE, TEXT("Copy Visible")); + AppendMenu(menu, MF_ENABLED, ID_CONTEXT_PASTE, TEXT("Paste")); +} + + +void debugview_info::update_context_menu(HMENU menu) +{ + EnableMenuItem(menu, ID_CONTEXT_PASTE, MF_BYCOMMAND | (IsClipboardFormatAvailable(CF_UNICODETEXT) ? MF_ENABLED : MF_GRAYED)); +} + + +void debugview_info::handle_context_menu(unsigned command) +{ + switch (command) + { + case ID_CONTEXT_COPY_VISIBLE: + { + // get visible text + debug_view_xy const visarea = m_view->visible_size(); + debug_view_char const *viewdata = m_view->viewdata(); + if (!viewdata) + { + PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC); + break; + } + + // turn into a plain string, trimming trailing whitespace + std::wstring text; + for (uint32_t row = 0; row < visarea.y; row++, viewdata += visarea.x) + { + std::wstring::size_type const start = text.length(); + for (uint32_t col = 0; col < visarea.x; ++col) + text += wchar_t(viewdata[col].byte); + std::wstring::size_type const nonblank = text.find_last_not_of(L"\t\n\v\r "); + if (nonblank != std::wstring::npos) + text.resize((std::max)(start, nonblank + 1)); + text += L"\r\n"; + } + + // copy to the clipboard + HGLOBAL const clip = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(wchar_t)); + if (!clip) + { + PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC); + break; + } + if (!OpenClipboard(m_wnd)) + { + GlobalFree(clip); + PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC); + break; + } + EmptyClipboard(); + LPWSTR const lock = reinterpret_cast<LPWSTR>(GlobalLock(clip)); + std::copy_n(text.c_str(), text.length() + 1, lock); + GlobalUnlock(clip); + if (!SetClipboardData(CF_UNICODETEXT, clip)) + { + GlobalFree(clip); + PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC); + } + CloseClipboard(); + break; + } + + case ID_CONTEXT_PASTE: + if (!IsClipboardFormatAvailable(CF_UNICODETEXT) || !OpenClipboard(m_wnd)) + { + PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC); + } + else + { + HGLOBAL const clip = GetClipboardData(CF_UNICODETEXT); + LPCWSTR lock = clip ? reinterpret_cast<LPCWSTR>(GlobalLock(clip)) : nullptr; + if (!clip || !lock) + { + PlaySound(TEXT("SystemAsterisk"), nullptr, SND_SYNC); + } + else + { + try + { + while (*lock) + { + if ((32 <= *lock) && (127 >= *lock)) + m_view->process_char(*lock); + ++lock; + } + } + catch (...) + { + GlobalUnlock(clip); + CloseClipboard(); + throw; + } + GlobalUnlock(clip); + } + CloseClipboard(); + } + break; + + default: + osd_printf_warning("debugview_info: unhandled context menu item %u\n", command); + } +} + + void debugview_info::draw_contents(HDC windc) { debug_view_char const *viewdata = m_view->viewdata(); @@ -290,18 +468,22 @@ void debugview_info::draw_contents(HDC windc) // get the client rect RECT client; GetClientRect(m_wnd, &client); + bool const need_filldown = client.bottom > (metrics().debug_font_height() * visarea.y); // create a compatible DC and an offscreen bitmap HDC const dc = CreateCompatibleDC(windc); - if (dc == nullptr) + if (!dc) return; HBITMAP const bitmap = CreateCompatibleBitmap(windc, client.right, client.bottom); - if (bitmap == nullptr) + if (!bitmap) { DeleteDC(dc); return; } HGDIOBJ const oldbitmap = SelectObject(dc, bitmap); + bool const show_hscroll = m_hscroll && IsWindowVisible(m_hscroll); + if (show_hscroll) + client.bottom -= metrics().hscroll_height(); // set the font HGDIOBJ const oldfont = SelectObject(dc, metrics().debug_font()); @@ -312,11 +494,13 @@ void debugview_info::draw_contents(HDC windc) // iterate over rows and columns for (uint32_t row = 0; row < visarea.y; row++) { + bool do_filldown = (row == (visarea.y - 1)) && need_filldown; + // loop twice; once to fill the background and once to draw the text for (int iter = 0; iter < 2; iter++) { COLORREF fgcolor; - COLORREF bgcolor = RGB(0xff,0xff,0xff); + COLORREF bgcolor = metrics().view_colors(DCA_NORMAL).second; HBRUSH bgbrush = nullptr; int last_attrib = -1; TCHAR buffer[256]; @@ -340,41 +524,49 @@ void debugview_info::draw_contents(HDC windc) { COLORREF oldbg = bgcolor; - // reset to standard colors - fgcolor = RGB(0x00,0x00,0x00); - bgcolor = RGB(0xff,0xff,0xff); - - // pick new fg/bg colors - if (viewdata[col].attrib & DCA_VISITED) bgcolor = RGB(0xc6, 0xe2, 0xff); - if (viewdata[col].attrib & DCA_ANCILLARY) bgcolor = RGB(0xe0,0xe0,0xe0); - if (viewdata[col].attrib & DCA_SELECTED) bgcolor = RGB(0xff,0x80,0x80); - if (viewdata[col].attrib & DCA_CURRENT) bgcolor = RGB(0xff,0xff,0x00); - if ((viewdata[col].attrib & DCA_SELECTED) && (viewdata[col].attrib & DCA_CURRENT)) bgcolor = RGB(0xff,0xc0,0x80); - if (viewdata[col].attrib & DCA_CHANGED) fgcolor = RGB(0xff,0x00,0x00); - if (viewdata[col].attrib & DCA_INVALID) fgcolor = RGB(0x00,0x00,0xff); - if (viewdata[col].attrib & DCA_DISABLED) fgcolor = RGB((GetRValue(fgcolor) + GetRValue(bgcolor)) / 2, (GetGValue(fgcolor) + GetGValue(bgcolor)) / 2, (GetBValue(fgcolor) + GetBValue(bgcolor)) / 2); - if (viewdata[col].attrib & DCA_COMMENT) fgcolor = RGB(0x00,0x80,0x00); + // pick new colors + std::tie(fgcolor, bgcolor) = metrics().view_colors(viewdata[col].attrib); // flush any pending drawing if (count > 0) { bounds.right = bounds.left + (count * metrics().debug_font_width()); if (iter == 0) + { FillRect(dc, &bounds, bgbrush); + if (do_filldown) + { + COLORREF const filldown = metrics().view_colors(last_attrib & DCA_ANCILLARY).second; + if (oldbg != filldown) + { + DeleteObject(bgbrush); + bgbrush = CreateSolidBrush(filldown); + oldbg = filldown; + } + RECT padding = bounds; + padding.top = padding.bottom; + padding.bottom = client.bottom; + FillRect(dc, &padding, bgbrush); + } + } else + { ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr); + } bounds.left = bounds.right; count = 0; } // set the new colors - if (iter == 0 && oldbg != bgcolor) + if (iter == 1) + { + SetTextColor(dc, fgcolor); + } + else if (oldbg != bgcolor) { DeleteObject(bgbrush); bgbrush = CreateSolidBrush(bgcolor); } - else if (iter == 1) - SetTextColor(dc, fgcolor); last_attrib = viewdata[col].attrib; } @@ -383,33 +575,43 @@ void debugview_info::draw_contents(HDC windc) } // flush any remaining stuff - if (count > 0) - { - bounds.right = bounds.left + (count * metrics().debug_font_width()); - if (iter == 0) - FillRect(dc, &bounds, bgbrush); - else - ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr); - } - - // erase to the end of the line + bounds.right = bounds.left + (count * metrics().debug_font_width()); if (iter == 0) { - bounds.left = bounds.right; + // erase to the end of the line bounds.right = client.right; FillRect(dc, &bounds, bgbrush); + if (do_filldown) + { + COLORREF const filldown = metrics().view_colors(last_attrib & DCA_ANCILLARY).second; + if (bgcolor != filldown) + { + DeleteObject(bgbrush); + bgbrush = CreateSolidBrush(filldown); + } + bounds.top = bounds.bottom; + bounds.bottom = client.bottom; + FillRect(dc, &bounds, bgbrush); + } DeleteObject(bgbrush); } + else if (count > 0) + { + ExtTextOut(dc, bounds.left, bounds.top, 0, nullptr, buffer, count, nullptr); + } } // advance viewdata viewdata += visarea.x; } - // erase anything beyond the bottom with white - GetClientRect(m_wnd, &client); - client.top = visarea.y * metrics().debug_font_height(); - FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH)); + // prevent garbage from showing in the corner + if (show_hscroll) + { + client.top = client.bottom; + client.bottom = client.top + metrics().hscroll_height(); + FillRect(dc, &client, (HBRUSH)GetStockObject(WHITE_BRUSH)); + } // reset the font SetBkMode(dc, oldbkmode); @@ -428,47 +630,48 @@ void debugview_info::draw_contents(HDC windc) void debugview_info::update() { - RECT bounds, vscroll_bounds, hscroll_bounds; - debug_view_xy totalsize, visiblesize, topleft; - bool show_vscroll, show_hscroll; SCROLLINFO scrollinfo; + // get the updated total rows/cols and left row/col + debug_view_xy const totalsize = m_view->total_size(); + debug_view_xy topleft = m_view->visible_position(); + // get the view window bounds + RECT bounds; GetClientRect(m_wnd, &bounds); + debug_view_xy visiblesize; visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width(); visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height(); - // get the updated total rows/cols and left row/col - totalsize = m_view->total_size(); - topleft = m_view->visible_position(); - // determine if we need to show the scrollbars - show_vscroll = show_hscroll = false; - if (totalsize.x > visiblesize.x && bounds.bottom >= metrics().hscroll_height()) + bool const fit_hscroll = (bounds.bottom - bounds.top) > metrics().hscroll_height(); + bool show_hscroll = fit_hscroll && (totalsize.x > visiblesize.x); + if (show_hscroll) { bounds.bottom -= metrics().hscroll_height(); visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height(); - show_hscroll = true; - } - if (totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width()) - { - bounds.right -= metrics().vscroll_width(); - visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width(); - show_vscroll = true; } - if (!show_vscroll && totalsize.y > visiblesize.y && bounds.right >= metrics().vscroll_width()) + bool const fit_vscroll = (bounds.right - bounds.left) > metrics().vscroll_width(); + bool const show_vscroll = fit_vscroll && (totalsize.y > visiblesize.y); + if (show_vscroll) { bounds.right -= metrics().vscroll_width(); visiblesize.x = (bounds.right - bounds.left) / metrics().debug_font_width(); - show_vscroll = true; + if (fit_hscroll && !show_hscroll && (totalsize.x > visiblesize.x)) + { + bounds.bottom -= metrics().hscroll_height(); + visiblesize.y = (bounds.bottom - bounds.top) / metrics().debug_font_height(); + show_hscroll = true; + } } // compute the bounds of the scrollbars + RECT vscroll_bounds; GetClientRect(m_wnd, &vscroll_bounds); vscroll_bounds.left = vscroll_bounds.right - metrics().vscroll_width(); if (show_hscroll) vscroll_bounds.bottom -= metrics().hscroll_height(); - + RECT hscroll_bounds; GetClientRect(m_wnd, &hscroll_bounds); hscroll_bounds.top = hscroll_bounds.bottom - metrics().hscroll_height(); if (show_vscroll) @@ -481,26 +684,34 @@ void debugview_info::update() topleft.x = std::max(totalsize.x - visiblesize.x, 0); // fill out the scroll info struct for the vertical scrollbar - scrollinfo.cbSize = sizeof(scrollinfo); - scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; - scrollinfo.nMin = 0; - scrollinfo.nMax = totalsize.y - 1; - scrollinfo.nPage = visiblesize.y; - scrollinfo.nPos = topleft.y; - SetScrollInfo(m_vscroll, SB_CTL, &scrollinfo, TRUE); + if (m_vscroll) + { + scrollinfo.cbSize = sizeof(scrollinfo); + scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + scrollinfo.nMin = 0; + scrollinfo.nMax = totalsize.y - 1; + scrollinfo.nPage = visiblesize.y; + scrollinfo.nPos = topleft.y; + SetScrollInfo(m_vscroll, SB_CTL, &scrollinfo, TRUE); + } // fill out the scroll info struct for the horizontal scrollbar - scrollinfo.cbSize = sizeof(scrollinfo); - scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; - scrollinfo.nMin = 0; - scrollinfo.nMax = totalsize.x - 1; - scrollinfo.nPage = visiblesize.x; - scrollinfo.nPos = topleft.x; - SetScrollInfo(m_hscroll, SB_CTL, &scrollinfo, TRUE); + if (m_hscroll) + { + scrollinfo.cbSize = sizeof(scrollinfo); + scrollinfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; + scrollinfo.nMin = 0; + scrollinfo.nMax = totalsize.x - 1; + scrollinfo.nPage = visiblesize.x; + scrollinfo.nPos = topleft.x; + SetScrollInfo(m_hscroll, SB_CTL, &scrollinfo, TRUE); + } // update window info - visiblesize.y++; - visiblesize.x++; + if (((bounds.right - bounds.left) > (visiblesize.x * metrics().debug_font_width())) && ((topleft.x + visiblesize.x) < totalsize.x)) + visiblesize.x++; + if (((bounds.bottom - bounds.top) > (visiblesize.y * metrics().debug_font_height())) && ((topleft.y + visiblesize.y) < totalsize.y)) + visiblesize.y++; m_view->set_visible_size(visiblesize); m_view->set_visible_position(topleft); @@ -580,7 +791,41 @@ uint32_t debugview_info::process_scroll(WORD type, HWND wnd) scrollinfo.nPos = result; SetScrollInfo(wnd, SB_CTL, &scrollinfo, TRUE); - return (uint32_t)result; + return uint32_t(result); +} + + +bool debugview_info::process_context_menu(int x, int y) +{ + // don't show a menu if not in client rect + RECT clientrect; + GetClientRect(m_wnd, &clientrect); + POINT loc{ x, y }; + ScreenToClient(m_wnd, &loc); + if (!PtInRect(&clientrect, loc)) + return false; + + // create the context menu if we haven’t already + if (!m_contextmenu) + { + m_contextmenu = CreatePopupMenu(); + if (!m_contextmenu) + return false; + add_items_to_context_menu(m_contextmenu); + } + + // show the context menu + update_context_menu(m_contextmenu); + BOOL const command(TrackPopupMenu( + m_contextmenu, + (GetSystemMetrics(SM_MENUDROPALIGNMENT) ? TPM_RIGHTALIGN : TPM_LEFTALIGN) | TPM_LEFTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, + x, y, + 0, + m_wnd, + nullptr)); + if (command) + handle_context_menu(command); + return true; } @@ -603,7 +848,7 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam) case WM_SYSKEYDOWN: if (wparam != VK_F10) return DefWindowProc(m_wnd, message, wparam, lparam); - // (fall through) + [[fallthrough]]; case WM_KEYDOWN: { if (m_owner.handle_key(wparam, lparam)) @@ -717,17 +962,33 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam) // mouse click case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: { - debug_view_xy topleft = m_view->visible_position(); + debug_view_xy const topleft = m_view->visible_position(); + debug_view_xy const visiblesize = m_view->visible_size(); debug_view_xy newpos; - newpos.x = topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(); - newpos.y = topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(); - m_view->process_click(DCK_LEFT_CLICK, newpos); + newpos.x = std::max(std::min<int>(topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(), topleft.x + visiblesize.x - 1), 0); + newpos.y = std::max(std::min<int>(topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(), topleft.y + visiblesize.y - 1), 0); + m_view->process_click((message == WM_LBUTTONDOWN) ? DCK_LEFT_CLICK : DCK_MIDDLE_CLICK, newpos); SetFocus(m_wnd); break; } - // hscroll + // right click + case WM_RBUTTONDOWN: + if (m_view->cursor_supported()) + { + debug_view_xy const topleft = m_view->visible_position(); + debug_view_xy const visiblesize = m_view->visible_size(); + debug_view_xy newpos; + newpos.x = std::max(std::min<int>(topleft.x + GET_X_LPARAM(lparam) / metrics().debug_font_width(), topleft.x + visiblesize.x - 1), 0); + newpos.y = std::max(std::min<int>(topleft.y + GET_Y_LPARAM(lparam) / metrics().debug_font_height(), topleft.y + visiblesize.y - 1), 0); + m_view->set_cursor_position(newpos); + m_view->set_cursor_visible(true); + } + return DefWindowProc(m_wnd, message, wparam, lparam); + + // horizontal scroll case WM_HSCROLL: { debug_view_xy topleft = m_view->visible_position(); @@ -737,7 +998,7 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam) break; } - // vscroll + // vertical scroll case WM_VSCROLL: { debug_view_xy topleft = m_view->visible_position(); @@ -747,6 +1008,11 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam) break; } + case WM_CONTEXTMENU: + if (!process_context_menu(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam))) + return DefWindowProc(m_wnd, message, wparam, lparam); + break; + // everything else: defaults default: return DefWindowProc(m_wnd, message, wparam, lparam); @@ -758,7 +1024,7 @@ LRESULT debugview_info::view_proc(UINT message, WPARAM wparam, LPARAM lparam) void debugview_info::static_update(debug_view &view, void *osdprivate) { - debugview_info *const info = (debugview_info *)osdprivate; + auto *const info = (debugview_info *)osdprivate; assert(info->m_view == &view); info->update(); } @@ -774,7 +1040,7 @@ LRESULT CALLBACK debugview_info::static_view_proc(HWND wnd, UINT message, WPARAM return 0; } - debugview_info *const info = (debugview_info *)(uintptr_t)GetWindowLongPtr(wnd, GWLP_USERDATA); + auto *const info = (debugview_info *)(uintptr_t)GetWindowLongPtr(wnd, GWLP_USERDATA); if (info == nullptr) return DefWindowProc(wnd, message, wparam, lparam); @@ -810,3 +1076,5 @@ void debugview_info::register_window_class() s_window_class_registered = true; } } + +} // namespace osd::debugger::win |