diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f8c5104..5fd7ff50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # Copyright (c) 2023 By William Su, All Rights Reserved. -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.10...4.1) # set VERSION variables cmake_policy(SET CMP0048 NEW) # provide CMAKE_MSVC_RUNTIME_LIBRARY diff --git a/GHelp/CMakeLists.txt b/GHelp/CMakeLists.txt index 6983893a..4636daca 100644 --- a/GHelp/CMakeLists.txt +++ b/GHelp/CMakeLists.txt @@ -46,7 +46,7 @@ file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/fixhhc.bat "if errorlevel 1 exit /b 0\n" file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/fixhhc.bat "exit /b 1\n") add_custom_command( - OUTPUT CBoard.chm + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/CBoard.chm COMMENT "Make CBoard.chm" DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/gmhelp.h ${CMAKE_CURRENT_SOURCE_DIR}/gmhelpidmap.h @@ -57,4 +57,4 @@ add_custom_command( WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) -add_custom_target(CBHelp ALL DEPENDS cboard.chm) +add_custom_target(CBHelp ALL DEPENDS CBoard.chm) diff --git a/GM/CBDesign.fbp b/GM/CBDesign.fbp index ad6e88a2..77771262 100644 --- a/GM/CBDesign.fbp +++ b/GM/CBDesign.fbp @@ -20509,7 +20509,7 @@ wxID_ANY wxITEM_NORMAL &Delete - wxID_DELETE + wxID_CLEAR none Del diff --git a/GM/CBDesign.xrc b/GM/CBDesign.xrc index c71d01b9..a5e3fba2 100644 --- a/GM/CBDesign.xrc +++ b/GM/CBDesign.xrc @@ -3894,7 +3894,7 @@ Ctrl+M Move clipboard objects to new locations\nMove - + Del Erase the current selection\nDelete (Del) diff --git a/GM/FrmBited.cpp b/GM/FrmBited.cpp index 4b953c7d..20bad4db 100644 --- a/GM/FrmBited.cpp +++ b/GM/FrmBited.cpp @@ -50,7 +50,10 @@ CBitEditFrame::CBitEditFrame(wxDocument& doc, BASE(&doc, &view, &parent, wxID_ANY, doc.GetUserReadableName() + " - Tile Editor"), m_wndSplitter([this, &view]{ - wxSplitterWindow* retval = new wxSplitterWindow(this, + wxSplitterWindow* retval = new wxSplitterWindow; + // KLUDGE: prevent events until m_wndSplitter set + retval->Hide(); + retval->Create(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, @@ -76,6 +79,7 @@ CBitEditFrame::CBitEditFrame(wxDocument& doc, return retval; }()) { + m_wndSplitter->Show(); SetIcon(wxIcon(std::format("#{}", IDR_BITEDITOR), wxBITMAP_TYPE_ICO_RESOURCE, 16, 16)); diff --git a/GM/LBoxTile.cpp b/GM/LBoxTile.cpp index 1963d7c1..5f294f47 100644 --- a/GM/LBoxTile.cpp +++ b/GM/LBoxTile.cpp @@ -34,6 +34,7 @@ const int tileBorder = 3; ///////////////////////////////////////////////////////////////////////////// +#if 0 BEGIN_MESSAGE_MAP(CTileListBox, CGrafixListBox) //{{AFX_MSG_MAP(CTileListBox) //}}AFX_MSG_MAP @@ -171,6 +172,7 @@ BOOL CTileListBox::OnDragSetup(DragInfo& pDI) const } return TRUE; } +#endif ///////////////////////////////////////////////////////////////////////////// diff --git a/GM/VwBitedt.cpp b/GM/VwBitedt.cpp index b0148818..12864968 100644 --- a/GM/VwBitedt.cpp +++ b/GM/VwBitedt.cpp @@ -1081,7 +1081,7 @@ void CBitEditView::OnImageBoardMask(wxCommandEvent& /*event*/) CBoardManager& pBMgr = GetDocument().GetBoardManager(); CBoardMaskDialog dlg(pBMgr); - if (dlg.ShowModal() != wxID_OK || dlg.m_nBrdNum == Invalid_v) + if (dlg.ShowModal() != wxID_OK || dlg.m_nBrdNum == wxNOT_FOUND) return; CBoard& pBoard = pBMgr.GetBoard(value_preserving_cast(dlg.m_nBrdNum)); diff --git a/GM/VwEdtbrd.cpp b/GM/VwEdtbrd.cpp index 933a661c..a00e2947 100644 --- a/GM/VwEdtbrd.cpp +++ b/GM/VwEdtbrd.cpp @@ -263,7 +263,7 @@ void CBrdEditView::OnDraw(wxDC& pDC) wxRect oRct; wxDC* pDrawDC = &pDC; - CB_VERIFY(pDC.GetClippingBox(oRct)); + pDC.GetClippingBox(oRct); if (oRct.IsEmpty()) { return; // Nothing to do @@ -1389,11 +1389,7 @@ void CBrdEditView::OnUpdateToolPalette(wxUpdateUIEvent& pCmdUI) if (pCmdUI.GetId() == XRCID("ID_TOOL_TILE")) { -#if 0 tid = GetDocument().GetTilePalWnd().GetCurrentTileID(); -#else - tid = nullTid; -#endif bEnable = tid != nullTid; if (tid == nullTid && m_nCurToolID == XRCID("ID_TOOL_TILE")) { diff --git a/GP/CBPlay.fbp b/GP/CBPlay.fbp index 9a5a2cd4..1ddd6548 100644 --- a/GP/CBPlay.fbp +++ b/GP/CBPlay.fbp @@ -1,6 +1,6 @@ - + C++ ; @@ -5665,6 +5665,161 @@ + + 0 + wxAUI_MGR_DEFAULT + + + 1 + 0 + 1 + impl_virtual + + + 0 + wxID_ANY + + + CMarkerPalette + + -1,-1 + ; ; forward_declare + + 0 + + + wxTAB_TRAVERSAL + + + bSizer84 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_comboMGrp + 1 + + + protected + 1 + + Resizable + 0 + 1 + + wxCB_SORT + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_listMark + 1 + + + protected + 1 + + Resizable + 1 + + + CMarkListBoxWx; forward_declare; forward_declare + 0 + + + + wxBORDER_SIMPLE|wxWANTS_CHARS + + + + 0 wxAUI_MGR_DEFAULT @@ -7934,13 +8089,13 @@ wxALL 0 - wxID_ANY Snap Grid sbSizer2 wxVERTICAL 1 none + 5 wxEXPAND @@ -8669,13 +8824,13 @@ wxALL 0 - wxID_ANY Cells sbSizer3 wxVERTICAL 1 none + 5 wxTOP|wxRIGHT|wxLEFT @@ -8822,13 +8977,13 @@ wxEXPAND|wxALL 0 - wxID_ANY Auto Stack sbSizer4 wxVERTICAL 1 none + 5 wxEXPAND @@ -9232,13 +9387,13 @@ wxEXPAND|wxALL 0 - wxID_ANY Plotted Moves sbSizer5 wxVERTICAL 1 none + 5 wxEXPAND @@ -14202,37 +14357,33 @@ - + 0 wxAUI_MGR_DEFAULT - wxBOTH 1 0 1 impl_virtual - 0 wxID_ANY - CTrayPropDialog + CTrayPalette - - wxDEFAULT_DIALOG_STYLE + 500,300 ; ; forward_declare - Tray Properties 0 - + wxTAB_TRAVERSAL - bSizer76 + bSizer85 wxVERTICAL none @@ -14241,64 +14392,308 @@ 0 - bSizer77 + bSizer86 wxHORIZONTAL none 5 wxEXPAND - 1 - + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + 0 + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + MyButton + + 0 + + 0 + + + 0 - bSizer78 - wxVERTICAL - none - - 5 - wxTOP|wxRIGHT|wxLEFT - 0 - - 1 - 1 - 1 - 1 - 0 - - 0 - 0 - - - - 1 - 0 - 1 - - 1 - 0 - Dock - 0 - Left - 0 - 1 - - 1 - - 0 - 0 - wxID_ANY - Name for Playing Piece Tray: - 0 - - 0 - - - 0 - - 1 - m_staticText53 - 1 - - + 1 + m_bpMenuBtn + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_comboYGrp + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_listTray + 1 + + + protected + 1 + + Resizable + 1 + + wxLB_MULTIPLE + CTrayListBoxWx; forward_declare + 0 + + + + + + + + + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 0 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + CTrayPropDialog + + + wxDEFAULT_DIALOG_STYLE + ; ; forward_declare + Tray Properties + + 0 + + + + + + bSizer76 + wxVERTICAL + none + + 5 + wxEXPAND + 0 + + + bSizer77 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bSizer78 + wxVERTICAL + none + + 5 + wxTOP|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + 0 + + 0 + 0 + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 0 + 1 + + 1 + + 0 + 0 + wxID_ANY + Name for Playing Piece Tray: + 0 + + 0 + + + 0 + + 1 + m_staticText53 + 1 + + protected 1 @@ -14870,13 +15265,13 @@ wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT 0 - wxID_ANY Tray content visibility sbSizer5 wxVERTICAL 1 none + 5 wxALL @@ -15629,16 +16024,1701 @@ 0=PV_MOVEMODE MENU_PV_MOVEMODE protected - - - 1=PV_PLAYMODE - MENU_PV_PLAYMODE - protected - - - 2=PV_SCNMODE - MENU_PV_SCNMODE - protected + + + 0 + 1 + Erase the selection + wxID_ANY + wxITEM_NORMAL + Delete Marker + wxID_CLEAR + none + + + + + + 0 + 1 + Select all markers in the current board view + wxID_ANY + wxITEM_NORMAL + Select All Markers + ID_EDIT_SELALLMARKERS + none + + + + + + Select All Markers From + m_menu3 + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + No Markers + ID_MRKGROUP_FIRST_0 + none + + + + + + m_separator8 + none + + + + 0 + 1 + Automatically stack selected pieces. + wxID_ANY + wxITEM_NORMAL + Auto Stack + ID_ACT_STACK + none + + + + + + 0 + 1 + Autostack selected objects using a offset of zero. + wxID_ANY + wxITEM_NORMAL + Auto Stack Deck + ID_ACT_AUTOSTACK_DECK + none + + + + + + 0 + 1 + Randomize the stacking order of the selected objects + wxID_ANY + wxITEM_NORMAL + Shuffle Objects + ID_ACT_SHUFFLE_SELECTED + none + + + + + m_separator9 + none + + + + 0 + 1 + Move selected piece(s) in front of other pieces + wxID_ANY + wxITEM_NORMAL + Move To Front + ID_ACT_TOFRONT + none + + + + + + 0 + 1 + Move selected pieces(s) behind other pieces + wxID_ANY + wxITEM_NORMAL + Move To Back + ID_ACT_TOBACK + none + + + + + + 0 + 1 + Turn the selected piece over to the next side + wxID_ANY + wxITEM_NORMAL + Turn Piece Over + ID_ACT_TURNOVER + none + + + + + m_separator10 + none + + + + 0 + 1 + Rotate (or wheel) group of pieces or markers by incremental amounts + wxID_ANY + wxITEM_NORMAL + &Rotate Group - Incremental... + ID_ACT_ROTATEGROUP + none + + + + + + 0 + 1 + Rotate piece or marker using incremental amounts + wxID_ANY + wxITEM_NORMAL + Rotate Object - Incremental... + ID_ACT_ROTATEREL + none + + + + + + Rotate Object - Absolute + m_menu4 + protected + + + 0 + 1 + Set all selection piece rotations to zero. + wxID_ANY + wxITEM_NORMAL + Reset Rotation + ID_ACT_ROTATE_0 + none + + + + + m_separator11 + none + + + + Square Faces + m_menu5 + protected + + + 0 + 1 + Set all selection piece rotations to zero. + wxID_ANY + wxITEM_NORMAL + + ID_ACT_ROTATE_0 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 90° + ID_ACT_ROTATE_90 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 180° + ID_ACT_ROTATE_180 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 270° + ID_ACT_ROTATE_270 + none + + + + + + + Hex Faces (Flat Up) + m_menu6 + protected + + + 0 + 1 + Set all selection piece rotations to zero. + wxID_ANY + wxITEM_NORMAL + + ID_ACT_ROTATE_0 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 60° + ID_ACT_ROTATE_60 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 120° + ID_ACT_ROTATE_120 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 180° + ID_ACT_ROTATE_180 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 240° + ID_ACT_ROTATE_240 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 300° + ID_ACT_ROTATE_300 + none + + + + + + + Hex Faces (Point Up) + m_menu7 + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 30° + ID_ACT_ROTATE_30 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 90° + ID_ACT_ROTATE_90 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 150° + ID_ACT_ROTATE_150 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 210° + ID_ACT_ROTATE_210 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 270° + ID_ACT_ROTATE_270 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 330° + ID_ACT_ROTATE_330 + none + + + + + + + Diamond Faces + m_menu8 + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 45° + ID_ACT_ROTATE_45 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 135° + ID_ACT_ROTATE_135 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 225° + ID_ACT_ROTATE_225 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 315° + ID_ACT_ROTATE_315 + none + + + + + + + m_separator20 + none + + + + 0 + 1 + Take ownership of selected pieces. + wxID_ANY + wxITEM_NORMAL + Take Ownership + ID_ACT_TAKE_OWNERSHIP + none + + + + + + 0 + 1 + Release ownership of selected pieces + wxID_ANY + wxITEM_NORMAL + Release Ownership + ID_ACT_RELEASE_OWNERSHIP + none + + + + + + 0 + 1 + Explicitly set piece ownership. + wxID_ANY + wxITEM_NORMAL + Set Ownership... + ID_ACT_SET_OWNER + none + + + + + m_separator13 + none + + + + 0 + 1 + Lock or unlock pieces and markers from selection. + wxID_ANY + wxITEM_CHECK + Lock Objects + ID_ACT_LOCKOBJECT + none + + + + + + 0 + 1 + Temporarily suspend piece and marker locks + wxID_ANY + wxITEM_CHECK + Suspend Object Locks + ID_ACT_LOCK_SUSPEND + none + + + + + m_separator14 + none + + + + 0 + 1 + Roll Dice + wxID_ANY + wxITEM_NORMAL + Roll Dice... + ID_ACTIONS_ROLLDICE + none + + + + + + 0 + 1 + Enter message for opponent + wxID_ANY + wxITEM_NORMAL + Enter Message... + ID_ACT_DOMESSAGE + none + + + + + + 0 + 1 + Edit text associated with a piece or marker + wxID_ANY + wxITEM_NORMAL + Edit Object Text... + ID_EDIT_ELEMENT_TEXT + none + + + + + m_separator15 + none + + + + Compound Move + m_menu9 + protected + + + 0 + 1 + Begin compound move + wxID_ANY + wxITEM_NORMAL + Begin a Compound Move + ID_ACT_COMPOUNDMOVE_BEGIN + none + + + + + + 0 + 1 + End active compound move + wxID_ANY + wxITEM_NORMAL + Accept Compound Move + ID_ACT_COMPOUNDMOVE_END + none + + + + + + 0 + 1 + Discard current compound move + wxID_ANY + wxITEM_NORMAL + Discard Compound Move + ID_ACT_COMPOUNDMOVE_DISCARD + none + + + + + + + Plotted Move + m_menu11 + protected + + + 0 + 1 + Begin a plotted move. + wxID_ANY + wxITEM_CHECK + Begin a Plotted Move + ID_PTOOL_PLOTMOVE + none + + + + + + 0 + 1 + Record the plotted move + wxID_ANY + wxITEM_NORMAL + Accept Plotted Move + ID_ACT_PLOTDONE + none + + + + + + 0 + 1 + Discard the plotted move + wxID_ANY + wxITEM_NORMAL + Discard Plotted Move + ID_ACT_PLOTDISCARD + none + + + + + + m_separator16 + none + + + + 0 + 1 + Show full scale board + wxID_ANY + wxITEM_RADIO + Full Scale Board + ID_VIEW_FULLSCALEBRD + none + + + + + + 0 + 1 + Show half scale board + wxID_ANY + wxITEM_RADIO + Half Scale Board + ID_VIEW_HALFSCALEBRD + none + + + + + + 0 + 1 + Show small scale board + wxID_ANY + wxITEM_RADIO + Small Scale Board + ID_VIEW_SMALLSCALEBRD + none + + + + + m_separator17 + none + + + + 0 + 1 + Split board view horizontally into two rows. + wxID_ANY + wxITEM_NORMAL + Horizontal Split + ID_VIEW_SPLITBOARDROWS + none + + + + + + 0 + 1 + Split board view vertically into two columns. + wxID_ANY + wxITEM_NORMAL + Vertical Split + ID_VIEW_SPLITBOARDCOLS + none + + + + + m_separator18 + none + + + + 0 + 1 + Hide or show pieces on board + wxID_ANY + wxITEM_CHECK + Hide Pieces + ID_VIEW_PIECES + none + + + + + + 0 + 1 + View the board and trays as if the current player was a spectator. + wxID_ANY + wxITEM_NORMAL + Simulate Spectator Player + ID_ACT_SIMULATE_SPECTATOR + none + + + + + + 1=PV_PLAYMODE + MENU_PV_PLAYMODE + protected + + + 0 + 1 + Jump to start of moves + wxID_ANY + wxITEM_NORMAL + Start of Moves + ID_PBCK_START + none + + + + + + 0 + 1 + Do the next move + wxID_ANY + wxITEM_NORMAL + Next Move + ID_PBCK_NEXT + none + + + + + + 0 + 1 + Step back to previous move + wxID_ANY + wxITEM_NORMAL + Previous Move + ID_PBCK_PREVIOUS + none + + + + + + 0 + 1 + Jump to end of move + wxID_ANY + wxITEM_NORMAL + End of Moves + ID_PBCK_END + none + + + + + m_separator29 + none + + + + 0 + 1 + Toggles automatic playback feature. + wxID_ANY + wxITEM_NORMAL + Automatic Playback + ID_PBCK_AUTO_STEP + none + + + + + m_separator30 + none + + + + 0 + 1 + If checked, compound moves are single stepped. + wxID_ANY + wxITEM_NORMAL + Single Step Compound Moves + ID_PBCK_STEP_CMOVES + none + + + + + + 0 + 1 + Next move automatically steps to next history entry on last move. + wxID_ANY + wxITEM_NORMAL + Automatically Step to Next History + ID_PBCK_STEP_TO_NEXT_HIST + none + + + + + + 0 + 1 + Keep graphical move indications when skipping moves. + wxID_ANY + wxITEM_NORMAL + Keep Skipped Move Indications + ID_PBCK_SKIP_KEEP_IND + none + + + + + m_separator31 + none + + + + 0 + 1 + Display current message text + wxID_ANY + wxITEM_NORMAL + Show Current Message... + ID_PBCK_READMESSAGE + none + + + + + m_separator32 + none + + + + 0 + 1 + Close current history playback and open the next + wxID_ANY + wxITEM_NORMAL + Next History Entry + ID_PBCK_NEXTHIST + none + + + + + + 0 + 1 + Close history playback mode. + wxID_ANY + wxITEM_NORMAL + Close History Playback + ID_PBCK_CLOSEHIST + none + + + + + m_separator33 + none + + + + 0 + 1 + Show full scale board + wxID_ANY + wxITEM_RADIO + Full Scale Board + ID_VIEW_FULLSCALEBRD + none + + + + + + 0 + 1 + Show half scale board + wxID_ANY + wxITEM_RADIO + Half Scale Board + ID_VIEW_HALFSCALEBRD + none + + + + + + 0 + 1 + Show small scale board + wxID_ANY + wxITEM_RADIO + Small Scale Board + ID_VIEW_SMALLSCALEBRD + none + + + + + m_separator34 + none + + + + 0 + 1 + Split board view horizontally into two rows. + wxID_ANY + wxITEM_NORMAL + Horizontal Split + ID_VIEW_SPLITBOARDROWS + none + + + + + + 0 + 1 + Split board view vertically into two columns. + wxID_ANY + wxITEM_NORMAL + Vertical Split + ID_VIEW_SPLITBOARDCOLS + none + + + + + m_separator35 + none + + + + 0 + 1 + Hide or show pieces on board + wxID_ANY + wxITEM_NORMAL + Hide Pieces + ID_VIEW_PIECES + none + + + + + + 0 + 1 + Draw movement playback indicators on top of pieces. + wxID_ANY + wxITEM_NORMAL + Indicators On Top + ID_VIEW_DRAW_IND_ON_TOP + none + + + + + + 0 + 1 + View the board and trays as if the current player was a spectator. + wxID_ANY + wxITEM_NORMAL + Simulate Spectator Player + ID_ACT_SIMULATE_SPECTATOR + none + + + + + m_separator36 + none + + + + 0 + 1 + Finishes and accepts the move file being played back. Adds to game history. + wxID_ANY + wxITEM_NORMAL + Accept Move File Playback... + ID_PBCK_FINISH + none + + + + + + 0 + 1 + Discard the current move recording. + wxID_ANY + wxITEM_NORMAL + Discard Move File Playback... + ID_PBCK_DISCARD + none + + + + + + 2=PV_SCNMODE + MENU_PV_SCNMODE + protected + + + 0 + 1 + Erase the selection + wxID_ANY + wxITEM_NORMAL + Delete Marker + wxID_CLEAR + none + + + + + + 0 + 1 + Select all markers in the current board view + wxID_ANY + wxITEM_NORMAL + Select All Markers + ID_EDIT_SELALLMARKERS + none + + + + + m_separator37 + none + + + + 0 + 1 + Automatically stack selected pieces. + wxID_ANY + wxITEM_NORMAL + Auto Stack + ID_ACT_STACK + none + + + + + + 0 + 1 + Autostack selected objects using a offset of zero. + wxID_ANY + wxITEM_NORMAL + Auto Stack Deck + ID_ACT_AUTOSTACK_DECK + none + + + + + + 0 + 1 + Randomize the stacking order of the selected objects + wxID_ANY + wxITEM_NORMAL + Shuffle Objects + ID_ACT_SHUFFLE_SELECTED + none + + + + + m_separator38 + none + + + + 0 + 1 + Move selected piece(s) in front of other pieces + wxID_ANY + wxITEM_NORMAL + Move To Front + ID_ACT_TOFRONT + none + + + + + + 0 + 1 + Move selected piece(s) in front of other pieces + wxID_ANY + wxITEM_NORMAL + Move To Back + ID_ACT_TOBACK + none + + + + + + 0 + 1 + Turn the selected piece over to the next side + wxID_ANY + wxITEM_NORMAL + Turn Piece Over + ID_ACT_TURNOVER + none + + + + + m_separator39 + none + + + + 0 + 1 + Rotate (or wheel) group of pieces or markers by incremental amounts + wxID_ANY + wxITEM_NORMAL + &Rotate Group - Incremental... + ID_ACT_ROTATEGROUP + none + + + + + + 0 + 1 + Rotate piece or marker using incremental amounts + wxID_ANY + wxITEM_NORMAL + Rotate Object - Incremental... + ID_ACT_ROTATEREL + none + + + + + + Rotate Object - Absolute + m_menu41 + protected + + + 0 + 1 + Set all selection piece rotations to zero. + wxID_ANY + wxITEM_NORMAL + Reset Rotation + ID_ACT_ROTATE_0 + none + + + + + m_separator111 + none + + + + Square Faces + m_menu51 + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + + ID_ACT_ROTATE_0 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 90° + ID_ACT_ROTATE_90 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 180° + ID_ACT_ROTATE_180 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 270° + ID_ACT_ROTATE_270 + none + + + + + + + Hex Faces (Flat Up) + m_menu61 + protected + + + 0 + 1 + Set all selection piece rotations to zero. + wxID_ANY + wxITEM_NORMAL + + ID_ACT_ROTATE_0 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 60° + ID_ACT_ROTATE_60 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 120° + ID_ACT_ROTATE_120 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 180° + ID_ACT_ROTATE_180 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 240° + ID_ACT_ROTATE_240 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 300° + ID_ACT_ROTATE_300 + none + + + + + + + Hex Faces (Point Up) + m_menu71 + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 30° + ID_ACT_ROTATE_30 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 90° + ID_ACT_ROTATE_90 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 150° + ID_ACT_ROTATE_150 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 210° + ID_ACT_ROTATE_210 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 270° + ID_ACT_ROTATE_270 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 330° + ID_ACT_ROTATE_330 + none + + + + + + + Diamond Faces + m_menu81 + protected + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 45° + ID_ACT_ROTATE_45 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 135° + ID_ACT_ROTATE_135 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 225° + ID_ACT_ROTATE_225 + none + + + + + + 0 + 1 + + wxID_ANY + wxITEM_NORMAL + 315° + ID_ACT_ROTATE_315 + none + + + + + + + m_separator42 + none + + + + 0 + 1 + Lock or unlock pieces and markers from selection. + wxID_ANY + wxITEM_CHECK + Lock Objects + ID_ACT_LOCKOBJECT + none + + + + + + 0 + 1 + Temporarily suspend piece and marker locks + wxID_ANY + wxITEM_CHECK + Suspend Object Locks + ID_ACT_LOCK_SUSPEND + none + + + + + m_separator43 + none + + + + 0 + 1 + Edit text associated with a piece or marker + wxID_ANY + wxITEM_NORMAL + Edit Object Text... + ID_EDIT_ELEMENT_TEXT + none + + + + + m_separator44 + none + + + + 0 + 1 + Show full scale board + wxID_ANY + wxITEM_RADIO + Full Scale Board + ID_VIEW_FULLSCALEBRD + none + + + + + + 0 + 1 + Show half scale board + wxID_ANY + wxITEM_RADIO + Half Scale Board + ID_VIEW_HALFSCALEBRD + none + + + + + + 0 + 1 + Show small scale board + wxID_ANY + wxITEM_RADIO + Small Scale Board + ID_VIEW_SMALLSCALEBRD + none + + + + + m_separator45 + none + + + + 0 + 1 + Split board view horizontally into two rows. + wxID_ANY + wxITEM_NORMAL + Horizontal Split + ID_VIEW_SPLITBOARDROWS + none + + + + + + 0 + 1 + Split board view vertically into two columns. + wxID_ANY + wxITEM_NORMAL + Vertical Split + ID_VIEW_SPLITBOARDCOLS + none + + + + + m_separator47 + none + + + + 0 + 1 + Hide or show pieces on board + wxID_ANY + wxITEM_CHECK + Hide Pieces + ID_VIEW_PIECES + none + + + + + + 0 + 1 + Enable or disable current board's snap grid + wxID_ANY + wxITEM_NORMAL + Snap Grid + ID_VIEW_SNAPGRID + none + + + 3=PJ_GSN_DEFAULT @@ -15774,6 +17854,173 @@ 5=PV_PIECE_TRAY MENU_PV_PIECE_TRAY protected + + + Turn Selected Pieces Over + m_menu1 + protected + + + 0 + 1 + Turn the selected piece over to the next side + wxID_ANY + wxITEM_NORMAL + &Next + ID_ACT_TURNOVER + none + + + + + + 0 + 1 + Turn the selected piece over to the prev side + wxID_ANY + wxITEM_NORMAL + &Prev + ID_ACT_TURNOVER_PREV + none + + + + + + 0 + 1 + Turn the selected piece over to a random side + wxID_ANY + wxITEM_NORMAL + &Random + ID_ACT_TURNOVER_RANDOM + none + + + + + + + Turn All Pieces Over + m_menu2 + protected + + + 0 + 1 + Turn over all pieces in the Tray to the next side. + wxID_ANY + wxITEM_NORMAL + &Next + ID_ACT_TURNOVER_ALL + none + + + + + + 0 + 1 + Turn over all pieces in the Tray to the previous side. + wxID_ANY + wxITEM_NORMAL + &Prev + ID_ACT_TURNOVER_ALL_PREV + none + + + + + + 0 + 1 + Turn over all pieces in the Tray to a random side. + wxID_ANY + wxITEM_NORMAL + &Random + ID_ACT_TURNOVER_ALL_RANDOM + none + + + + + + + 0 + 1 + Turn the clicked piece over to the clicked side + wxID_ANY + wxITEM_NORMAL + Turn Over to Clicked Side + ID_ACT_TURNOVER_SELECT + none + + + + + m_separator5 + none + + + + 0 + 1 + Shuffle (randomize) only the tray's selected items. + wxID_ANY + wxITEM_NORMAL + Shuffle Selected Items + ID_PTRAY_SHUFFLE_SELECTED + none + + + + + + 0 + 1 + Shuffle (randomize) the tray's contents + wxID_ANY + wxITEM_NORMAL + Shuffle All Pieces + ID_PTRAY_SHUFFLE + none + + + + + m_separator6 + none + + + + 0 + 1 + Edit text associated with a piece or marker + wxID_ANY + wxITEM_NORMAL + Edit Object Text... + ID_EDIT_ELEMENT_TEXT + none + + + + + m_separator7 + none + + + + 0 + 1 + Show information about the currently selected tray. + wxID_ANY + wxITEM_NORMAL + About the Selected Tray... + ID_PTRAY_ABOUT + none + + + 6=MV_RICHEDIT @@ -15789,6 +18036,58 @@ 8=PV_SELCT_BOX MENU_PV_SELCT_BOX protected + + + 0 + 1 + Turn the selected piece over to the next side + wxID_ANY + wxITEM_NORMAL + &Next + ID_ACT_TURNOVER + none + + + + + + 0 + 1 + Turn the selected piece over to the prev side + wxID_ANY + wxITEM_NORMAL + &Prev + ID_ACT_TURNOVER_PREV + none + + + + + + 0 + 1 + Turn the selected piece over to a random side + wxID_ANY + wxITEM_NORMAL + &Random + ID_ACT_TURNOVER_RANDOM + none + + + + + + 0 + 1 + Turn the clicked piece over to the clicked side + wxID_ANY + wxITEM_NORMAL + &Clicked Side + ID_ACT_TURNOVER_SELECT + none + + + diff --git a/GP/CBPlay.xrc b/GP/CBPlay.xrc index 40590c72..f49e421f 100644 --- a/GP/CBPlay.xrc +++ b/GP/CBPlay.xrc @@ -1074,6 +1074,30 @@ + + + + wxVERTICAL + + wxEXPAND + 5 + + + + 0 + + + + + wxEXPAND + 5 + + + + + + + Enter Move Description @@ -2708,6 +2732,48 @@ + + 500,300 + + + wxVERTICAL + + wxEXPAND + 5 + + + wxHORIZONTAL + + wxEXPAND + 5 + + + 0 + 0 + + + + + wxALIGN_CENTER_VERTICAL + 5 + + + 0 + + + + + + + wxEXPAND + 5 + + + + + + + Tray Properties @@ -2960,12 +3026,670 @@ + + + + Erase the selection + + + + + Select all markers in the current board view + + + + + + + + + + + + + + Automatically stack selected pieces. + + + + + Autostack selected objects using a offset of zero. + + + + + Randomize the stacking order of the selected objects + + + + + + Move selected piece(s) in front of other pieces + + + + + Move selected pieces(s) behind other pieces + + + + + Turn the selected piece over to the next side + + + + + + Rotate (or wheel) group of pieces or markers by incremental amounts + + + + + Rotate piece or marker using incremental amounts + + + + + + + Set all selection piece rotations to zero. + + + + + + + + Set all selection piece rotations to zero. + + + + + + + + + + + + + + + + + + + + + + + Set all selection piece rotations to zero. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Take ownership of selected pieces. + + + + + Release ownership of selected pieces + + + + + Explicitly set piece ownership. + + + + + + Lock or unlock pieces and markers from selection. + 1 + + + + + Temporarily suspend piece and marker locks + 1 + + + + + + Roll Dice + + + + + Enter message for opponent + + + + + Edit text associated with a piece or marker + + + + + + + + Begin compound move + + + + + End active compound move + + + + + Discard current compound move + + + + + + + + Begin a plotted move. + 1 + + + + + Record the plotted move + + + + + Discard the plotted move + + + + + + + Show full scale board + 1 + + + + + Show half scale board + 1 + + + + + Show small scale board + 1 + + + + + + Split board view horizontally into two rows. + + + + + Split board view vertically into two columns. + + + + + + Hide or show pieces on board + 1 + + + + + View the board and trays as if the current player was a spectator. + + + + + Jump to start of moves + + + + + Do the next move + + + + + Step back to previous move + + + + + Jump to end of move + + + + + + Toggles automatic playback feature. + + + + + + If checked, compound moves are single stepped. + + + + + Next move automatically steps to next history entry on last move. + + + + + Keep graphical move indications when skipping moves. + + + + + + Display current message text + + + + + + Close current history playback and open the next + + + + + Close history playback mode. + + + + + + Show full scale board + 1 + + + + + Show half scale board + 1 + + + + + Show small scale board + 1 + + + + + + Split board view horizontally into two rows. + + + + + Split board view vertically into two columns. + + + + + + Hide or show pieces on board + + + + + Draw movement playback indicators on top of pieces. + + + + + View the board and trays as if the current player was a spectator. + + + + + + Finishes and accepts the move file being played back. Adds to game history. + + + + + Discard the current move recording. + + + + + Erase the selection + + + + + Select all markers in the current board view + + + + + + Automatically stack selected pieces. + + + + + Autostack selected objects using a offset of zero. + + + + + Randomize the stacking order of the selected objects + + + + + + Move selected piece(s) in front of other pieces + + + + + Move selected piece(s) in front of other pieces + + + + + Turn the selected piece over to the next side + + + + + + Rotate (or wheel) group of pieces or markers by incremental amounts + + + + + Rotate piece or marker using incremental amounts + + + + + + + Set all selection piece rotations to zero. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Set all selection piece rotations to zero. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lock or unlock pieces and markers from selection. + 1 + + + + + Temporarily suspend piece and marker locks + 1 + + + + + + Edit text associated with a piece or marker + + + + + + Show full scale board + 1 + + + + + Show half scale board + 1 + + + + + Show small scale board + 1 + + + + + + Split board view horizontally into two rows. + + + + + Split board view vertically into two columns. + + + + + + Hide or show pieces on board + 1 + + + + + Enable or disable current board's snap grid + @@ -3019,6 +3743,70 @@ + + + + + + Turn the selected piece over to the next side + + + + + Turn the selected piece over to the prev side + + + + + Turn the selected piece over to a random side + + + + + + + + Turn over all pieces in the Tray to the next side. + + + + + Turn over all pieces in the Tray to the previous side. + + + + + Turn over all pieces in the Tray to a random side. + + + + + + Turn the clicked piece over to the clicked side + + + + + + Shuffle (randomize) only the tray's selected items. + + + + + Shuffle (randomize) the tray's contents + + + + + + Edit text associated with a piece or marker + + + + + + Show information about the currently selected tray. + @@ -3028,6 +3816,26 @@ + + + + Turn the selected piece over to the next side + + + + + Turn the selected piece over to the prev side + + + + + Turn the selected piece over to a random side + + + + + Turn the clicked piece over to the clicked side + diff --git a/GP/DlgRotpc.cpp b/GP/DlgRotpc.cpp index 04397174..0e039ad7 100644 --- a/GP/DlgRotpc.cpp +++ b/GP/DlgRotpc.cpp @@ -1,6 +1,6 @@ // DlgRotpc.cpp : implementation file // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -35,11 +35,10 @@ static char THIS_FILE[] = __FILE__; ///////////////////////////////////////////////////////////////////////////// // CRotatePieceDialog dialog -CRotatePieceDialog::CRotatePieceDialog(CWnd& v, wxWindow* pParent /*= &CB::GetMainWndWx()*/) : - CB_XRC_BEGIN_CTRLS_DEFN(pParent, CRotatePieceDialog) +CRotatePieceDialog::CRotatePieceDialog(wxWindow& pParent) : + CB_XRC_BEGIN_CTRLS_DEFN(&pParent, CRotatePieceDialog) CB_XRC_CTRL_VAL(m_editCurVal, m_nRelativeRotation, -359, 359, wxNUM_VAL_SIGN_PLUS) - CB_XRC_END_CTRLS_DEFN(), - view(&v) + CB_XRC_END_CTRLS_DEFN() { // KLUDGE: don't see a way to use GetSizeFromText() in .xrc wxSize size = m_editCurVal->GetSizeFromText("+999"_cbstring); @@ -104,7 +103,8 @@ void CRotatePieceDialog::OnContextMenu(CWnd* pWnd, CPoint point) void CRotatePieceDialog::ApplyOffset(int nOffset) { m_nRelativeRotation = (m_nRelativeRotation + nOffset) % 360; - view->SendMessage(WM_ROTATEPIECE_DELTA, (WPARAM)m_nRelativeRotation); + RotatePieceDeltaEvent event(m_nRelativeRotation); + GetParent()->ProcessWindowEvent(event); TransferDataToWindow(); } diff --git a/GP/DlgRotpc.h b/GP/DlgRotpc.h index 7bc339bf..e817ea64 100644 --- a/GP/DlgRotpc.h +++ b/GP/DlgRotpc.h @@ -36,10 +36,7 @@ class CRotatePieceDialog : public wxDialog { // Construction public: - /* TEMPORARY: this needs to send msgs to the view, but that - hasn't been converted to wx yet, so can't be passed as - parent */ - CRotatePieceDialog(CWnd& v, wxWindow* pParent = &CB::GetMainWndWx()); // standard constructor + CRotatePieceDialog(wxWindow& pParent); // standard constructor // Dialog Data int m_nRelativeRotation; @@ -68,9 +65,6 @@ class CRotatePieceDialog : public wxDialog afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); #endif wxDECLARE_EVENT_TABLE(); - -private: - RefPtr view; }; #endif diff --git a/GP/FrmDockMark.cpp b/GP/FrmDockMark.cpp index 15adceac..28bdbed1 100644 --- a/GP/FrmDockMark.cpp +++ b/GP/FrmDockMark.cpp @@ -56,7 +56,7 @@ CDockMarkPalette::~CDockMarkPalette() ///////////////////////////////////////////////////////////////////////////// -void CDockMarkPalette::SetChild(CMarkerPalette* pChildWnd) +void CDockMarkPalette::SetChild(CMarkerPaletteContainer* pChildWnd) { if (m_pChildWnd == pChildWnd) return; @@ -98,6 +98,7 @@ void CDockMarkPalette::OnSize(UINT nType, int cx, int cy) void CDockMarkPalette::OnDestroy() { + wxASSERT(!m_pChildWnd); m_pChildWnd = NULL; CDockablePane::OnDestroy(); } diff --git a/GP/FrmDockMark.h b/GP/FrmDockMark.h index 848933a7..6213157b 100644 --- a/GP/FrmDockMark.h +++ b/GP/FrmDockMark.h @@ -1,6 +1,6 @@ // FrmDockMark.h - container window for the marker palette. // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -27,7 +27,7 @@ ///////////////////////////////////////////////////////////////////////////// // CDockMarkPalette window -class CMarkerPalette; +class CMarkerPaletteContainer; class CDockMarkPalette : public CDockablePane { @@ -37,16 +37,16 @@ class CDockMarkPalette : public CDockablePane CDockMarkPalette(); // Attributes -public: - CMarkerPalette* m_pChildWnd; +private: + CB::propagate_const m_pChildWnd; // Operations public: - void SetChild(CMarkerPalette* pChildWnd); + void SetChild(CMarkerPaletteContainer* pChildWnd); // Implementation public: - virtual ~CDockMarkPalette(); + ~CDockMarkPalette() override; // Generated message map functions protected: diff --git a/GP/FrmDockTray.cpp b/GP/FrmDockTray.cpp index a661b633..ca10475f 100644 --- a/GP/FrmDockTray.cpp +++ b/GP/FrmDockTray.cpp @@ -56,7 +56,7 @@ CDockTrayPalette::~CDockTrayPalette() ///////////////////////////////////////////////////////////////////////////// -void CDockTrayPalette::SetChild(CTrayPalette* pChildWnd) +void CDockTrayPalette::SetChild(CTrayPaletteContainer* pChildWnd) { if (m_pChildWnd == pChildWnd) return; diff --git a/GP/FrmDockTray.h b/GP/FrmDockTray.h index 4a84f5aa..ac37c9b2 100644 --- a/GP/FrmDockTray.h +++ b/GP/FrmDockTray.h @@ -27,7 +27,7 @@ ///////////////////////////////////////////////////////////////////////////// // CDockTrayPalette window -class CTrayPalette; +class CTrayPaletteContainer; class CDockTrayPalette : public CDockablePane { @@ -38,11 +38,11 @@ class CDockTrayPalette : public CDockablePane // Attributes public: - CTrayPalette* m_pChildWnd; + CTrayPaletteContainer* m_pChildWnd; // Operations public: - void SetChild(CTrayPalette* pChildWnd); + void SetChild(CTrayPaletteContainer* pChildWnd); // Overrides // ClassWizard generated virtual function overrides diff --git a/GP/FrmMain.cpp b/GP/FrmMain.cpp index f7b0cdae..8b4e9cdc 100644 --- a/GP/FrmMain.cpp +++ b/GP/FrmMain.cpp @@ -1,6 +1,6 @@ // FrmMain.cpp : implementation of the CMainFrame class // -// Copyright (c) 1994-2024 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -399,18 +399,32 @@ void CMainFrame::OnIdle() } } +namespace { + /* CB is currently a mix of MFC and wx, + so need to send both kinds of msg */ + BOOL OnClosePalette(CWnd& pWnd) + { + pWnd.SendMessage(WM_PALETTE_HIDE); + pWnd.SendMessageToDescendants(WM_PALETTE_HIDE, true, true); + wxWindow* wxWnd = CB::FindWxWindow(pWnd); + if (wxWnd) + { + wxCommandEvent event(WM_PALETTE_HIDE_WX); + wxWnd->GetEventHandler()->ProcessEventLocally(event); + CB::SendEventToDescendants(*wxWnd, event, true); + } + return true; + } +} + BOOL CMainFrame::OnCloseMiniFrame(CPaneFrameWnd* pWnd) { - pWnd->SendMessage(WM_PALETTE_HIDE); - pWnd->SendMessageToDescendants(WM_PALETTE_HIDE, true, true); - return true; + return OnClosePalette(CheckedDeref(pWnd)); } BOOL CMainFrame::OnCloseDockingPane(CDockablePane* pWnd) { - pWnd->SendMessage(WM_PALETTE_HIDE); - pWnd->SendMessageToDescendants(WM_PALETTE_HIDE, true, true); - return true; + return OnClosePalette(CheckedDeref(pWnd)); } void CMainFrame::ShowPalettePanes(BOOL bShow) @@ -423,36 +437,36 @@ void CMainFrame::ShowPalettePanes(BOOL bShow) /////////////////////////////////////////////////////////////////////// -void CMainFrame::UpdatePaletteWindow(CWnd* pWnd, BOOL bIsOn) +void CMainFrame::UpdatePaletteWindow(CWnd& pWnd, BOOL bIsOn) { - if (pWnd->m_hWnd != NULL) // Handle exists if palette allowed + if (pWnd.m_hWnd != NULL) // Handle exists if palette allowed { - BOOL bIsControlBar = pWnd->IsKindOf(RUNTIME_CLASS(CBasePane)); - BOOL bVisible = ((pWnd->GetStyle() & WS_VISIBLE) != 0); + BOOL bIsControlBar = pWnd.IsKindOf(RUNTIME_CLASS(CBasePane)); + BOOL bVisible = ((pWnd.GetStyle() & WS_VISIBLE) != 0); CMDIChildWndEx* pMDIChild = (CMDIChildWndEx*)MDIGetActive(); if (pMDIChild == NULL || pMDIChild->IsIconic()) { if (!bIsControlBar && bVisible) - pWnd->ShowWindow(SW_HIDE); + pWnd.ShowWindow(SW_HIDE); else if (bIsControlBar && bVisible) - ShowPane((CBasePane*)pWnd, FALSE, FALSE, FALSE); + ShowPane(&dynamic_cast(pWnd), FALSE, FALSE, FALSE); } else { if (bIsOn && !bVisible) { if (!bIsControlBar) - pWnd->ShowWindow(SW_SHOW); + pWnd.ShowWindow(SW_SHOW); else - ShowPane((CBasePane*)pWnd, TRUE, FALSE, FALSE); + ShowPane(&dynamic_cast(pWnd), TRUE, FALSE, FALSE); } else if (!bIsOn && bVisible) { if (!bIsControlBar) - pWnd->ShowWindow(SW_HIDE); + pWnd.ShowWindow(SW_HIDE); else - ShowPane((CBasePane*)pWnd, FALSE, FALSE, FALSE); + ShowPane(&dynamic_cast(pWnd), FALSE, FALSE, FALSE); } } } diff --git a/GP/FrmMain.h b/GP/FrmMain.h index ee8894e6..b1326a35 100644 --- a/GP/FrmMain.h +++ b/GP/FrmMain.h @@ -1,6 +1,6 @@ // FrmMain.h : interface of the CMainFrame class // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -51,17 +51,17 @@ class CMainFrame : public CMDIFrameWndExCb, public: CDocument* GetCurrentDocument(); - CDockMarkPalette* GetDockingMarkerWindow() { return &m_wndMarkPal; } - CDockTrayPalette* GetDockingTrayAWindow() { return &m_wndTrayPalA; } - CDockTrayPalette* GetDockingTrayBWindow() { return &m_wndTrayPalB; } + CDockMarkPalette& GetDockingMarkerWindow() { return m_wndMarkPal; } + CDockTrayPalette& GetDockingTrayAWindow() { return m_wndTrayPalA; } + CDockTrayPalette& GetDockingTrayBWindow() { return m_wndTrayPalB; } - CReadMsgWnd* GetMessageWindow() { return &m_wndMessage; } + CReadMsgWnd& GetMessageWindow() { return m_wndMessage; } CMFCStatusBar* GetStatusBar() { return &m_wndStatusBar; } // Operations public: - void UpdatePaletteWindow(CWnd* pWnd, BOOL bIsOn); + void UpdatePaletteWindow(CWnd& pWnd, BOOL bIsOn); void ShowPalettePanes(BOOL bShow); void OnIdle(); BOOL OnCloseMiniFrame(CPaneFrameWnd* pWnd) override; diff --git a/GP/FrmPbrd.cpp b/GP/FrmPbrd.cpp index eda068ca..676523ef 100644 --- a/GP/FrmPbrd.cpp +++ b/GP/FrmPbrd.cpp @@ -1,6 +1,6 @@ // FrmPbrd.cpp : implementation file // -// Copyright (c) 1994-2023 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -48,11 +48,14 @@ IMPLEMENT_DYNCREATE(CPlayBoardFrame, CMDIChildWndEx) BEGIN_MESSAGE_MAP(CPlayBoardFrame, CMDIChildWndEx) //{{AFX_MSG_MAP(CPlayBoardFrame) +#if 0 ON_COMMAND(ID_VIEW_HALFSCALEBRD, OnViewHalfScaleBrd) ON_UPDATE_COMMAND_UI(ID_VIEW_HALFSCALEBRD, OnUpdateViewHalfScaleBrd) ON_COMMAND(ID_VIEW_FULLSCALEBRD, OnViewFullScaleBrd) ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCALEBRD, OnUpdateViewFullScaleBrd) +#endif ON_WM_CLOSE() +#if 0 ON_COMMAND(ID_VIEW_SNAPGRID, OnViewSnapGrid) ON_UPDATE_COMMAND_UI(ID_VIEW_SNAPGRID, OnUpdateViewSnapGrid) ON_COMMAND(ID_EDIT_SELALLMARKERS, OnEditSelAllMarkers) @@ -74,6 +77,7 @@ BEGIN_MESSAGE_MAP(CPlayBoardFrame, CMDIChildWndEx) ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER, OnUpdateActTurnOver) ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_PREV, OnUpdateActTurnOver) ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_RANDOM, OnUpdateActTurnOver) +#endif ON_COMMAND(ID_PTOOL_PLOTMOVE, OnActPlotMove) ON_UPDATE_COMMAND_UI(ID_PTOOL_PLOTMOVE, OnUpdateActPlotMove) ON_COMMAND(ID_ACT_PLOTDONE, OnActPlotDone) @@ -85,8 +89,10 @@ BEGIN_MESSAGE_MAP(CPlayBoardFrame, CMDIChildWndEx) ON_COMMAND(ID_VIEW_SPLITBOARDCOLS, OnViewSplitBoardCols) ON_UPDATE_COMMAND_UI(ID_VIEW_SPLITBOARDCOLS, OnUpdateViewSplitBoardCols) //}}AFX_MSG_MAP +#if 0 ON_COMMAND_RANGE(ID_MRKGROUP_FIRST, ID_MRKGROUP_FIRST + 64, OnSelectGroupMarkers) ON_UPDATE_COMMAND_UI_RANGE(ID_MRKGROUP_FIRST, ID_MRKGROUP_FIRST + 64, OnUpdateSelectGroupMarkers) +#endif // Other messages ON_MESSAGE(WM_CENTERBOARDONPOINT, OnMessageCenterBoardOnPoint) ON_MESSAGE(WM_WINSTATE, OnMessageWindowState) @@ -213,14 +219,14 @@ BOOL CPlayBoardFrame::OnCreateClient(LPCREATESTRUCT lpcs, } if (!m_wndSplitter2.CreateView(0, 0, - RUNTIME_CLASS(CSelectedPieceView), + RUNTIME_CLASS(CSelectedPieceViewContainer), CSize(rct.Width() - xSize, ySize), pContext)) { TRACE("Failed to create second Selected Piece pane\n"); return FALSE; } if (!m_wndSplitter2.CreateView(1, 0, - RUNTIME_CLASS(CTinyBoardView), + RUNTIME_CLASS(CTinyBoardViewContainer), CSize(rct.Width() - xSize, rct.Height() - ySize), pContext)) { TRACE("Failed to create small scale map pane\n"); @@ -413,8 +419,13 @@ LRESULT CPlayBoardFrame::OnMessageWindowState(WPARAM wParam, LPARAM lParam) LRESULT CPlayBoardFrame::SendMessageToActiveBoardPane(UINT nMsg, WPARAM wParam, LPARAM lParam) { - CWnd& pWnd = GetActiveBoardView(); - return pWnd.SendMessage(nMsg, wParam, lParam); + CPlayBoardView& pWnd = GetActiveBoardView(); + wxASSERT(nMsg == WM_SELECT_BOARD_OBJLIST); + const CPlayBoard* board = reinterpret_cast(wParam); + const std::vector>* objList = reinterpret_cast>*>(lParam); + SelectBoardObjListEvent event(CheckedDeref(board), CheckedDeref(objList)); + pWnd.ProcessWindowEvent(event); + return 1; } ///////////////////////////////////////////////////////////////////////////// @@ -424,7 +435,10 @@ LRESULT CPlayBoardFrame::OnMessageCenterBoardOnPoint(WPARAM wParam, LPARAM lPara { // Route the message to the active board view. CPlayBoardView& pView = GetActiveBoardView(); - return pView.SendMessage(WM_CENTERBOARDONPOINT, wParam, lParam); + const POINT* point = reinterpret_cast(wParam); + CenterBoardOnPointEvent event(CB::Convert(CheckedDeref(point))); + pView.ProcessWindowEvent(event); + return 0; } // Send these on to the main view so they can be process no @@ -443,9 +457,20 @@ CCbSplitterWnd& CPlayBoardFrame::GetBoardSplitter() const CPlayBoardView& CPlayBoardFrame::GetActiveBoardView() const { CCbSplitterWnd& pSplitWnd = CheckedDeref((CCbSplitterWnd*)m_wndSplitter1.GetPane(0, 0)); - return CheckedDeref((CPlayBoardView*)pSplitWnd.GetActivePane()); + const CWnd* view = GetActiveView(); + if (view && + view->IsKindOf(RUNTIME_CLASS(CPlayBoardViewContainer)) && + view->GetParent() == &pSplitWnd) + { + return static_cast(*view); + } + wxASSERT(!"dead code?"); + const CWnd& wnd = CheckedDeref(pSplitWnd.GetActivePane()); + const CPlayBoardViewContainer& container = dynamic_cast(wnd); + return static_cast(container); } +#if 0 void CPlayBoardFrame::OnViewHalfScaleBrd() { GetActiveBoardView().OnViewHalfScaleBrd(); @@ -560,35 +585,45 @@ void CPlayBoardFrame::OnUpdateActTurnOver(CCmdUI* pCmdUI) { GetActiveBoardView().OnUpdateActTurnOver(pCmdUI); } +#endif void CPlayBoardFrame::OnActPlotMove() { - GetActiveBoardView().OnActPlotMove(); + wxASSERT(!"dead code?"); + wxCommandEvent dummy; + GetActiveBoardView().OnActPlotMove(dummy); } void CPlayBoardFrame::OnUpdateActPlotMove(CCmdUI* pCmdUI) { - GetActiveBoardView().OnUpdateActPlotMove(pCmdUI); + wxASSERT(!"dead code?"); + CB_VERIFY(CB::RelayOnCmdMsg(GetActiveBoardView(), ID_PTOOL_PLOTMOVE, CN_UPDATE_COMMAND_UI, pCmdUI, nullptr)); } void CPlayBoardFrame::OnActPlotDone() { - GetActiveBoardView().OnActPlotDone(); + wxASSERT(!"dead code?"); + wxCommandEvent dummy; + GetActiveBoardView().OnActPlotDone(dummy); } void CPlayBoardFrame::OnUpdateActPlotDone(CCmdUI* pCmdUI) { - GetActiveBoardView().OnUpdateActPlotDone(pCmdUI); + wxASSERT(!"dead code?"); + CB_VERIFY(CB::RelayOnCmdMsg(GetActiveBoardView(), ID_ACT_PLOTDONE, CN_UPDATE_COMMAND_UI, pCmdUI, nullptr)); } void CPlayBoardFrame::OnActPlotDiscard() { - GetActiveBoardView().OnActPlotDiscard(); + wxASSERT(!"dead code?"); + wxCommandEvent dummy; + GetActiveBoardView().OnActPlotDiscard(dummy); } void CPlayBoardFrame::OnUpdateActPlotDiscard(CCmdUI* pCmdUI) { - GetActiveBoardView().OnUpdateActPlotDiscard(pCmdUI); + wxASSERT(!"dead code?"); + CB_VERIFY(CB::RelayOnCmdMsg(GetActiveBoardView(), ID_ACT_PLOTDISCARD, CN_UPDATE_COMMAND_UI, pCmdUI, nullptr)); } void CPlayBoardFrame::OnViewSplitBoardRows() diff --git a/GP/GamDoc.cpp b/GP/GamDoc.cpp index 626b1874..c1a36264 100644 --- a/GP/GamDoc.cpp +++ b/GP/GamDoc.cpp @@ -1,6 +1,6 @@ // GamDoc.cpp // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -195,9 +195,7 @@ END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CGamDoc construction/destruction -CGamDoc::CGamDoc() : - m_palTrayA(*this), - m_palTrayB(*this) +CGamDoc::CGamDoc() { m_nSeedCarryOver = (UINT)GetTickCount(); @@ -228,9 +226,6 @@ CGamDoc::CGamDoc() : m_bKeepMoveHist = TRUE; m_bVrfyGameState = TRUE; m_bVrfySaveState = TRUE; - m_palTrayA.SetPaletteID(0); - m_palTrayB.SetPaletteID(1); - m_palMark.SetDocument(this); m_wDocRand = GetTimeBasedRandomNumber(FALSE); // Non zero random number m_nMoveInterlock = 0; m_bQuietPlayback = FALSE; @@ -355,6 +350,37 @@ BOOL CGamDoc::OnSaveDocument(LPCTSTR pszPathName) void CGamDoc::DeleteContents() { + /* close may trigger paint of other windows, + so close before delete */ + if (m_palTrayA) + { + CDockTrayPalette* pFrame = m_palTrayA->GetDockingFrame(); + if (pFrame) + { + pFrame->SetChild(NULL); // Need to remove pointer from Tray's UI Frame. + } + m_palTrayA = nullptr; + } + if (m_palTrayB) + { + CDockTrayPalette* pFrame = m_palTrayB->GetDockingFrame(); + if (pFrame) + { + pFrame->SetChild(NULL); // Need to remove pointer from Tray's UI Frame. + } + m_palTrayB = nullptr; + } + if (m_palMark) + { + CDockMarkPalette* pFrame = static_cast(m_palMark->GetDockingFrame()); + if (pFrame) + { + ASSERT_KINDOF(CDockMarkPalette, pFrame); + pFrame->SetChild(NULL); // Need to remove pointer from Marker's UI Frame. + } + m_palMark = nullptr; + } + // m_wReserved1 = 0; m_wReserved2 = 0; m_wReserved3 = 0; @@ -399,37 +425,6 @@ void CGamDoc::DeleteContents() m_nMoveInterlock = 0; m_bQuietPlayback = FALSE; - if (m_palTrayA.m_hWnd != NULL) - { - CDockTrayPalette* pFrame = (CDockTrayPalette*)m_palTrayA.GetDockingFrame(); - if (pFrame) - { - ASSERT_KINDOF(CDockTrayPalette, pFrame); - pFrame->SetChild(NULL); // Need to remove pointer from Tray's UI Frame. - } - m_palTrayA.DestroyWindow(); - } - if (m_palTrayB.m_hWnd != NULL) - { - CDockTrayPalette* pFrame = (CDockTrayPalette*)m_palTrayB.GetDockingFrame(); - if (pFrame) - { - ASSERT_KINDOF(CDockTrayPalette, pFrame); - pFrame->SetChild(NULL); // Need to remove pointer from Tray's UI Frame. - } - m_palTrayB.DestroyWindow(); - } - if (m_palMark.m_hWnd != NULL) - { - CDockMarkPalette* pFrame = (CDockMarkPalette*)m_palMark.GetDockingFrame(); - if (pFrame) - { - ASSERT_KINDOF(CDockMarkPalette, pFrame); - pFrame->SetChild(NULL); // Need to remove pointer from Marker's UI Frame. - } - m_palMark.DestroyWindow(); - } - DiscardWindowState(); if (m_pPlayerMgr != NULL) delete m_pPlayerMgr; @@ -449,21 +444,21 @@ void CGamDoc::OnIdle(BOOL bActive) { CMainFrame* pMFrame = GetMainFrame(); - CDockMarkPalette* pDockMark = pMFrame->GetDockingMarkerWindow(); - pDockMark->SetChild(&m_palMark); + CDockMarkPalette& pDockMark = pMFrame->GetDockingMarkerWindow(); + pDockMark.SetChild(&*m_palMark); pMFrame->UpdatePaletteWindow(pDockMark, m_bMarkPalVisible); - CDockTrayPalette* pDockTrayA = pMFrame->GetDockingTrayAWindow(); - pDockTrayA->SetChild(&m_palTrayA); + CDockTrayPalette& pDockTrayA = pMFrame->GetDockingTrayAWindow(); + pDockTrayA.SetChild(&*m_palTrayA); pMFrame->UpdatePaletteWindow(pDockTrayA, m_bTrayAVisible); - CDockTrayPalette* pDockTrayB = pMFrame->GetDockingTrayBWindow(); - pDockTrayB->SetChild(&m_palTrayB); + CDockTrayPalette& pDockTrayB = pMFrame->GetDockingTrayBWindow(); + pDockTrayB.SetChild(&*m_palTrayB); pMFrame->UpdatePaletteWindow(pDockTrayB, m_bTrayBVisible); - CReadMsgWnd* pDocMsg = pMFrame->GetMessageWindow(); + CReadMsgWnd& pDocMsg = pMFrame->GetMessageWindow(); pMFrame->UpdatePaletteWindow(pDocMsg, m_bMsgWinVisible && !IsScenario()); - pDocMsg->SetText(this); + pDocMsg.SetText(this); } } @@ -475,8 +470,8 @@ void CGamDoc::OnIdle(BOOL bActive) void CGamDoc::DoInitialUpdate() { - m_palTrayA.UpdatePaletteContents(NULL); - m_palTrayB.UpdatePaletteContents(NULL); + (*m_palTrayA)->UpdatePaletteContents(NULL); + (*m_palTrayB)->UpdatePaletteContents(NULL); } void CGamDoc::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint) @@ -484,13 +479,13 @@ void CGamDoc::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint) CGamDocHint* ph = static_cast(pHint); if (lHint == HINT_TRAYCHANGE) { - m_palTrayA.UpdatePaletteContents(ph->GetArgs().m_pTray); - m_palTrayB.UpdatePaletteContents(ph->GetArgs().m_pTray); + (*m_palTrayA)->UpdatePaletteContents(ph->GetArgs().m_pTray); + (*m_palTrayB)->UpdatePaletteContents(ph->GetArgs().m_pTray); } else if (lHint == HINT_GAMESTATEUSED) { - m_palTrayA.UpdatePaletteContents(); - m_palTrayB.UpdatePaletteContents(); + (*m_palTrayA)->UpdatePaletteContents(); + (*m_palTrayB)->UpdatePaletteContents(); } CDocument::UpdateAllViews(pSender, lHint, pHint); } @@ -533,7 +528,7 @@ CGamProjView& CGamDoc::FindProjectView() const AfxThrowNotSupportedException(); } -CView* CGamDoc::FindPBoardView(const CPlayBoard& pPBoard) const +CPlayBoardView* CGamDoc::FindPBoardView(const CPlayBoard& pPBoard) const { if (!IsScenario() && pPBoard.IsPrivate() && @@ -546,11 +541,12 @@ CView* CGamDoc::FindPBoardView(const CPlayBoard& pPBoard) const POSITION pos = GetFirstViewPosition(); while (pos != NULL) { - CPlayBoardView* pView = (CPlayBoardView*)GetNextView(pos); - if (pView->IsKindOf(RUNTIME_CLASS(CPlayBoardView))) + CPlayBoardViewContainer* pCont = static_cast(GetNextView(pos)); + if (pCont->IsKindOf(RUNTIME_CLASS(CPlayBoardViewContainer))) { - if (pView->GetPlayBoard() == &pPBoard) - return pView; + CPlayBoardView& pView = *pCont; + if (&pView.GetPlayBoard() == &pPBoard) + return &pView; } } return NULL; @@ -637,9 +633,15 @@ BOOL CGamDoc::OnNewScenario() m_pYMgr->SetTileManager(m_pGbx->GetTileManager()); // Finally set up the tray palettes - m_palTrayA.Create(GetMainFrame()->GetDockingTrayAWindow()); - m_palTrayB.Create(GetMainFrame()->GetDockingTrayBWindow()); - m_palMark.Create(GetMainFrame()->GetDockingMarkerWindow()); + wxASSERT(!m_palTrayA); + m_palTrayA = new CTrayPaletteContainer(*this, ID_VIEW_TRAYA); + m_palTrayA->Create(GetMainFrame()->GetDockingTrayAWindow()); + wxASSERT(!m_palTrayB); + m_palTrayB = new CTrayPaletteContainer(*this, ID_VIEW_TRAYB); + m_palTrayB->Create(GetMainFrame()->GetDockingTrayBWindow()); + wxASSERT(!m_palMark); + m_palMark = new CMarkerPaletteContainer(*this); + m_palMark->Create(GetMainFrame()->GetDockingMarkerWindow()); return TRUE; } @@ -963,7 +965,7 @@ const CTileManager& CGamDoc::GetTileManager() const return CheckedDeref(CheckedDeref(m_pGbx).GetTileManager()); } -CMarkManager& CGamDoc::GetMarkManager() +const CMarkManager& CGamDoc::GetMarkManager() const { return CheckedDeref(CheckedDeref(m_pGbx).GetMarkManager()); } @@ -1629,7 +1631,7 @@ void CGamDoc::OnEditSelectBoards() pPBMgr.FindPBoardsNotInList(dlg.m_tblBrds, tblNotInList); for (size_t i = size_t(0); i < tblNotInList.size(); i++) { - CView* pView = FindPBoardView(*tblNotInList.at(i)); + CPlayBoardView* pView = FindPBoardView(*tblNotInList.at(i)); if (pView != NULL) { CFrameWnd* pFrame = pView->GetParentFrame(); diff --git a/GP/GamDoc.h b/GP/GamDoc.h index e32537cf..908c0668 100644 --- a/GP/GamDoc.h +++ b/GP/GamDoc.h @@ -1,6 +1,6 @@ // GamDoc.h // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -127,6 +127,13 @@ class CGamDocHint : public CObject DECLARE_DYNCREATE(CGamDocHint); public: CGamDocHint() : hint(HINT_INVALID) {} + ~CGamDocHint() + { + if (hint == HINT_POINTINVIEW) + { + args.m_pointInView.~Args(); + } + } template struct Args @@ -143,14 +150,14 @@ class CGamDocHint : public CObject struct Args { const CPlayBoard* m_pPBoard; - CDrawObj* m_pDrawObj; + const CDrawObj* m_pDrawObj; }; template<> struct Args { CPlayBoard* m_pPBoard; - const std::vector>* m_pPtrList; + const std::vector>* m_pPtrList; }; template<> @@ -177,7 +184,7 @@ class CGamDocHint : public CObject struct Args { CPlayBoard* m_pPBoard; - POINT m_point; + wxPoint m_point; }; template<> @@ -200,6 +207,10 @@ class CGamDocHint : public CObject if (hint == HINT_INVALID) { hint = HINT; + if (hint == HINT_POINTINVIEW) + { + new (&args.m_pointInView) Args; + } } else if (HINT != hint) { @@ -210,7 +221,7 @@ class CGamDocHint : public CObject private: EGamDocHint hint; - union { + union U { Args m_trayChange; Args m_updateObject; Args m_updateObjList; @@ -220,6 +231,7 @@ class CGamDocHint : public CObject Args m_pointInView; Args m_selectObj; Args m_selectObjList; + U() {} } args; }; @@ -316,7 +328,11 @@ class CGamDoc : public CDocument // Major game related objects... const CTileManager& GetTileManager() const; CTileManager& GetTileManager() { return const_cast(std::as_const(*this).GetTileManager()); } - CMarkManager& GetMarkManager(); + const CMarkManager& GetMarkManager() const; + CMarkManager& GetMarkManager() + { + return const_cast(std::as_const(*this).GetMarkManager()); + } const CBoardManager& GetBoardManager() const; CBoardManager& GetBoardManager() { @@ -347,8 +363,8 @@ class CGamDoc : public CDocument BOOL CreateNewFrame(CDocTemplate* pTemplate, const CB::string& pszTitle, LPVOID lpvCreateParam); CGamProjView& FindProjectView() const; - CView* FindPBoardView(const CPlayBoard& pPBoard) const; - CView* MakeSurePBoardVisible(CPlayBoard& pPBoard); + CPlayBoardView* FindPBoardView(const CPlayBoard& pPBoard) const; + CPlayBoardView* MakeSurePBoardVisible(CPlayBoard& pPBoard); void GetDocumentFrameList(std::vector>& tblFrames) const; BOOL IsWindowStateAvailable() const { return m_pWinState != NULL; } @@ -374,7 +390,7 @@ class CGamDoc : public CDocument CB::string GetGameElementString(GameElement gelem) const; BOOL HasGameElementString(GameElement gelem) const; void SetGameElementString(GameElement gelem, const CB::string* pszString); - void GetTipTextForObject(const CDrawObj& pDObj, CB::string &strTip, CB::string* pStrTitle = NULL) const; + void GetTipTextForObject(const CDrawObj& pDObj, CB::string &strTip) const; // Invalid_v = top GameElement GetGameElementCodeForObject(const CDrawObj& pDObj, size_t nSide = Invalid_v) const; GameElement GetVerifiedGameElementCodeForObject(const CDrawObj& pDObj, size_t nSide = Invalid_v) const; @@ -428,7 +444,7 @@ class CGamDoc : public CDocument void PlacePieceListOnBoard(CPoint pnt, const std::vector& pTbl, int xStagger, int yStagger, CPlayBoard *pPBrd); size_t PlacePieceListInTray(const std::vector& pTbl, CTraySet& pYGrp, size_t nPos = Invalid_v); - size_t PlaceObjectTableInTray(const std::vector> & pTbl, CTraySet& pYGrp, size_t nPos = Invalid_v); + size_t PlaceObjectTableInTray(const std::vector>& pTbl, CTraySet& pYGrp, size_t nPos = Invalid_v); void PlaceObjectTableOnBoard(const std::vector>& pLst, CPoint pntUpLeft, CPlayBoard* pPBrd, PlacePos ePos = placeDefault); void PlaceObjectTableOnBoard(CPoint pnt, const std::vector>& pTbl, @@ -438,7 +454,7 @@ class CGamDoc : public CDocument CSize sizeDelta, PlacePos ePos = placeDefault); void InvertPlayingPieceInTray(PieceID pid, CPieceTable::Flip flip, size_t side, bool bOkToNotifyTray, bool forceHide); - void InvertPlayingPieceOnBoard(CPieceObj& pObj, const CPlayBoard& pPBrd, CPieceTable::Flip flip, size_t side = Invalid_v); + void InvertPlayingPieceOnBoard(const CPieceObj& pObj, const CPlayBoard& pPBrd, CPieceTable::Flip flip, size_t side = Invalid_v); void InvertPlayingPieceTableOnBoard(const std::vector>& pLst, const CPlayBoard& pPBrd, CPieceTable::Flip flip); void ChangePlayingPieceFacingOnBoard(CPieceObj& pObj, CPlayBoard* pPBrd, @@ -457,18 +473,18 @@ class CGamDoc : public CDocument CPoint ptEnd, UINT nLineWd, COLORREF crLine, ObjectID dwObjID = ObjectID()); void ModifyLineObject(CPlayBoard* pPBrd, CPoint ptBeg, CPoint ptEnd, UINT nLineWd, COLORREF crLine, CLine* pObj); - void ReorgObjsInDrawList(CPlayBoard *pPBrd, std::vector>& pList, BOOL bToFront); - void DeleteObjectsInTable(const std::vector>& pList); + void ReorgObjsInDrawList(CPlayBoard *pPBrd, std::vector>& pList, BOOL bToFront); + void DeleteObjectsInTable(const std::vector>& pList); void SetObjectText(GameElement elem, const CB::string* pszObjText); void SetObjectLockdownTable(const std::vector>& pLst, BOOL bLockState); void SetObjectLockdown(CDrawObj& pDObj, BOOL bLockState); BOOL RemovePieceFromCurrentLocation(PieceID pid, BOOL bDeleteIfBoard, BOOL bTrayHintAllowed = TRUE); - void RemoveObjectFromCurrentLocation(CDrawObj* pObj); + void RemoveObjectFromCurrentLocation(const CDrawObj& pObj); void ExpungeUnusedPiecesFromBoards(); - void FindObjectTableUnionRect(const std::vector>& pLst, CRect& rct) const; + void FindObjectTableUnionRect(const std::vector>& pLst, CRect& rct) const; // Object and piece locator methods... BOOL FindPieceCurrentLocation(PieceID pid, const CTraySet*& pTraySet, @@ -496,12 +512,12 @@ class CGamDoc : public CDocument { return const_cast(std::as_const(*this).FindObjectOnBoard(dwObjID, const_cast(ppObj))); } - CPlayBoard* FindObjectOnBoard(CDrawObj* pObj); + CPlayBoard* FindObjectOnBoard(const CDrawObj& pObj); // Support for playback... void EnsureBoardVisible(CPlayBoard& pPBoard); void EnsureBoardLocationVisible(CPlayBoard& pPBoard, CPoint point); - void EnsureTrayIndexVisible(const CTraySet& pYSet, int nPos); + void EnsureTrayIndexVisible(const CTraySet& pYSet, size_t nPos); void SelectObjectOnBoard(CPlayBoard& pPBoard, CDrawObj* pObj); void SelectObjectListOnBoard(CPlayBoard& pPBoard, const std::vector>& pList); void SelectTrayItem(const CTraySet& pYSet, PieceID pid, UINT nResourceID); @@ -678,13 +694,24 @@ class CGamDoc : public CDocument CTileFacingMap* m_pTileFacingMap; // Map of temp tile rotations (NOT SERIALIZED) +private: + class WindowDestroy + { + public: + void operator()(CWnd* p) const + { + p->DestroyWindow(); + delete p; + } + }; + // Some document related windows... public: // Tray Palettes... - CTrayPalette m_palTrayA; - CTrayPalette m_palTrayB; + CB::propagate_const> m_palTrayA; + CB::propagate_const> m_palTrayB; // Marker Palette... - CMarkerPalette m_palMark; + CB::propagate_const> m_palMark; // Implementation protected: diff --git a/GP/GamDoc1.cpp b/GP/GamDoc1.cpp index 19de48e8..e07af438 100644 --- a/GP/GamDoc1.cpp +++ b/GP/GamDoc1.cpp @@ -1,6 +1,6 @@ // GamDoc1.cpp - Command and Control for document wide operations // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -144,7 +144,7 @@ void CGamDoc::PlaceObjectOnBoard(CPlayBoard *pPBrd, CDrawObj::OwnerPtr opObj, } } else - RemoveObjectFromCurrentLocation(&pObj); + RemoveObjectFromCurrentLocation(pObj); pObj.MoveObject(pObj.GetRect().TopLeft() + sizeDelta); @@ -186,7 +186,7 @@ void CGamDoc::PlaceObjectTableOnBoard(const std::vector> CDrawList* pDwg = pPBrd->GetPieceList(); ASSERT(pDwg); CRect rct; - FindObjectTableUnionRect(pLst, rct); + FindObjectTableUnionRect(ToRefPtr(pLst), rct); CSize size(pntUpLeft.x - rct.left, pntUpLeft.y - rct.top); if (pPBrd->GetPlotMoveMode()) @@ -291,14 +291,14 @@ void CGamDoc::PlaceObjectTableOnBoard(const std::vector> // Record processing if (pObj.GetType() == CDrawObj::drawPieceObj) { - CPieceObj& pPObj = static_cast(pObj); + const CPieceObj& pPObj = static_cast(pObj); CRect rctPce = pPObj.GetRect(); RecordPieceMoveToBoard(pPBrd, pPObj.m_pid, GetMidRect(rctPce) + size, ePos); } else if (pObj.GetType() == CDrawObj::drawMarkObj) { - CMarkObj& pMObj = static_cast(pObj); + const CMarkObj& pMObj = static_cast(pObj); CRect rctMrk = pMObj.GetRect(); RecordMarkMoveToBoard(pPBrd, pMObj.GetObjectID(), pMObj.m_mid, GetMidRect(rctMrk) + size, ePos); @@ -317,7 +317,7 @@ void CGamDoc::PlaceObjectTableOnBoard(const std::vector> } } else - RemoveObjectFromCurrentLocation(&pObj); + RemoveObjectFromCurrentLocation(pObj); pObj.MoveObject(pObj.GetRect().TopLeft() + size); @@ -446,17 +446,17 @@ size_t CGamDoc::PlacePieceListInTray(const std::vector& pTbl, CTraySet& ////////////////////////////////////////////////////////////////////// // Returns index of last piece inserted. -size_t CGamDoc::PlaceObjectTableInTray(const std::vector>& pLst, CTraySet& pYGrp, size_t nPos) +size_t CGamDoc::PlaceObjectTableInTray(const std::vector>& pLst, CTraySet& pYGrp, size_t nPos) { // Scan this list in reverse order so they show up in the // same visual order. for (size_t i = pLst.size() ; i != size_t(0) ; --i) { - CDrawObj& pObj = *pLst[i - size_t(1)]; + const CDrawObj& pObj = *pLst[i - size_t(1)]; // Only pieces are placed. Other objects are left as they were. if (pObj.GetType() == CDrawObj::drawPieceObj) { - PlacePieceInTray(static_cast(pObj).m_pid, pYGrp, nPos); + PlacePieceInTray(static_cast(pObj).m_pid, pYGrp, nPos); if (nPos != Invalid_v) nPos++; } @@ -466,7 +466,7 @@ size_t CGamDoc::PlaceObjectTableInTray(const std::vector ////////////////////////////////////////////////////////////////////// // (RECORDS) -void CGamDoc::InvertPlayingPieceOnBoard(CPieceObj& pObj, const CPlayBoard& pPBrd, CPieceTable::Flip flip, size_t side /*= Invalid_v*/) +void CGamDoc::InvertPlayingPieceOnBoard(const CPieceObj& pObj, const CPlayBoard& pPBrd, CPieceTable::Flip flip, size_t side /*= Invalid_v*/) { if (m_pPTbl->GetSides(pObj.m_pid) <= size_t(1)) return; @@ -618,18 +618,18 @@ void CGamDoc::ChangeMarkerFacingOnBoard(CMarkObj& pObj, CPlayBoard* pPBrd, ////////////////////////////////////////////////////////////////////// // (RECORDS) -void CGamDoc::DeleteObjectsInTable(const std::vector>& pLst) +void CGamDoc::DeleteObjectsInTable(const std::vector>& pLst) { for (auto pos = pLst.begin() ; pos != pLst.end() ; ++pos) { - CDrawObj& pObj = **pos; + const CDrawObj& pObj = **pos; // Only nonpieces are deleted. Pieces are left as they were. if (pObj.GetType() != CDrawObj::drawPieceObj) { if (pObj.GetType() == CDrawObj::drawMarkObj) RecordObjectDelete(pObj.GetObjectID()); - CPlayBoard* pPBrd = FindObjectOnBoard(&pObj); + CPlayBoard* pPBrd = FindObjectOnBoard(pObj); ASSERT(pPBrd != NULL); pPBrd->RemoveObject(pObj); @@ -824,7 +824,7 @@ void CGamDoc::ModifyLineObject(CPlayBoard* pPBrd, CPoint ptBeg, ////////////////////////////////////////////////////////////////////// -void CGamDoc::ReorgObjsInDrawList(CPlayBoard *pPBrd, std::vector>& pList, +void CGamDoc::ReorgObjsInDrawList(CPlayBoard *pPBrd, std::vector>& pList, BOOL bToFront) { CDrawList* pDwg = pPBrd->GetPieceList(); @@ -866,10 +866,10 @@ const CPlayBoard* CGamDoc::FindObjectOnBoard(ObjectID dwObjID, const CDrawObj*& return m_pPBMgr->FindObjectOnBoard(dwObjID, ppObj); } -CPlayBoard* CGamDoc::FindObjectOnBoard(CDrawObj* pObj) +CPlayBoard* CGamDoc::FindObjectOnBoard(const CDrawObj& pObj) { ASSERT(m_pPBMgr != NULL); - return m_pPBMgr->FindObjectOnBoard(*pObj); + return m_pPBMgr->FindObjectOnBoard(pObj); } const CPlayBoard* CGamDoc::FindPieceOnBoard(PieceID pid, const CPieceObj*& ppObj) const @@ -944,18 +944,18 @@ BOOL CGamDoc::FindPieceCurrentLocation(PieceID pid, const CTraySet*& pTraySet, //////////////////////////////////////////////////////////////////// -void CGamDoc::RemoveObjectFromCurrentLocation(CDrawObj* pObj) +void CGamDoc::RemoveObjectFromCurrentLocation(const CDrawObj& pObj) { CPlayBoard* pPBoard = FindObjectOnBoard(pObj); if (pPBoard != NULL) { - pPBoard->RemoveObject(*pObj); + pPBoard->RemoveObject(pObj); if (!IsQuietPlayback()) { // Cause it's former location to be invalidated... CGamDocHint hint; hint.GetArgs().m_pPBoard = pPBoard; - hint.GetArgs().m_pDrawObj = pObj; + hint.GetArgs().m_pDrawObj = &pObj; UpdateAllViews(NULL, HINT_UPDATEOBJECT, &hint); } } @@ -963,13 +963,13 @@ void CGamDoc::RemoveObjectFromCurrentLocation(CDrawObj* pObj) //////////////////////////////////////////////////////////////////// -void CGamDoc::FindObjectTableUnionRect(const std::vector>& pLst, CRect& rct) const +void CGamDoc::FindObjectTableUnionRect(const std::vector>& pLst, CRect& rct) const { rct.SetRectEmpty(); for (auto pos = pLst.begin() ; pos != pLst.end() ; ++pos) { - CDrawObj& pObj = **pos; + const CDrawObj& pObj = **pos; if (rct.IsRectEmpty()) rct = pObj.GetRect(); else diff --git a/GP/GamDoc2.cpp b/GP/GamDoc2.cpp index 20d93cad..1944f792 100644 --- a/GP/GamDoc2.cpp +++ b/GP/GamDoc2.cpp @@ -184,7 +184,7 @@ void CGamDoc::SaveRecordedMoves() m_strCurMsg.clear(); m_astrMsgHist.clear(); - GetMainFrame()->GetMessageWindow()->SetText(NULL); + GetMainFrame()->GetMessageWindow().SetText(NULL); // Save was ok..add to game history AddMovesToGameHistoryTable(pHist); diff --git a/GP/GamDoc3.cpp b/GP/GamDoc3.cpp index 10194e4d..9c51dba9 100644 --- a/GP/GamDoc3.cpp +++ b/GP/GamDoc3.cpp @@ -1,6 +1,6 @@ // GamDoc3.cpp -- serialization support for the document. // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -526,7 +526,7 @@ void CGamDoc::SerializeGame(CArchive& ar) } GetTrayManager().PropagateOwnerMaskToAllPieces(this); GetPBoardManager().PropagateOwnerMaskToAllPieces(); - GetMainFrame()->GetMessageWindow()->SetText(this); + GetMainFrame()->GetMessageWindow().SetText(this); } } @@ -688,11 +688,11 @@ void CGamDoc::SerializeScenarioOrGame(CArchive& ar, uint64_t& offsetOffsetFeatur ar << (BYTE)0; // 0 -> no win state serialize // V2.0 ar << (WORD)m_bTrayAVisible; - m_palTrayA.Serialize(ar); // Save tray position on screen + (*m_palTrayA)->Serialize(ar); // Save tray position on screen ar << (WORD)m_bTrayBVisible; - m_palTrayB.Serialize(ar); // Save tray position on screen + (*m_palTrayB)->Serialize(ar); // Save tray position on screen ar << (WORD)m_bMarkPalVisible; - m_palMark.Serialize(ar); // Save tray position on screen + (*m_palMark)->Serialize(ar); // Save tray position on screen // Main content serialization.... @@ -848,11 +848,17 @@ void CGamDoc::SerializeScenarioOrGame(CArchive& ar, uint64_t& offsetOffsetFeatur } ar >> wTmp; m_bTrayAVisible = (BOOL)wTmp; - m_palTrayA.Serialize(ar); // Restore tray position on screen + wxASSERT(!m_palTrayA); + m_palTrayA = new CTrayPaletteContainer(*this, ID_VIEW_TRAYA); + (*m_palTrayA)->Serialize(ar); // Restore tray position on screen ar >> wTmp; m_bTrayBVisible = (BOOL)wTmp; - m_palTrayB.Serialize(ar); // Restore tray position on screen + wxASSERT(!m_palTrayB); + m_palTrayB = new CTrayPaletteContainer(*this, ID_VIEW_TRAYB); + (*m_palTrayB)->Serialize(ar); // Restore tray position on screen ar >> wTmp; m_bMarkPalVisible = (BOOL)wTmp; - m_palMark.Serialize(ar); // Restore tray position on screen + wxASSERT(!m_palMark); + m_palMark = new CMarkerPaletteContainer(*this); + (*m_palMark)->Serialize(ar); // Restore tray position on screen // OK....retrieve the file offset of the game data... if (NumVersion(verMajor, verMinor) < NumVersion(2, 90)) @@ -877,9 +883,9 @@ void CGamDoc::SerializeScenarioOrGame(CArchive& ar, uint64_t& offsetOffsetFeatur m_pYMgr->SetTileManager(m_pGbx->GetTileManager()); // Finally set up the tray palettes - m_palTrayA.Create(GetMainFrame()->GetDockingTrayAWindow()); - m_palTrayB.Create(GetMainFrame()->GetDockingTrayBWindow()); - m_palMark.Create(GetMainFrame()->GetDockingMarkerWindow()); + m_palTrayA->Create(GetMainFrame()->GetDockingTrayAWindow()); + m_palTrayB->Create(GetMainFrame()->GetDockingTrayBWindow()); + m_palMark->Create(GetMainFrame()->GetDockingMarkerWindow()); // Main content serialization.... m_pPBMgr->Serialize(ar); // Board contents diff --git a/GP/GamDoc4.cpp b/GP/GamDoc4.cpp index cb8a0a1c..f8a03190 100644 --- a/GP/GamDoc4.cpp +++ b/GP/GamDoc4.cpp @@ -1,6 +1,6 @@ // GamDoc4.cpp - various game playback support routines // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -468,7 +468,7 @@ void CGamDoc::EnsureBoardLocationVisible(CPlayBoard& pPBoard, CPoint point) // near the center of the view. CGamDocHint hint; hint.GetArgs().m_pPBoard = &pPBoard; - hint.GetArgs().m_point = point; + hint.GetArgs().m_point = CB::Convert(point); UpdateAllViews(NULL, HINT_POINTINVIEW, &hint); } @@ -484,7 +484,7 @@ void CGamDoc::EnsureBoardVisible(CPlayBoard& pPBoard) ///////////////////////////////////////////////////////////////////////////// -void CGamDoc::EnsureTrayIndexVisible(const CTraySet& pYSet, int nPos) +void CGamDoc::EnsureTrayIndexVisible(const CTraySet& pYSet, size_t nPos) { if (IsQuietPlayback()) return; if (!m_bTrayAVisible) @@ -492,8 +492,8 @@ void CGamDoc::EnsureTrayIndexVisible(const CTraySet& pYSet, int nPos) // Make sure item nPos is visible. size_t nGroup = GetTrayManager().FindTrayByRef(pYSet); - ASSERT(nGroup != Invalid_v); - m_palTrayA.ShowTrayIndex(nGroup, nPos); + wxASSERT(nGroup != Invalid_v); + (*m_palTrayA)->ShowTrayIndex(nGroup, nPos); } ///////////////////////////////////////////////////////////////////////////// @@ -546,7 +546,7 @@ void CGamDoc::SelectTrayItem(const CTraySet& pYSet, PieceID pid, // Select the piece in the appropriate trayset. size_t nGroup = GetTrayManager().FindTrayByRef(pYSet); ASSERT(nGroup != Invalid_v); - m_palTrayA.SelectTrayPiece(nGroup, pid, pszNotificationTip ? pszNotificationTip : nullptr); + (*m_palTrayA)->SelectTrayPiece(nGroup, pid, pszNotificationTip ? pszNotificationTip : nullptr); } void CGamDoc::SelectMarkerPaletteItem(MarkID mid) @@ -556,12 +556,12 @@ void CGamDoc::SelectMarkerPaletteItem(MarkID mid) if (!m_bMarkPalVisible) OnViewMarkPalette(); // Select the marker in the appropriate group. - m_palMark.SelectMarker(mid); + (*m_palMark)->SelectMarker(mid); } ///////////////////////////////////////////////////////////////////////////// -CView* CGamDoc::MakeSurePBoardVisible(CPlayBoard& pPBoard) +CPlayBoardView* CGamDoc::MakeSurePBoardVisible(CPlayBoard& pPBoard) { if (IsQuietPlayback()) return NULL; if (pPBoard.IsPrivate() && @@ -577,7 +577,7 @@ CView* CGamDoc::MakeSurePBoardVisible(CPlayBoard& pPBoard) return nullptr; } - CView* pView = FindPBoardView(pPBoard); + CPlayBoardView* pView = FindPBoardView(pPBoard); if (pView != NULL) { // This board already has a view. Activate that view. @@ -664,19 +664,20 @@ void CGamDoc::IndicateTextTipOnBoard(const CPlayBoard& pPBoard, // Shows a balloon tip so person knows what happened. void CGamDoc::IndicateTextTipOnBoard(const CPlayBoard& pPBoard, - CPoint pointWorkspace, const CB::string& pszStr) + CPoint pointWorkspaceMfc, const CB::string& pszStr) { + wxPoint pointWorkspace = CB::Convert(pointWorkspaceMfc); if (IsQuietPlayback()) return; - CPlayBoardView* pView = (CPlayBoardView*)FindPBoardView(pPBoard); + CPlayBoardView* pView = FindPBoardView(pPBoard); ASSERT(pView != NULL); - pView->WorkspaceToClient(pointWorkspace); - pView->SetNotificationTip(pointWorkspace, &pszStr); + pointWorkspace = pView->WorkspaceToClient(pointWorkspace); + pView->SetNotificationTip(pointWorkspace, pszStr); } void CGamDoc::FlushAllSelections() { - m_palTrayA.DeselectAll(); - m_palTrayB.DeselectAll(); + (*m_palTrayA)->DeselectAll(); + (*m_palTrayB)->DeselectAll(); // Use hint to flush select lists. CGamDocHint hint; @@ -687,8 +688,8 @@ void CGamDoc::FlushAllSelections() void CGamDoc::FlushAllIndicators() { - m_palTrayA.DeselectAll(); - m_palTrayB.DeselectAll(); + (*m_palTrayA)->DeselectAll(); + (*m_palTrayB)->DeselectAll(); for (size_t i = 0; i < m_pPBMgr->GetNumPBoards(); i++) { diff --git a/GP/GamDoc5.cpp b/GP/GamDoc5.cpp index a18bd17d..c7bb8a97 100644 --- a/GP/GamDoc5.cpp +++ b/GP/GamDoc5.cpp @@ -1,6 +1,6 @@ // GamDoc5.cpp : just plain miscellaneous stuff // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -198,8 +198,7 @@ GameElement CGamDoc::GetVerifiedGameElementCodeForObject(const CDrawObj& pDObj, return elem; } -void CGamDoc::GetTipTextForObject(const CDrawObj& pDObj, CB::string &strTip, - CB::string* pStrTitle /* = NULL */) const +void CGamDoc::GetTipTextForObject(const CDrawObj& pDObj, CB::string &strTip) const { if (pDObj.GetType() == CDrawObj::drawPieceObj) { @@ -235,7 +234,7 @@ void CGamDoc::DoEditPieceText(PieceID pid) { GameElement elemDown = MakePieceElement(pid, value_preserving_cast(i)); CB::string strDown = GetGameElementString(elemDown); - if (strDown != dlg.m_strText) + if (strDown.empty() || strDown != dlg.m_strText) { dlg.m_bSetAllSides = FALSE; break; @@ -273,7 +272,7 @@ void CGamDoc::DoEditObjectText(const CDrawObj& pDObj) CEditElementTextDialog dlg; CB::string strTip; - GetTipTextForObject(pDObj, strTip, NULL); + GetTipTextForObject(pDObj, strTip); dlg.m_strText = strTip; @@ -322,18 +321,17 @@ void CGamDoc::EventShowBoardNotification(BoardID nBrdSerNum, CPoint pntTipLoc, c if (pntTipLoc.x == -1 || pntTipLoc.y == -1) { EnsureBoardVisible(*pPBoard); - pView = (CPlayBoardView*)FindPBoardView(*pPBoard); - CRect rct; - pView->GetClientRect(rct); + pView = FindPBoardView(*pPBoard); + CRect rct = CB::Convert(pView->GetClientRect()); pntTipLoc = rct.CenterPoint(); } else { EnsureBoardLocationVisible(*pPBoard, pntTipLoc); - pView = (CPlayBoardView*)FindPBoardView(*pPBoard); - pView->WorkspaceToClient(pntTipLoc); + pView = FindPBoardView(*pPBoard); + pntTipLoc = CB::Convert(pView->WorkspaceToClient(CB::Convert(pntTipLoc))); } - pView->SetNotificationTip(pntTipLoc, &strMsg); + pView->SetNotificationTip(CB::Convert(pntTipLoc), strMsg); } //////////////////////////////////////////////////////////////////////////// @@ -366,7 +364,7 @@ void CGamDoc::MsgSetMessageText(const CB::string& str) else m_strCurMsg = str; - GetMainFrame()->GetMessageWindow()->SetText(this); + GetMainFrame()->GetMessageWindow().SetText(this); if (!IsQuietPlayback() && !m_bMsgWinVisible) m_bMsgWinVisible = TRUE; } diff --git a/GP/Gp.cpp b/GP/Gp.cpp index eab940e2..11a1c469 100644 --- a/GP/Gp.cpp +++ b/GP/Gp.cpp @@ -1,6 +1,6 @@ // Gp.cpp : Defines the class behaviors for the application. // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -48,8 +48,12 @@ static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif +wxDEFINE_EVENT(WM_ROTATEPIECE_DELTA_WX, RotatePieceDeltaEvent); +wxDEFINE_EVENT(WM_CENTERBOARDONPOINT_WX, CenterBoardOnPointEvent); wxDEFINE_EVENT(WM_SHOWPLAYINGBOARD_WX, ShowPlayingBoardEvent); wxDEFINE_EVENT(WM_WINSTATE_RESTORE_WX, WinStateRestoreEvent); +wxDEFINE_EVENT(WM_SELECT_BOARD_OBJLIST_WX, SelectBoardObjListEvent); +wxDEFINE_EVENT(WM_PALETTE_HIDE_WX, wxCommandEvent); ///////////////////////////////////////////////////////////////////////////// // Registry keys... @@ -177,6 +181,42 @@ namespace { return true; } + + protected: + /* for safety, and to approximate MFC, + disable MFC toolbar/menu commands that aren't + explicitly enabled */ + bool TryAfter(wxEvent& event) override + { + if (wxAppWithMFC::TryAfter(event)) + { + return true; + } + + /* for safety, and to approximate MFC, + disable toolbar/menu commands that aren't + explicitly enabled */ + if (event.GetEventType() == wxEVT_UPDATE_UI) + { + wxUpdateUIEvent& pCmdUI = static_cast(event); + wxString xrcid = wxXmlResource::FindXRCIDById(pCmdUI.GetId()); + // !event.obj suggests MFC + /* if xrcid is empty, then id is something + wx-internal (e.g., wxAUI_BUTTON_WINDOWLIST), + so don't interfere with it */ + if (!event.GetEventObject() && !xrcid.empty()) + { + if (pCmdUI.IsCheckable()) + { + pCmdUI.Check(false); + } + pCmdUI.Enable(false); + return true; + } + } + + return false; + } }; } wxDECLARE_APP(wxCGpApp); @@ -265,7 +305,7 @@ BOOL CGpApp::InitInstance() IDR_GP_BOARDVIEW, RUNTIME_CLASS(CGamDoc), RUNTIME_CLASS(CPlayBoardFrame), - RUNTIME_CLASS(CPlayBoardView)); + RUNTIME_CLASS(CPlayBoardViewContainer)); EnableLoadWindowPlacement(FALSE); diff --git a/GP/Gp.h b/GP/Gp.h index 7f07452e..f9d01ec0 100644 --- a/GP/Gp.h +++ b/GP/Gp.h @@ -1,6 +1,6 @@ // Gp.h : main header file for the GP application // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -22,6 +22,9 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +#if !defined(GP_H_) +#define GP_H_ + #ifndef __AFXWIN_H__ #error include 'stdafx.h' before including this file for PCH #endif @@ -33,6 +36,9 @@ #include "versions.h" #include "FrmMain.h" +class CPlayBoard; +class CDrawObj; + ///////////////////////////////////////////////////////////////////////////// #define IDW_TOOLBAR_MAIN AFX_IDW_TOOLBAR @@ -47,7 +53,52 @@ ///////////////////////////////////////////////////////////////////////////// #define WM_ROTATEPIECE_DELTA (WM_USER + 210) // WPARAM = (int)relative rotation delta +class RotatePieceDeltaEvent : public wxEvent +{ +public: + RotatePieceDeltaEvent(int delta); + + int GetDelta() const { return delta; } + + wxEvent* Clone() const override { return new RotatePieceDeltaEvent(*this); } + +private: + const int delta; +}; +wxDECLARE_EVENT(WM_ROTATEPIECE_DELTA_WX, RotatePieceDeltaEvent); +inline RotatePieceDeltaEvent::RotatePieceDeltaEvent(int d) : + wxEvent(wxID_ANY, WM_ROTATEPIECE_DELTA_WX), + delta(d) +{ +} +typedef void (wxEvtHandler::* RotatePieceDeltaEventFunction)(RotatePieceDeltaEvent&); +#define RotatePieceDeltaEventHandler(func) wxEVENT_HANDLER_CAST(RotatePieceDeltaEventFunction, func) +#define EVT_ROTATEPIECE_DELTA(func) \ + wx__DECLARE_EVT0(WM_ROTATEPIECE_DELTA_WX, RotatePieceDeltaEventHandler(func)) + #define WM_CENTERBOARDONPOINT (WM_USER + 211) // WPARAM = POINT* in board coords +class CenterBoardOnPointEvent : public wxEvent +{ +public: + CenterBoardOnPointEvent(const wxPoint& point); + + const wxPoint& GetPoint() const { return point; } + + wxEvent* Clone() const override { return new CenterBoardOnPointEvent(*this); } + +private: + const wxPoint point; +}; +wxDECLARE_EVENT(WM_CENTERBOARDONPOINT_WX, CenterBoardOnPointEvent); +inline CenterBoardOnPointEvent::CenterBoardOnPointEvent(const wxPoint& p) : + wxEvent(wxID_ANY, WM_CENTERBOARDONPOINT_WX), + point(p) +{ +} +typedef void (wxEvtHandler::* CenterBoardOnPointEventFunction)(CenterBoardOnPointEvent&); +#define CenterBoardOnPointEventHandler(func) wxEVENT_HANDLER_CAST(CenterBoardOnPointEventFunction, func) +#define EVT_CENTERBOARDONPOINT(func) \ + wx__DECLARE_EVT0(WM_CENTERBOARDONPOINT_WX, CenterBoardOnPointEventHandler(func)) #define WM_SHOWPLAYINGBOARD (WM_USER + 212) // WPARAM = size_t Playing Board Index class ShowPlayingBoardEvent : public wxEvent @@ -92,6 +143,36 @@ typedef void (wxEvtHandler::* WinStateRestoreEventFunction)(WinStateRestoreEvent wx__DECLARE_EVT0(WM_WINSTATE_RESTORE_WX, WinStateRestoreEventHandler(func)) #define WM_SELECT_BOARD_OBJLIST (WM_USER + 214) // WPARAM = CPlayBoard*, LPARAM = const std::vector>* +class SelectBoardObjListEvent : public wxEvent +{ +public: + SelectBoardObjListEvent(const CPlayBoard& b, + const std::vector>& l); + + const CPlayBoard& GetBoard() const { return board; } + const std::vector>& GetObjList() const + { + return objList; + } + + wxEvent* Clone() const override { return new SelectBoardObjListEvent(*this); } + +private: + const CPlayBoard& board; + const std::vector>& objList; +}; +wxDECLARE_EVENT(WM_SELECT_BOARD_OBJLIST_WX, SelectBoardObjListEvent); +inline SelectBoardObjListEvent::SelectBoardObjListEvent(const CPlayBoard& b, + const std::vector>& l) : + wxEvent(wxID_ANY, WM_SELECT_BOARD_OBJLIST_WX), + board(b), + objList(l) +{ +} +typedef void (wxEvtHandler::* SelectBoardObjListEventFunction)(SelectBoardObjListEvent&); +#define SelectBoardObjListEventHandler(func) wxEVENT_HANDLER_CAST(SelectBoardObjListEventFunction, func) +#define EVT_SELECT_BOARD_OBJLIST(func) \ + wx__DECLARE_EVT0(WM_SELECT_BOARD_OBJLIST_WX, SelectBoardObjListEventHandler(func)) #define WM_MESSAGEBOX (WM_USER + 215) // WPARAM = Opts. LPARAM = Msg ID or Ptr enum @@ -103,6 +184,7 @@ enum }; #define WM_PALETTE_HIDE (WM_USER + 216) +wxDECLARE_EVENT(WM_PALETTE_HIDE_WX, wxCommandEvent); ///////////////////////////////////////////////////////////////////////////// // Context menu offset definitions. @@ -180,3 +262,4 @@ inline CMainFrame* GetMainFrame() { return (CMainFrame*)(GetApp()->m_pMainWnd); ///////////////////////////////////////////////////////////////////////////// +#endif diff --git a/GP/LBoxSlct.cpp b/GP/LBoxSlct.cpp index d03e283d..60e145cd 100644 --- a/GP/LBoxSlct.cpp +++ b/GP/LBoxSlct.cpp @@ -1,6 +1,6 @@ // LBoxSlct.cpp // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -44,35 +44,36 @@ const int tileGap = 6; ///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CSelectListBox, CTileBaseListBox2) - //{{AFX_MSG_MAP(CSelectListBox) - ON_REGISTERED_MESSAGE(WM_DRAGDROP, OnDragItem) - ON_WM_CONTEXTMENU() - ON_WM_INITMENUPOPUP() - ON_COMMAND_EX(ID_ACT_TURNOVER, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_PREV, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_RANDOM, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_SELECT, OnActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_PREV, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_RANDOM, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_SELECT, OnUpdateActTurnOver) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() +wxIMPLEMENT_DYNAMIC_CLASS(CSelectListBox, CTileBaseListBox2); + +wxBEGIN_EVENT_TABLE(CSelectListBox, CTileBaseListBox2) + EVT_DRAGDROP(OnDragItem) + EVT_CONTEXT_MENU(OnContextMenu) + EVT_MENU_OPEN(OnInitMenuPopup) + EVT_MENU(XRCID("ID_ACT_TURNOVER"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_PREV"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_RANDOM"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_SELECT"), OnActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_PREV"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_RANDOM"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_SELECT"), OnUpdateActTurnOver) +wxEND_EVENT_TABLE() ///////////////////////////////////////////////////////////////////////////// const CTileManager& CSelectListBox::GetTileManager() const { - ASSERT(m_pDoc != NULL); + wxASSERT(m_pDoc != NULL); return m_pDoc->GetTileManager(); } ///////////////////////////////////////////////////////////////////////////// -BOOL CSelectListBox::OnDragSetup(DragInfo& pDI) const +BOOL CSelectListBox::OnDragSetup(DragInfoWx& pDI) const { - ASSERT(!"untested code"); + wxASSERT(!"untested code"); +#if 0 if (GetCount() <= 1) { pDI.SetDragType(DRAG_INVALID); @@ -81,7 +82,7 @@ BOOL CSelectListBox::OnDragSetup(DragInfo& pDI) const if (!IsMultiSelect()) { - ASSERT(!"unreachable code"); + wxASSERT(!"unreachable code"); /* if this ever happens, rewrite like LBoxGrfx w/ list/single distinction m_multiSelList.clear(); @@ -91,24 +92,27 @@ BOOL CSelectListBox::OnDragSetup(DragInfo& pDI) const pDI.SetDragType(DRAG_SELECTVIEW); pDI.GetSubInfo().m_ptrArray = &GetMappedMultiSelectList(); pDI.m_hcsrSuggest = g_res.hcrDragTile; - pDI.GetSubInfo().m_gamDoc = m_pDoc; + pDI.GetSubInfo().m_gamDoc = &*m_pDoc; +#endif return TRUE; } -LRESULT CSelectListBox::OnDragItem(WPARAM wParam, LPARAM lParam) +void CSelectListBox::OnDragItem(DragDropEvent& event) { - if (wParam != GetProcessId(GetCurrentProcess())) + if (event.GetProcessId() != wxGetProcessId()) { - return -1; + wxASSERT(!"bad event process"); + return; } - const DragInfo& pdi = CheckedDeref(reinterpret_cast(lParam)); + const DragInfoWx& pdi = event.GetDragInfo(); DoInsertLineProcessing(pdi); if (pdi.GetDragType() != DRAG_SELECTVIEW) - return -1; // Only our drops allowed + return; // Only our drops allowed ASSERT(!"untested code"); +#if 0 if (pdi.GetSubInfo().m_gamDoc != m_pDoc) return -1; // Only pieces from our document. @@ -129,40 +133,44 @@ LRESULT CSelectListBox::OnDragItem(WPARAM wParam, LPARAM lParam) } } return 1; +#endif } -void CSelectListBox::OnContextMenu(CWnd* /*pWnd*/, CPoint point) +void CSelectListBox::OnContextMenu(wxContextMenuEvent& event) { + const wxPoint& point = event.GetPosition(); // remember clicked side in case of ID_ACT_TURNOVER_SELECT - CPoint clientPoint(point); - ScreenToClient(&clientPoint); - CRect rect; + wxPoint clientPoint(point); + clientPoint = ScreenToClient(clientPoint); + wxRect rect; menuGameElement = OnGetHitItemCodeAtPoint(&CGamDoc::GetGameElementCodeForObject, clientPoint, rect); - CMenu bar; - if (bar.LoadMenuW(IDR_MENU_PLAYER_POPUPS)) + std::unique_ptr bar(wxXmlResource::Get()->LoadMenuBar("IDR_MENU_PLAYER_POPUPS")); + if (bar) { - CMenu& popup = *bar.GetSubMenu(MENU_PV_SELCT_BOX); - ASSERT(popup.m_hMenu != NULL); + int index = bar->FindMenu("8=PV_SELCT_BOX"); + wxASSERT(index != wxNOT_FOUND); + std::unique_ptr popup(bar->Remove(value_preserving_cast(index))); // Make sure we clean up even if exception is tossed. - TRY + try { - popup.TrackPopupMenu(TPM_LEFTBUTTON | - TPM_LEFTALIGN | - TPM_RIGHTBUTTON, - point.x, point.y, this); // Route commands through tray window + PopupMenu(&*popup, clientPoint); + } + catch (...) + { + wxASSERT(!"exception"); } - END_TRY } else { - ASSERT(!"LoadMenu error"); + wxASSERT(!"LoadMenuBar error"); } } -void CSelectListBox::OnInitMenuPopup(CMenu* pMenu, UINT /*nIndex*/, BOOL bSysMenu) +void CSelectListBox::OnInitMenuPopup(wxMenuEvent& event) { +#if 0 // based on CFrameWnd::OnInitMenuPopup() ASSERT(!bSysMenu); @@ -215,77 +223,82 @@ void CSelectListBox::OnInitMenuPopup(CMenu* pMenu, UINT /*nIndex*/, BOOL bSysMen } state.m_nIndexMax = nCount; } +#else + event.Skip(); +#endif } -BOOL CSelectListBox::OnActTurnOver(UINT id) +void CSelectListBox::OnActTurnOver(wxCommandEvent& event) { + int id = event.GetId(); CPlayBoardView& view = GetBoardView(); - switch (id) + if (id == XRCID("ID_ACT_TURNOVER") || + id == XRCID("ID_ACT_TURNOVER_PREV") || + id == XRCID("ID_ACT_TURNOVER_RANDOM")) { - case ID_ACT_TURNOVER: - case ID_ACT_TURNOVER_PREV: - case ID_ACT_TURNOVER_RANDOM: - { - bool b = view.OnCmdMsg(id, CN_COMMAND, nullptr, nullptr); - ASSERT(b); - return b; - } - case ID_ACT_TURNOVER_SELECT: - { - const CPlayBoard& playBoard = CheckedDeref(view.GetPlayBoard()); + CB_VERIFY(CB::RelayProcessEvent(view, event)); + return; + } + else if (id == XRCID("ID_ACT_TURNOVER_SELECT")) + { + const CPlayBoard& playBoard = view.GetPlayBoard(); - m_pDoc->AssignNewMoveGroup(); + m_pDoc->AssignNewMoveGroup(); - PieceID pid = static_cast(menuGameElement); - auto it = std::find_if(GetItemMap()->begin(), - GetItemMap()->end(), - [pid](CB::not_null drawObj) + PieceID pid = static_cast(menuGameElement); + auto it = std::find_if(GetItemMap()->begin(), + GetItemMap()->end(), + [pid](const RefPtr& drawObj) + { + if (drawObj->GetType() != CDrawObj::drawPieceObj) { - if (drawObj->GetType() != CDrawObj::drawPieceObj) - { - return false; - } - CPieceObj& pieceObj = static_cast(*drawObj); - return pieceObj.m_pid == pid; - }); - ASSERT(it != GetItemMap()->end()); - CDrawObj& drawObj = **it; - ASSERT(drawObj.GetType() == CDrawObj::drawPieceObj); - CPieceObj& pieceObj = static_cast(drawObj); - size_t side = menuGameElement.GetSide(); - m_pDoc->InvertPlayingPieceOnBoard(pieceObj, playBoard, CPieceTable::fSelect, side); - - return true; - } - default: - AfxThrowInvalidArgException(); + return false; + } + const CPieceObj& pieceObj = static_cast(*drawObj); + return pieceObj.m_pid == pid; + }); + wxASSERT(it != GetItemMap()->end()); + const CDrawObj& drawObj = **it; + wxASSERT(drawObj.GetType() == CDrawObj::drawPieceObj); + const CPieceObj& pieceObj = static_cast(drawObj); + size_t side = menuGameElement.GetSide(); + m_pDoc->InvertPlayingPieceOnBoard(pieceObj, playBoard, CPieceTable::fSelect, side); + + return; + } + else + { + AfxThrowInvalidArgException(); } } -void CSelectListBox::OnUpdateActTurnOver(CCmdUI* pCmdUI) +void CSelectListBox::OnUpdateActTurnOver(wxUpdateUIEvent& pCmdUI) { - switch (pCmdUI->m_nID) + int id = pCmdUI.GetId(); + if (id == XRCID("ID_ACT_TURNOVER") || + id == XRCID("ID_ACT_TURNOVER_PREV") || + id == XRCID("ID_ACT_TURNOVER_RANDOM")) { - case ID_ACT_TURNOVER: - case ID_ACT_TURNOVER_PREV: - case ID_ACT_TURNOVER_RANDOM: - pCmdUI->DoUpdate(&GetBoardView(), TRUE); - break; - case ID_ACT_TURNOVER_SELECT: + CB_VERIFY(CB::RelayProcessEvent(GetBoardView(), pCmdUI)); + return; + } + else if (id == XRCID("ID_ACT_TURNOVER_SELECT")) + { + bool enable = menuGameElement != Invalid_v && + menuGameElement.IsAPiece(); + pCmdUI.Enable(enable); +#if 0 + if (pCmdUI->m_pSubMenu != NULL) { - bool enable = menuGameElement != Invalid_v && - menuGameElement.IsAPiece(); - pCmdUI->Enable(enable); - if (pCmdUI->m_pSubMenu != NULL) - { - // Need to handle menu that the submenu is connected to. - pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex, - MF_BYPOSITION | (enable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED))); - } - break; + // Need to handle menu that the submenu is connected to. + pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex, + MF_BYPOSITION | (enable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED))); } - default: - AfxThrowInvalidArgException(); +#endif + } + else + { + AfxThrowInvalidArgException(); } } @@ -297,42 +310,43 @@ BOOL CSelectListBox::OnIsToolTipsEnabled() const return m_pDoc->IsShowingObjectTips(); } -GameElement CSelectListBox::OnGetHitItemCodeAtPoint(CPoint point, CRect& rct) const +GameElement CSelectListBox::OnGetHitItemCodeAtPoint(wxPoint point, wxRect& rct) const { return OnGetHitItemCodeAtPoint(&CGamDoc::GetVerifiedGameElementCodeForObject, point, rct); } -GameElement CSelectListBox::OnGetHitItemCodeAtPoint(GetGameElementCodeForObject_t func, CPoint point, CRect& rct) const +GameElement CSelectListBox::OnGetHitItemCodeAtPoint(GetGameElementCodeForObject_t func, wxPoint point, wxRect& rct) const { point = ClientToItem(point); - BOOL bOutsideClient; - UINT nIndex = ItemFromPoint(point, bOutsideClient); - if (nIndex >= 65535 || GetCount() <= 0) + int nIndex = VirtualHitTest(point.y); + if (nIndex == wxNOT_FOUND) + { return Invalid_v; + } - std::vector tids = GetTileIDs(nIndex); - ASSERT(!tids.empty() && tids[size_t(0)] != nullTid); + std::vector tids = GetTileIDs(value_preserving_cast(nIndex)); + wxASSERT(!tids.empty() && tids[size_t(0)] != nullTid); - std::vector rcts = GetTileRectsForItem(value_preserving_cast(nIndex), tids); + std::vector rcts = GetTileRectsForItem(value_preserving_cast(nIndex), tids); for (size_t i = size_t(0); i < rcts.size(); ++i) { - ASSERT(!rcts[i].IsRectEmpty()); - if (rcts[i].PtInRect(point)) + wxASSERT(!rcts[i].IsEmpty()); + if (rcts[i].Contains(point)) { rct = ItemToClient(rcts[i]); - const CDrawObj& pObj = MapIndexToItem(nIndex); + const CDrawObj& pObj = MapIndexToItem(value_preserving_cast(nIndex)); if (pObj.GetType() == CDrawObj::drawPieceObj) { const CPieceObj& pieceObj = static_cast(pObj); - CPieceTable& pieceTbl = m_pDoc->GetPieceTable(); + const CPieceTable& pieceTbl = m_pDoc->GetPieceTable(); uint8_t side = pieceTbl.GetSide(pieceObj.m_pid, i); - return (m_pDoc->*func)(pieceObj, side); + return ((*m_pDoc).*func)(pieceObj, side); } else { - return (m_pDoc->*func)(pObj, Invalid_v); + return ((*m_pDoc).*func)(pObj, Invalid_v); } } } @@ -340,12 +354,14 @@ GameElement CSelectListBox::OnGetHitItemCodeAtPoint(GetGameElementCodeForObject_ return Invalid_v; } -void CSelectListBox::OnGetTipTextForItemCode(GameElement nItemCode, - CB::string& strTip) const +CB::string CSelectListBox::OnGetTipTextForItemCode(GameElement nItemCode) const { if (nItemCode == Invalid_v) - return; - strTip = m_pDoc->GetGameElementString(nItemCode); + { + wxASSERT(!"invalid gameelement"); + return CB::string(); + } + return m_pDoc->GetGameElementString(nItemCode); } ///////////////////////////////////////////////////////////////////////////// @@ -356,7 +372,7 @@ BOOL CSelectListBox::OnDoesItemHaveTipText(size_t nItem) const if (pDObj.GetType() == CDrawObj::drawPieceObj) { const CPieceObj& pObj = static_cast(pDObj); - CPieceTable& pieceTbl = m_pDoc->GetPieceTable(); + const CPieceTable& pieceTbl = m_pDoc->GetPieceTable(); size_t sides = pieceTbl.GetSides(pObj.m_pid); for (size_t i = size_t(0); i < sides; ++i) { @@ -395,26 +411,21 @@ CB::string CSelectListBox::OnGetItemDebugString(size_t nIndex) const ///////////////////////////////////////////////////////////////////////////// -CSize CSelectListBox::OnItemSize(size_t nIndex) const +wxSize CSelectListBox::GetItemSize(size_t nIndex) const { - ASSERT(m_pDoc != NULL); + wxASSERT(m_pDoc != NULL); std::vector tids = GetTileIDs(nIndex); - ASSERT(!tids.empty() && tids[size_t(0)] != nullTid); + wxASSERT(!tids.empty() && tids[size_t(0)] != nullTid); return DoOnItemSize(nIndex, tids); } -void CSelectListBox::OnItemDraw(CDC& pDC, size_t nIndex, UINT nAction, UINT nState, - CRect rctItem) const +void CSelectListBox::OnDrawItem(wxDC& pDC, const wxRect& rctItem, size_t nIndex) const { - // see https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-drawitemstruct - if (nIndex == size_t(UINT(-1))) - return; // Nothing to draw. - std::vector tids = GetTileIDs(nIndex); - ASSERT(!tids.empty() && tids[size_t(0)] != nullTid); - DoOnDrawItem(pDC, nIndex, nAction, nState, rctItem, tids); + wxASSERT(!tids.empty() && tids[size_t(0)] != nullTid); + DoOnDrawItem(pDC, nIndex, rctItem, tids); } // retval[0] is active face, followed by inactives @@ -424,7 +435,7 @@ std::vector CSelectListBox::GetTileIDs(size_t nIndex) const if (pDObj.GetType() == CDrawObj::drawPieceObj) { - CPieceTable& pPTbl = m_pDoc->GetPieceTable(); + const CPieceTable& pPTbl = m_pDoc->GetPieceTable(); PieceID pid = static_cast(pDObj).m_pid; @@ -458,21 +469,24 @@ std::vector CSelectListBox::GetTileIDs(size_t nIndex) const else if (pDObj.GetType() == CDrawObj::drawMarkObj) { MarkID mid = static_cast(pDObj).m_mid; - CMarkManager& pMMgr = m_pDoc->GetMarkManager(); + const CMarkManager& pMMgr = m_pDoc->GetMarkManager(); std::vector retval; retval.push_back(pMMgr.GetMark(mid).m_tid); return retval; } else { - ASSERT(FALSE); // Shouldn't happen + wxASSERT(FALSE); // Shouldn't happen return std::vector(); } } const CPlayBoardView& CSelectListBox::GetBoardView() const { - CFrameWnd& frame = CheckedDeref(AFXGetParentFrame(this)); + wxWindow& view = CheckedDeref(GetParent()); + wxWindow& container = CheckedDeref(view.GetParent()); + CWnd& cwndContainer = CheckedDeref(CB::ToCWnd(container)); + CFrameWnd& frame = CheckedDeref(AFXGetParentFrame(&cwndContainer)); const CPlayBoardFrame& pbrdFrame = CheckedDeref(DYNAMIC_DOWNCAST(CPlayBoardFrame, &frame)); return pbrdFrame.GetActiveBoardView(); } diff --git a/GP/LBoxSlct.h b/GP/LBoxSlct.h index 07ce9876..8c3fb409 100644 --- a/GP/LBoxSlct.h +++ b/GP/LBoxSlct.h @@ -1,6 +1,6 @@ // LBoxSlct.h // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -58,11 +58,11 @@ class CSelectListBox : public CTileBaseListBox2 // Operations public: - void SetDocument(CGamDoc* pDoc) { CTileBaseListBox2::SetDocument(CheckedDeref(pDoc)); m_pDoc = pDoc; } + void SetDocument(CGamDoc& pDoc) { CTileBaseListBox2::SetDocument(pDoc); m_pDoc = &pDoc; } // Implementation protected: - CGamDoc* m_pDoc; + CB::propagate_const m_pDoc; GameElement menuGameElement = Invalid_v; @@ -71,31 +71,28 @@ class CSelectListBox : public CTileBaseListBox2 std::vector GetTileIDs(size_t nIndex) const; // Overrides - virtual CSize OnItemSize(size_t nIndex) const override; - virtual void OnItemDraw(CDC& pDC, size_t nIndex, UINT nAction, UINT nState, - CRect rctItem) const override; - virtual BOOL OnDragSetup(DragInfo& pDI) const override; + wxSize GetItemSize(size_t nIndex) const override; + void OnDrawItem(wxDC& pDC, const wxRect& rctItem, size_t nIndex) const override; + virtual BOOL OnDragSetup(DragInfoWx& pDI) const override; virtual CB::string OnGetItemDebugString(size_t nItem) const override; // Tool tip processing virtual BOOL OnIsToolTipsEnabled() const override; - virtual GameElement OnGetHitItemCodeAtPoint(CPoint point, CRect& rct) const override; + virtual GameElement OnGetHitItemCodeAtPoint(wxPoint point, wxRect& rct) const override; private: typedef GameElement (CGamDoc::*GetGameElementCodeForObject_t)(const CDrawObj& pDObj, size_t nSide) const; - GameElement OnGetHitItemCodeAtPoint(GetGameElementCodeForObject_t func, CPoint point, CRect& rct) const; + GameElement OnGetHitItemCodeAtPoint(GetGameElementCodeForObject_t func, wxPoint point, wxRect& rct) const; public: - virtual void OnGetTipTextForItemCode(GameElement nItemCode, CB::string& strTip) const override; + virtual CB::string OnGetTipTextForItemCode(GameElement nItemCode) const override; virtual BOOL OnDoesItemHaveTipText(size_t nItem) const override; - //{{AFX_MSG(CSelectListBox) - afx_msg LRESULT OnDragItem(WPARAM wParam, LPARAM lParam); - afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); - afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); - afx_msg BOOL OnActTurnOver(UINT id); - afx_msg void OnUpdateActTurnOver(CCmdUI* pCmdUI); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() + void OnDragItem(DragDropEvent& event); + void OnContextMenu(wxContextMenuEvent& event); + void OnInitMenuPopup(wxMenuEvent& event); + void OnActTurnOver(wxCommandEvent& event); + void OnUpdateActTurnOver(wxUpdateUIEvent& pCmdUI); + wxDECLARE_EVENT_TABLE(); private: const CPlayBoardView& GetBoardView() const; @@ -103,7 +100,8 @@ class CSelectListBox : public CTileBaseListBox2 { return const_cast(std::as_const(*this).GetBoardView()); } + + wxDECLARE_DYNAMIC_CLASS(CSelectListBox); }; #endif - diff --git a/GP/LBoxTray.cpp b/GP/LBoxTray.cpp index 9ba9c8bb..0d6b2b2c 100644 --- a/GP/LBoxTray.cpp +++ b/GP/LBoxTray.cpp @@ -1,6 +1,6 @@ // LBoxTray.cpp // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -364,7 +364,6 @@ CTrayListBoxWx::CTrayListBoxWx(CGamDoc& pDoc) : CTrayListBoxWx() { Init(pDoc); - CGrafixListBoxDataWx::SetDocument(pDoc); } ///////////////////////////////////////////////////////////////////////////// @@ -374,12 +373,10 @@ const CTileManager& CTrayListBoxWx::GetTileManager() const return m_pDoc->GetTileManager(); } -#if 0 -BOOL CTrayListBox::IsShowingTileImages() const +BOOL CTrayListBoxWx::IsShowingTileImages() const { return m_eTrayViz == trayVizAllSides || m_eTrayViz == trayVizOneSide; } -#endif void CTrayListBoxWx::SetTrayContentVisibility(TrayViz eTrayViz, CB::string pszHiddenString) { @@ -459,7 +456,6 @@ BOOL CTrayListBoxWx::OnDoesItemHaveTipText(size_t nItem) const PieceID pid = MapIndexToItem(nItem); if (m_eTrayViz != trayVizAllSides) { - wxASSERT(!"untested code"); uint8_t side = m_pDoc->GetPieceTable().GetSide(pid); return m_pDoc->HasGameElementString(MakePieceElement(pid, side)); } @@ -470,7 +466,6 @@ BOOL CTrayListBoxWx::OnDoesItemHaveTipText(size_t nItem) const { if (m_pDoc->HasGameElementString(MakePieceElement(pid, i))) { - wxASSERT(!"untested code"); return true; } } @@ -480,50 +475,46 @@ BOOL CTrayListBoxWx::OnDoesItemHaveTipText(size_t nItem) const ///////////////////////////////////////////////////////////////////////////// -#if 0 -void CTrayListBox::DeselectAll() +void CTrayListBoxWx::DeselectAll() { - ASSERT(IsMultiSelect()); - if (GetCount() < 1) + wxASSERT(IsMultiSelect()); + if (GetItemCount() < 1) return; - SelItemRange(FALSE, 0, GetCount()-1); + BASE::DeselectAll(); } -size_t CTrayListBox::SelectTrayPiece(PieceID pid) +size_t CTrayListBoxWx::SelectTrayPiece(PieceID pid) { size_t nIndex = MapItemToIndex(pid); if (nIndex != Invalid_v) { - ShowListIndex(value_preserving_cast(nIndex)); - SetSel(value_preserving_cast(nIndex), TRUE); + ShowListIndex(nIndex); + Select(nIndex, TRUE); } else { - if (GetCount() > 0) - SetSel(0, TRUE); + if (GetItemCount() > 0) + Select(0, TRUE); } return nIndex; } ///////////////////////////////////////////////////////////////////////////// -void CTrayListBox::ShowListIndex(int nPos) +void CTrayListBoxWx::ShowListIndex(size_t nPos) { - if (nPos < GetTopIndex()) + if (nPos < this->GetVisibleRowsBegin()) { - SetTopIndex(nPos); + ScrollToRow(nPos); return; } - CRect rct; - GetItemRect(nPos, &rct); - CRect rctClient; - GetClientRect(&rctClient); - if (rct.IntersectRect(&rct, &rctClient)) + wxRect rct = GetItemRect(nPos); + wxRect rctClient = GetClientRect(); + if (rct.Intersects(rctClient)) return; - SetTopIndex(nPos); + ScrollToRow(nPos); } -#endif ///////////////////////////////////////////////////////////////////////////// @@ -557,26 +548,11 @@ void CTrayListBoxWx::OnDrawItem(wxDC& pDC, const wxRect& rctItem, size_t nIndex) else { // Hidden pieces. Draw the supplied text. -#if 0 - pDC.SetTextAlign(TA_TOP | TA_LEFT); - CBrush brBack(GetSysColor(nState & ODS_SELECTED ? - COLOR_HIGHLIGHT : COLOR_WINDOW)); - pDC.FillRect(&rctItem, &brBack); // Fill background color - pDC.SetBkMode(TRANSPARENT); - CFont* pPrvFont = pDC.SelectObject(CFont::FromHandle(g_res.h8ss)); - pDC.SetTextColor(GetSysColor(nState & ODS_SELECTED ? - COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)); - pDC.TextOut(rctItem.left, rctItem.top, m_strHiddenString); - pDC.SelectObject(pPrvFont); -#else - wxASSERT(!"needs testing"); - // TODO: is bkg automatic? pDC.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT); pDC.SetFont(g_res.h8ssWx); pDC.SetTextForeground(wxSystemSettings::GetColour(IsSelected(nIndex) ? wxSYS_COLOUR_HIGHLIGHTTEXT : wxSYS_COLOUR_WINDOWTEXT)); pDC.DrawLabel(m_strHiddenString, rctItem, wxALIGN_TOP | wxALIGN_LEFT); -#endif #if 0 if (nAction & ODA_FOCUS) pDC.DrawFocusRect(&rctItem); @@ -619,7 +595,6 @@ std::vector CTrayListBoxWx::GetPieceTileIDs(size_t nIndex) const BOOL CTrayListBoxWx::OnDragSetup(DragInfoWx& pDI) const { - wxASSERT(!"needs testing"); if (m_pDoc->IsPlaying()) { pDI.SetDragType(DRAG_INVALID); @@ -636,7 +611,7 @@ BOOL CTrayListBoxWx::OnDragSetup(DragInfoWx& pDI) const } else { - ASSERT(!"untested code"); + wxASSERT(!"untested code"); pDI.SetDragType(DRAG_PIECE); pDI.GetSubInfo().m_pieceID = GetCurMapItem(); pDI.GetSubInfo().m_size = GetDragSize(); diff --git a/GP/LBoxTray.h b/GP/LBoxTray.h index 245cde16..2006e5b9 100644 --- a/GP/LBoxTray.h +++ b/GP/LBoxTray.h @@ -1,6 +1,6 @@ // LBoxTray.cpp // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -112,7 +112,12 @@ class CTrayListBoxWx : public CGrafixListBoxDataWx public: CTrayListBoxWx(); CTrayListBoxWx(CGamDoc& pDoc); - void Init(const CGamDoc& pDoc) { wxASSERT(!m_pDoc); m_pDoc = &pDoc; } + void Init(CGamDoc& pDoc) + { + wxASSERT(!m_pDoc); + BASE::SetDocument(pDoc); + m_pDoc = &pDoc; + } // Attributes public: @@ -126,7 +131,7 @@ class CTrayListBoxWx : public CGrafixListBoxDataWx public: void DeselectAll(); size_t SelectTrayPiece(PieceID pid); - void ShowListIndex(int nPos); + void ShowListIndex(size_t nPos); void SetTrayContentVisibility(TrayViz eTrayViz, CB::string pszHiddenString = CB::string()); void SetTipsAllowed(BOOL bTipsAllowed) @@ -164,6 +169,8 @@ class CTrayListBoxWx : public CGrafixListBoxDataWx wxDECLARE_DYNAMIC_CLASS(CTrayListBoxWx); private: + typedef CGrafixListBoxDataWx BASE; + bool IsShowAllSides(PieceID pid) const; }; diff --git a/GP/MoveMgr.cpp b/GP/MoveMgr.cpp index 8039f240..278d2102 100644 --- a/GP/MoveMgr.cpp +++ b/GP/MoveMgr.cpp @@ -1025,7 +1025,7 @@ void CObjectDelete::DoMove(CGamDoc& pDoc, int nMoveWithinGroup) const if (pPBoard != NULL) { - std::vector> list; + std::vector> list; list.push_back(pObj); pDoc.DeleteObjectsInTable(list); } diff --git a/GP/PBoard.cpp b/GP/PBoard.cpp index 6ef2f59f..0f52389e 100644 --- a/GP/PBoard.cpp +++ b/GP/PBoard.cpp @@ -1,6 +1,6 @@ // PBoard.cpp // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -141,6 +141,20 @@ void CPlayBoard::Draw(CDC& pDC, const CRect& pDrawRct, TileScale eScale) m_pIndList->Draw(pDC, pDrawRct, eScale); } +void CPlayBoard::Draw(wxDC& pDC, const wxRect& pDrawRct, TileScale eScale) +{ + wxASSERT(m_pBoard); + wxASSERT(m_pPceList); + + if (m_bIVisible && !m_bIndOnTop) + m_pIndList->Draw(pDC, pDrawRct, eScale); + + m_pPceList->Draw(pDC, pDrawRct, eScale, TRUE, FALSE, !m_bPVisible, m_bLockedDrawnBeneath); + + if (m_bIVisible && m_bIndOnTop) + m_pIndList->Draw(pDC, pDrawRct, eScale); +} + ////////////////////////////////////////////////////////////////////// // Piece is centered on point. diff --git a/GP/PBoard.h b/GP/PBoard.h index 3cb7ad2c..a34d8f32 100644 --- a/GP/PBoard.h +++ b/GP/PBoard.h @@ -107,6 +107,7 @@ class CPlayBoard // Operations public: void Draw(CDC& pDC, const CRect& pDrawRct, TileScale eScale); + void Draw(wxDC& pDC, const wxRect& pDrawRct, TileScale eScale); // ------- // CPieceObj& AddPiece(CPoint pnt, PieceID pid); const CPieceObj* FindPieceID(PieceID pid) const; diff --git a/GP/PalMark.cpp b/GP/PalMark.cpp index 312f3d19..db4ffb14 100644 --- a/GP/PalMark.cpp +++ b/GP/PalMark.cpp @@ -1,6 +1,6 @@ // PalMark.cpp : implementation file // -// Copyright (c) 1994-2024 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -36,7 +36,9 @@ static char THIS_FILE[] = __FILE__; #endif -IMPLEMENT_DYNCREATE(CMarkerPalette, CMiniFrameWnd) +#if 0 +wxIMPLEMENT_CLASS(CMarkerPalette, wxPanel) +#endif #ifdef _DEBUG #define new DEBUG_NEW @@ -44,53 +46,65 @@ IMPLEMENT_DYNCREATE(CMarkerPalette, CMiniFrameWnd) ///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CMarkerPalette, CWnd) - //{{AFX_MSG_MAP(CMarkerPalette) +wxBEGIN_EVENT_TABLE(CMarkerPalette, wxPanel) +#if 0 ON_WM_ERASEBKGND() ON_WM_SIZE() ON_WM_CREATE() ON_WM_WINDOWPOSCHANGING() - ON_CBN_SELCHANGE(IDC_W_MARKLIST, OnMarkerNameCbnSelchange) - ON_MESSAGE(WM_OVERRIDE_SELECTED_ITEM, OnOverrideSelectedItem) - ON_MESSAGE(WM_GET_DRAG_SIZE, OnGetDragSize) +#endif + EVT_CHOICE(XRCID("m_comboMGrp"), OnMarkerNameCbnSelchange) + EVT_OVERRIDE_SELECTED_ITEM(OnOverrideSelectedItem) + EVT_GET_DRAG_SIZE(OnGetDragSize) +#if 0 ON_WM_HELPINFO() ON_WM_CREATE() - //}}AFX_MSG_MAP - ON_MESSAGE(WM_PALETTE_HIDE, OnPaletteHide) - ON_MESSAGE(WM_WINSTATE_RESTORE, OnMessageRestoreWinState) +#endif + EVT_COMMAND(wxID_ANY, WM_PALETTE_HIDE_WX, OnPaletteHide) + EVT_WINSTATE_RESTORE(OnMessageRestoreWinState) +wxEND_EVENT_TABLE() + +BEGIN_MESSAGE_MAP(CMarkerPaletteContainer, CWnd) + ON_WM_CREATE() + ON_WM_SETFOCUS() + ON_WM_SIZE() END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMarkerPalette -CMarkerPalette::CMarkerPalette() +CMarkerPalette::CMarkerPalette(CMarkerPaletteContainer& container, CGamDoc& pDoc) : + m_pContainer(&container), + m_pDoc(&pDoc), + m_comboMGrp(nullptr), + m_listMark(nullptr) { - m_pDoc = NULL; - - m_listMark.EnableDrag(TRUE); m_dummyArray.push_back(MarkID(0)); m_bStateVarsArmed = FALSE; m_nComboHeight = 0; - m_pDockingFrame = NULL; } -BOOL CMarkerPalette::Create(CWnd* pOwnerWnd, DWORD dwStyle, UINT nID) +BOOL CMarkerPalette::Create(/*CWnd& pOwnerWnd, DWORD dwStyle, UINT nID*/) { - dwStyle |= WS_CHILD | WS_VISIBLE; - if (!CWnd::Create(AfxRegisterWndClass(0), NULL, dwStyle, - CRect(0, 0, 200, 100), pOwnerWnd, nID)) + if (!CB::XrcLoad(*this, *m_pContainer, "CMarkerPalette")) { - TRACE("Failed to create Tray palette window.\n"); - return FALSE; + return false; } + m_comboMGrp = XRCCTRL(*this, "m_comboMGrp", wxChoice); + m_listMark = XRCCTRL(*this, "m_listMark", CMarkListBoxWx); + (*m_pContainer)->Layout(); + + m_listMark->EnableDrag(TRUE); + m_listMark->SetDocument(&*m_pDoc); UpdatePaletteContents(); // Queue up a message to finish up state restore. - PostMessage(WM_WINSTATE_RESTORE); + QueueEvent(WinStateRestoreEvent().Clone()); return TRUE; } +#if 0 int CMarkerPalette::OnCreate(LPCREATESTRUCT lpCreateStruct) { CRect rctCombo; @@ -128,96 +142,101 @@ int CMarkerPalette::OnCreate(LPCREATESTRUCT lpCreateStruct) return 0; } +#endif /////////////////////////////////////////////////////////////////////// // This method handles the custom message WM_WINSTATE_RESTORE. The // message is posted during view initial update if the state of // the windows should be restored. -LRESULT CMarkerPalette::OnMessageRestoreWinState(WPARAM, LPARAM) +void CMarkerPalette::OnMessageRestoreWinState(WinStateRestoreEvent& /*event*/) { UpdatePaletteContents(); if (!m_bStateVarsArmed) - return (LRESULT)0; + return; - m_comboMGrp.SetCurSel(m_nComboIndex); + m_comboMGrp->SetSelection(m_nComboIndex == uint32_t(wxNOT_FOUND) ? + wxNOT_FOUND + : + value_preserving_cast(m_nComboIndex)); UpdateMarkerList(); - m_listMark.SetCurSel(m_nListCurSel); - m_listMark.SetTopIndex(m_nListTopindex); + m_listMark->SetSelection(m_nListCurSel == uint32_t(wxNOT_FOUND) ? + wxNOT_FOUND + : + value_preserving_cast(m_nListCurSel)); + m_listMark->ScrollToRow(value_preserving_cast(m_nListTopindex)); m_bStateVarsArmed = FALSE; - - return (LRESULT)0; } ///////////////////////////////////////////////////////////////////////////// -LRESULT CMarkerPalette::OnPaletteHide(WPARAM, LPARAM) +void CMarkerPalette::OnPaletteHide(wxCommandEvent& /*event*/) { GetMainFrame()->SendMessage(WM_COMMAND, ID_VIEW_MARKERPAL); - return (LRESULT)0; } ///////////////////////////////////////////////////////////////////////////// -size_t CMarkerPalette::GetSelectedMarkerGroup() +size_t CMarkerPalette::GetSelectedMarkerGroup() const { - int nSel = m_comboMGrp.GetCurSel(); - if (nSel < 0) + int nSel = m_comboMGrp->GetSelection(); + if (nSel == wxNOT_FOUND) return Invalid_v; - return value_preserving_cast(m_comboMGrp.GetItemData(nSel)); + return value_preserving_cast(reinterpret_cast(m_comboMGrp->GetClientData(value_preserving_cast(nSel)))); } -int CMarkerPalette::FindMarkerGroupIndex(size_t nGroupNum) +int CMarkerPalette::FindMarkerGroupIndex(size_t nGroupNum) const { - if (m_comboMGrp.GetCount() <= 0) - return -1; - for (int nIdx = 0; nIdx < m_comboMGrp.GetCount(); nIdx++) + if (m_comboMGrp->IsEmpty()) + return wxNOT_FOUND; + for (size_t nIdx = size_t(0) ; nIdx < m_comboMGrp->GetCount() ; ++nIdx) { - if (value_preserving_cast(m_comboMGrp.GetItemData(nIdx)) == nGroupNum) - return nIdx; + if (reinterpret_cast(m_comboMGrp->GetClientData(value_preserving_cast(nIdx))) == nGroupNum) + return value_preserving_cast(nIdx); } - return -1; + return wxNOT_FOUND; } ///////////////////////////////////////////////////////////////////////////// -LRESULT CMarkerPalette::OnOverrideSelectedItem(WPARAM wParam, LPARAM lParam) +void CMarkerPalette::OnOverrideSelectedItem(OverrideSelectedItemEvent& event) { size_t nSel = GetSelectedMarkerGroup(); if (nSel == Invalid_v) - return (LRESULT)0; + { + event.Skip(); + return; + } CMarkManager& pMMgr = m_pDoc->GetMarkManager(); CMarkSet& pMSet = pMMgr.GetMarkSet(nSel); if (pMSet.IsRandomMarkerPull()) { - COverrideInfo& oi = *reinterpret_cast*>(wParam); - oi.CheckType(); + OverrideSelectedItemEvent& oi = event; uint32_t nRandSeed = m_pDoc->GetRandomNumberSeed(); int32_t nRandNum = CalcRandomNumberUsingSeed(0, value_preserving_cast(pMSet.GetMarkIDTable().size()), nRandSeed, &nRandSeed); - oi.m_markID = pMSet.GetMarkIDTable().at(value_preserving_cast(nRandNum)); + oi.ID() = pMSet.GetMarkIDTable().at(value_preserving_cast(nRandNum)); m_pDoc->SetRandomNumberSeed(nRandSeed); } - - return (LRESULT)1; } -LRESULT CMarkerPalette::OnGetDragSize(WPARAM wParam, LPARAM /*lParam*/) +void CMarkerPalette::OnGetDragSize(GetDragSizeEvent& event) { size_t nSel = GetSelectedMarkerGroup(); if (nSel == Invalid_v) { - ASSERT(!"bad tray"); - return 0; + wxASSERT(!"bad tray"); + event.Skip(); + return; } CMarkManager& pMMgr = m_pDoc->GetMarkManager(); CMarkSet& pMSet = pMMgr.GetMarkSet(nSel); @@ -225,31 +244,30 @@ LRESULT CMarkerPalette::OnGetDragSize(WPARAM wParam, LPARAM /*lParam*/) std::vector items; if (pMSet.IsRandomMarkerPull()) { - items.reserve(value_preserving_cast(m_listMark.GetCount())); - for (int i = 0; i < m_listMark.GetCount(); ++i) + items.reserve(m_listMark->GetItemCount()); + for (size_t i = size_t(0) ; i < m_listMark->GetItemCount() ; ++i) { - items.push_back(i); + items.push_back(value_preserving_cast(i)); } } else { - items.push_back(m_listMark.GetCurSel()); + items.push_back(m_listMark->GetSelection()); } CTileManager& tileMgr = m_pDoc->GetTileManager(); - CSize retval(0, 0); + wxSize retval(0, 0); for (int item : items) { - MarkID mid = m_listMark.MapIndexToItem(value_preserving_cast(item)); + MarkID mid = m_listMark->MapIndexToItem(value_preserving_cast(item)); MarkDef& pMark = pMMgr.GetMark(mid); - ASSERT(pMark.m_tid != nullTid); - CSize size = tileMgr.GetTile(pMark.m_tid).GetSize(); - retval.cx = std::max(retval.cx, size.cx); - retval.cy = std::max(retval.cy, size.cy); + wxASSERT(pMark.m_tid != nullTid); + wxSize size = CB::Convert(tileMgr.GetTile(pMark.m_tid).GetSize()); + retval.x = std::max(retval.x, size.x); + retval.y = std::max(retval.y, size.y); } - CheckedDeref(reinterpret_cast(wParam)) = retval; - return 1; + event.SetSize(retval); } ///////////////////////////////////////////////////////////////////////////// @@ -257,14 +275,14 @@ LRESULT CMarkerPalette::OnGetDragSize(WPARAM wParam, LPARAM /*lParam*/) void CMarkerPalette::SelectMarker(MarkID mid) { size_t nGrp = m_pDoc->GetMarkManager().FindMarkInMarkSet(mid); - ASSERT(nGrp != Invalid_v); + wxASSERT(nGrp != Invalid_v); size_t nSel = GetSelectedMarkerGroup(); if (nSel != nGrp) { - m_comboMGrp.SetCurSel(FindMarkerGroupIndex(nGrp)); + m_comboMGrp->SetSelection(FindMarkerGroupIndex(nGrp)); UpdateMarkerList(); } - m_listMark.SelectMarker(mid); + m_listMark->SelectMarker(mid); } ///////////////////////////////////////////////////////////////////////////// @@ -273,26 +291,26 @@ void CMarkerPalette::Serialize(CArchive& ar) { if (ar.IsStoring()) { - ar << (DWORD)m_comboMGrp.GetCurSel(); - ar << (DWORD)m_listMark.GetTopIndex(); - ar << (DWORD)m_listMark.GetCurSel(); + ar << static_cast(value_preserving_cast(m_comboMGrp->GetSelection())); + ar << static_cast(value_preserving_cast(m_listMark->GetVisibleRowsBegin())); + ar << static_cast(value_preserving_cast(m_listMark->GetSelection())); } else { if (CGamDoc::GetLoadingVersion() >= NumVersion(2, 90)) // V2.90 { - DWORD dwTmp; - ar >> dwTmp; m_nComboIndex = (int)dwTmp; - ar >> dwTmp; m_nListTopindex = (int)dwTmp; - ar >> dwTmp; m_nListCurSel = (int)dwTmp; + uint32_t dwTmp; + ar >> dwTmp; m_nComboIndex = dwTmp; + ar >> dwTmp; m_nListTopindex = dwTmp; + ar >> dwTmp; m_nListCurSel = dwTmp; m_bStateVarsArmed = TRUE; // Inform Create() data is good } else if (CGamDoc::GetLoadingVersion() >= NumVersion(2, 0)) // V2.0 { - DWORD dwTmp; - ar >> dwTmp; m_nComboIndex = (int)dwTmp; - ar >> dwTmp; m_nListTopindex = (int)dwTmp; - ar >> dwTmp; m_nListCurSel = (int)dwTmp; + uint32_t dwTmp; + ar >> dwTmp; m_nComboIndex = dwTmp; + ar >> dwTmp; m_nListTopindex = dwTmp; + ar >> dwTmp; m_nListCurSel = dwTmp; CWinPlacement wndSink; ar >> wndSink; // Eat this puppy m_bStateVarsArmed = TRUE; // Inform Create() data is good @@ -300,7 +318,7 @@ void CMarkerPalette::Serialize(CArchive& ar) else // Pre V2.0 data { // Just eat the old data and go with the defaults - short sTmp; + uint16_t sTmp; ar >> sTmp; ar >> sTmp; ar >> sTmp; @@ -311,27 +329,17 @@ void CMarkerPalette::Serialize(CArchive& ar) ///////////////////////////////////////////////////////////////////////////// -void CMarkerPalette::SetDocument(CGamDoc *pDoc) -{ - ASSERT(pDoc->IsKindOf(RUNTIME_CLASS(CGamDoc))); - m_pDoc = pDoc; - m_listMark.SetDocument(pDoc); -} - -///////////////////////////////////////////////////////////////////////////// - void CMarkerPalette::LoadMarkerNameList() { - ASSERT(m_pDoc); CMarkManager& pMMgr = m_pDoc->GetMarkManager(); - m_comboMGrp.ResetContent(); + m_comboMGrp->Clear(); for (size_t i = size_t(0); i < pMMgr.GetNumMarkSets(); i++) { - int nIdx = m_comboMGrp.AddString(pMMgr.GetMarkSet(i).GetName()); - m_comboMGrp.SetItemData(nIdx, value_preserving_cast(i)); // Store the marker index in the data item + int nIdx = m_comboMGrp->Append(pMMgr.GetMarkSet(i).GetName()); + m_comboMGrp->SetClientData(value_preserving_cast(nIdx), reinterpret_cast(value_preserving_cast(i))); // Store the marker index in the data item } - m_comboMGrp.SetCurSel(0); + m_comboMGrp->SetSelection(0); UpdateMarkerList(); } @@ -343,8 +351,8 @@ void CMarkerPalette::UpdatePaletteContents() if (nSel == Invalid_v) nSel = 0; // Force first entry (if any) LoadMarkerNameList(); - if (value_preserving_cast(nSel) < m_comboMGrp.GetCount()) - m_comboMGrp.SetCurSel(FindMarkerGroupIndex(nSel)); + if (nSel < m_comboMGrp->GetCount()) + m_comboMGrp->SetSelection(FindMarkerGroupIndex(nSel)); UpdateMarkerList(); } @@ -352,13 +360,12 @@ void CMarkerPalette::UpdatePaletteContents() void CMarkerPalette::UpdateMarkerList() { - ASSERT(m_pDoc); CMarkManager& pMMgr = m_pDoc->GetMarkManager(); size_t nSel = GetSelectedMarkerGroup(); if (nSel == Invalid_v) { - m_listMark.SetItemMap(NULL); + m_listMark->SetItemMap(NULL); return; } @@ -378,13 +385,14 @@ void CMarkerPalette::UpdateMarkerList() m_dummyArray.push_back(pMarkTbl->front()); pMarkTbl = &m_dummyArray; } - m_listMark.SetTrayContentVisibility(pMSet.GetMarkerTrayContentVisibility(), str); - m_listMark.SetItemMap(pMarkTbl); + m_listMark->SetTrayContentVisibility(pMSet.GetMarkerTrayContentVisibility(), str); + m_listMark->SetItemMap(pMarkTbl); } ///////////////////////////////////////////////////////////////////////////// // CMarkerPalette message handlers +#if 0 BOOL CMarkerPalette::OnEraseBkgnd(CDC* pDC) { return TRUE; // controls take care of erase @@ -406,7 +414,7 @@ void CMarkerPalette::OnSize(UINT nType, int cx, int cy) } } -void CMarkerPalette::PostNcDestroy() +void CMarkerPaletteContainer::PostNcDestroy() { /* DO NOTHING - FRAME CLASS WOULD DELETE SELF! */ } @@ -419,14 +427,71 @@ void CMarkerPalette::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) if (m_comboMGrp.m_hWnd != NULL) m_comboMGrp.ShowDropDown(FALSE); } +#endif -void CMarkerPalette::OnMarkerNameCbnSelchange() +void CMarkerPalette::OnMarkerNameCbnSelchange(wxCommandEvent& /*event*/) { UpdateMarkerList(); } +#if 0 BOOL CMarkerPalette::OnHelpInfo(HELPINFO* pHelpInfo) { GetApp()->DoHelpTopic("gp-ref-pal-markers.htm"); return TRUE; } +#endif + +CMarkerPaletteContainer::CMarkerPaletteContainer(CGamDoc& pDoc) : + CB::wxNativeContainerWindowMixin(static_cast(*this)), + child(new CMarkerPalette(*this, pDoc)) +{ +} + +void CMarkerPaletteContainer::SetDockingFrame(CDockMarkPalette* pDockingFrame) +{ + m_pDockingFrame = pDockingFrame; + SetParent(pDockingFrame); +} + +BOOL CMarkerPaletteContainer::Create(CWnd& pOwnerWnd/*, DWORD dwStyle = 0, UINT nID = 0*/) +{ + DWORD dwStyle = WS_CHILD | WS_VISIBLE; + if (!CWnd::Create(AfxRegisterWndClass(0), NULL, dwStyle, + CRect(0, 0, 200, 100), &pOwnerWnd, 0)) + { + TRACE("Failed to create Tray palette container window.\n"); + return FALSE; + } + + return TRUE; +} + +int CMarkerPaletteContainer::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CWnd::OnCreate(lpCreateStruct) == -1) + { + return -1; + } + + if (!child->Create()) + { + TRACE("Failed to create Tray palette window.\n"); + return -1; + } + + return 0; +} + +// MFC puts the focus here, so move it to the useful window +void CMarkerPaletteContainer::OnSetFocus(CWnd* pOldWnd) +{ + CWnd::OnSetFocus(pOldWnd); + child->SetFocus(); +} + +void CMarkerPaletteContainer::OnSize(UINT nType, int cx, int cy) +{ + child->SetSize(0, 0, cx, cy); + return CWnd::OnSize(nType, cx, cy); +} diff --git a/GP/PalMark.h b/GP/PalMark.h index 8e982f49..e1e92c35 100644 --- a/GP/PalMark.h +++ b/GP/PalMark.h @@ -1,6 +1,6 @@ // PalMark.h : header file // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -36,26 +36,26 @@ ///////////////////////////////////////////////////////////////////////////// class CGamDoc; +class CMarkerPaletteContainer; +class CDockMarkPalette; +class WinStateRestoreEvent; ///////////////////////////////////////////////////////////////////////////// // CMarkerPalette window - Marker palette's are part of the document object. -class CMarkerPalette : public CWnd +class CMarkerPalette : public wxPanel { - DECLARE_DYNCREATE(CMarkerPalette) - // Construction public: - CMarkerPalette(); - BOOL Create(CWnd* pOwnerWnd, DWORD dwStyle = 0, UINT nID = 0); + CMarkerPalette(CMarkerPaletteContainer& container, CGamDoc& pDoc); + BOOL Create(); // Attributes public: - void SetDocument(CGamDoc *pDoc); // Operations public: - size_t GetSelectedMarkerGroup(); + size_t GetSelectedMarkerGroup() const; void UpdatePaletteContents(); @@ -63,18 +63,10 @@ class CMarkerPalette : public CWnd void Serialize(CArchive &ar); - CDockablePane* GetDockingFrame() { return m_pDockingFrame; } - void SetDockingFrame(CDockablePane* pDockingFrame) - { - m_pDockingFrame = pDockingFrame; - SetParent(pDockingFrame); - } - // Implementation protected: - CGamDoc* m_pDoc; - CRect m_rctPos; - CDockablePane* m_pDockingFrame; + RefPtr m_pContainer; + RefPtr m_pDoc; // This dummy area only contains a single entry. It is used // when only single entry should be shown in the Tray listbox. @@ -83,45 +75,85 @@ class CMarkerPalette : public CWnd std::vector m_dummyArray; // Enclosed controls.... - CComboBox m_comboMGrp; - CMarkListBox m_listMark; + CB::propagate_const m_comboMGrp; + CB::propagate_const m_listMark; void LoadMarkerNameList(); void UpdateMarkerList(); - int FindMarkerGroupIndex(size_t nGroupNum); + int FindMarkerGroupIndex(size_t nGroupNum) const; // Some temporary vars used during windows position restoration. // They are loaded during the de-serialization process. BOOL m_bStateVarsArmed; // Set so state restore is one-shot process - int m_nComboIndex; - int m_nListTopindex; - int m_nListCurSel; + uint32_t m_nComboIndex; + uint32_t m_nListTopindex; + uint32_t m_nListCurSel; int m_nComboHeight; - CWinPlacement m_wndPlace; - // Implementation public: - virtual void PostNcDestroy(); - // Generated message map functions protected: - //{{AFX_MSG(CMarkerPalette) +#if 0 afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnDestroy(); afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); - afx_msg void OnMarkerNameCbnSelchange(); - afx_msg LRESULT OnOverrideSelectedItem(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnGetDragSize(WPARAM wParam, LPARAM lParam); +#endif + void OnMarkerNameCbnSelchange(wxCommandEvent& /*event*/); + void OnOverrideSelectedItem(OverrideSelectedItemEvent& event); + void OnGetDragSize(GetDragSizeEvent& event); +#if 0 afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - //}}AFX_MSG - afx_msg LRESULT OnPaletteHide(WPARAM, LPARAM); - afx_msg LRESULT OnMessageRestoreWinState(WPARAM, LPARAM); +#endif + void OnPaletteHide(wxCommandEvent& event); + void OnMessageRestoreWinState(WinStateRestoreEvent& event); + + wxDECLARE_EVENT_TABLE(); +}; + +class CMarkerPaletteContainer : public CWnd, + public CB::wxNativeContainerWindowMixin +{ +public: + CMarkerPaletteContainer(CGamDoc& pDoc); + BOOL Create(CWnd& pOwnerWnd/*, DWORD dwStyle = 0, UINT nID = 0*/); + +#if 0 + void PostNcDestroy() override; +#endif + operator const CMarkerPalette&() const { return *child; } + operator CMarkerPalette&() + { + return const_cast(static_cast(std::as_const(*this))); + } + const CMarkerPalette* operator->() const { return &static_cast(*this); } + CMarkerPalette* operator->() + { + return const_cast(std::as_const(*this).operator->()); + } + + const CDockMarkPalette* GetDockingFrame() const { return m_pDockingFrame.get(); } + CDockMarkPalette* GetDockingFrame() + { + return const_cast(std::as_const(*this).GetDockingFrame()); + } + void SetDockingFrame(CDockMarkPalette* pDockingFrame); + + void Serialize(CArchive& ar) override { wxASSERT(false); AfxThrowNotSupportedException(); } + +private: + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnSize(UINT nType, int cx, int cy); DECLARE_MESSAGE_MAP() + + CB::propagate_const m_pDockingFrame = nullptr; + // owned by wx + CB::propagate_const child = nullptr; }; ///////////////////////////////////////////////////////////////////////////// diff --git a/GP/PalTray.cpp b/GP/PalTray.cpp index 6e0d0723..054c60df 100644 --- a/GP/PalTray.cpp +++ b/GP/PalTray.cpp @@ -1,6 +1,6 @@ // PalTray.cpp : implementation file // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -41,7 +41,7 @@ static char THIS_FILE[] = __FILE__; #endif -IMPLEMENT_DYNAMIC(CTrayPalette, CWnd) +wxIMPLEMENT_CLASS(CTrayPalette, wxPanel) #ifdef _DEBUG #define new DEBUG_NEW @@ -53,87 +53,112 @@ IMPLEMENT_DYNAMIC(CTrayPalette, CWnd) ///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CTrayPalette, CWnd) - //{{AFX_MSG_MAP(CTrayPalette) +wxBEGIN_EVENT_TABLE(CTrayPalette, wxPanel) +#if 0 ON_WM_ERASEBKGND() ON_WM_SIZE() ON_WM_CREATE() ON_WM_WINDOWPOSCHANGING() - ON_CBN_SELCHANGE(IDC_W_TRAYNAMECOMBO, OnTrayNameCbnSelchange) - ON_LBN_DBLCLK(IDC_W_TRAYLIST, OnTrayListDoubleClick) - ON_REGISTERED_MESSAGE(WM_DRAGDROP, OnDragItem) - ON_MESSAGE(WM_OVERRIDE_SELECTED_ITEM_LIST, OnOverrideSelectedItemList) - ON_MESSAGE(WM_GET_DRAG_SIZE, OnGetDragSize) - ON_WM_CONTEXTMENU() - ON_COMMAND(ID_PTRAY_SHUFFLE, OnPieceTrayShuffle) - ON_UPDATE_COMMAND_UI(ID_PTRAY_SHUFFLE, OnUpdatePieceTrayShuffle) - ON_WM_LBUTTONUP() - ON_COMMAND(ID_PTRAY_SHUFFLE_SELECTED, OnPieceTrayShuffleSelected) - ON_UPDATE_COMMAND_UI(ID_PTRAY_SHUFFLE_SELECTED, OnUpdatePieceTrayShuffleSelected) - ON_COMMAND(ID_EDIT_ELEMENT_TEXT, OnEditElementText) - ON_UPDATE_COMMAND_UI(ID_EDIT_ELEMENT_TEXT, OnUpdateEditElementText) - ON_COMMAND_EX(ID_ACT_TURNOVER, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_PREV, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_RANDOM, OnActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_PREV, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_RANDOM, OnUpdateActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_ALL, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_ALL_PREV, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_ALL_RANDOM, OnActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_ALL, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_ALL_PREV, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_ALL_RANDOM, OnUpdateActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_SELECT, OnActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_SELECT, OnUpdateActTurnOver) - ON_COMMAND(ID_PTRAY_ABOUT, OnPieceTrayAbout) - ON_UPDATE_COMMAND_UI(ID_PTRAY_ABOUT, OnUpdatePieceTrayAbout) +#endif + EVT_CHOICE(XRCID("m_comboYGrp"), OnTrayNameCbnSelchange) + EVT_LISTBOX_DCLICK(XRCID("m_listTray"), OnTrayListDoubleClick) + EVT_DRAGDROP(OnDragItem) + EVT_OVERRIDE_SELECTED_ITEM_LIST(OnOverrideSelectedItemList) + EVT_GET_DRAG_SIZE(OnGetDragSize) + EVT_CONTEXT_MENU(OnContextMenu) + EVT_MENU(XRCID("ID_PTRAY_SHUFFLE"), OnPieceTrayShuffle) + EVT_UPDATE_UI(XRCID("ID_PTRAY_SHUFFLE"), OnUpdatePieceTrayShuffle) + EVT_BUTTON(XRCID("m_bpMenuBtn"), OnMenuButton) + EVT_MENU(XRCID("ID_PTRAY_SHUFFLE_SELECTED"), OnPieceTrayShuffleSelected) + EVT_UPDATE_UI(XRCID("ID_PTRAY_SHUFFLE_SELECTED"), OnUpdatePieceTrayShuffleSelected) + EVT_MENU(XRCID("ID_EDIT_ELEMENT_TEXT"), OnEditElementText) + EVT_UPDATE_UI(XRCID("ID_EDIT_ELEMENT_TEXT"), OnUpdateEditElementText) + EVT_MENU(XRCID("ID_ACT_TURNOVER"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_PREV"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_RANDOM"), OnActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_PREV"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_RANDOM"), OnUpdateActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_ALL"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_ALL_PREV"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_ALL_RANDOM"), OnActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_ALL"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_ALL_PREV"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_ALL_RANDOM"), OnUpdateActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_SELECT"), OnActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_SELECT"), OnUpdateActTurnOver) + EVT_MENU(XRCID("ID_PTRAY_ABOUT"), OnPieceTrayAbout) + EVT_UPDATE_UI(XRCID("ID_PTRAY_ABOUT"), OnUpdatePieceTrayAbout) +#if 0 ON_WM_HELPINFO() ON_WM_MOUSEMOVE() - //}}AFX_MSG_MAP - ON_MESSAGE(WM_WINSTATE_RESTORE, OnMessageRestoreWinState) - ON_MESSAGE(WM_PALETTE_HIDE, OnPaletteHide) +#endif + EVT_WINSTATE_RESTORE(OnMessageRestoreWinState) + EVT_COMMAND(wxID_ANY, WM_PALETTE_HIDE_WX, OnPaletteHide) +#if 0 ON_WM_INITMENUPOPUP() +#endif +wxEND_EVENT_TABLE() + +BEGIN_MESSAGE_MAP(CTrayPaletteContainer, CWnd) + ON_WM_CREATE() + ON_WM_SETFOCUS() + ON_WM_SIZE() END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTrayPalette -CTrayPalette::CTrayPalette(CGamDoc& pDoc) : +CTrayPalette::CTrayPalette(CTrayPaletteContainer& container, CGamDoc& pDoc, UINT palID) : + m_pContainer(&container), m_pDoc(&pDoc), - m_listTray(*m_pDoc) + m_bpMenuBtn(nullptr), + m_comboYGrp(nullptr), + m_listTray(nullptr) { - ASSERT(m_pDoc->IsKindOf(RUNTIME_CLASS(CGamDoc))); - m_listTray.EnableDrag(); - m_listTray.EnableSelfDrop(); - m_listTray.EnableDropScroll(); - m_listTray.SetTrayContentVisibility(trayVizAllSides); - m_dummyArray.push_back(PieceID(0)); m_bStateVarsArmed = FALSE; m_nComboHeight = 0; m_pDockingFrame = NULL; + SetPaletteID(palID); } -BOOL CTrayPalette::Create(CWnd* pOwnerWnd, DWORD dwStyle, UINT nID) +BOOL CTrayPalette::Create(/*wxWindow & pOwnerWnd, DWORD dwStyle, UINT nID*/) { LoadMenuButtonBitmap(); - dwStyle |= WS_CHILD | WS_VISIBLE; - if (!CWnd::Create(AfxRegisterWndClass(0), NULL, dwStyle, - CRect(0, 0, 200, 100), pOwnerWnd, nID)) + if (!CB::XrcLoad(*this, *m_pContainer, "CTrayPalette")) { - TRACE("Failed to create Tray palette window.\n"); - return FALSE; + return false; } + m_bpMenuBtn = XRCCTRL(*this, "m_bpMenuBtn", wxBitmapButton); + m_bpMenuBtn->SetBitmap(m_bmpMenuBtn); + m_comboYGrp = XRCCTRL(*this, "m_comboYGrp", wxChoice); + m_listTray = XRCCTRL(*this, "m_listTray", CTrayListBoxWx); + (*m_pContainer)->Layout(); + + m_listTray->Init(*m_pDoc); + m_listTray->EnableDrag(); + m_listTray->EnableSelfDrop(); + m_listTray->EnableDropScroll(); + m_listTray->SetTrayContentVisibility(trayVizAllSides); + + EnsureTooltipExistance(); UpdatePaletteContents(); // Queue up a message to finish up state restore. - PostMessage(WM_WINSTATE_RESTORE); + QueueEvent(WinStateRestoreEvent().Clone()); return TRUE; } +void CTrayPaletteContainer::SetDockingFrame(CDockTrayPalette* pDockingFrame) +{ + m_pDockingFrame = pDockingFrame; + SetParent(pDockingFrame); +} + +#if 0 int CTrayPalette::OnCreate(LPCREATESTRUCT lpCreateStruct) { m_rctMenuBtn.left = 0; @@ -178,6 +203,7 @@ int CTrayPalette::OnCreate(LPCREATESTRUCT lpCreateStruct) return 0; } +#endif ///////////////////////////////////////////////////////////////////////////// // Because of the way MFC and Windows re-parents the tooltip control they @@ -187,15 +213,12 @@ int CTrayPalette::OnCreate(LPCREATESTRUCT lpCreateStruct) BOOL CTrayPalette::EnsureTooltipExistance() { - if (m_toolTipMenu.m_hWnd == NULL) - { - // Add a tip to the menu icon click area. - m_toolTipMenu.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOPREFIX); - m_toolTipMenu.AddTool(this, IDS_TIP_CLICK_MENU, m_rctMenuBtn, ID_TIP_MENU); + // Add a tip to the menu button. + m_toolTipMenu.SetBalloonMode(true); + m_toolTipMenu.Enable(true); + m_toolTipMenu.Add(*m_bpMenuBtn, CB::string::LoadString(IDS_TIP_CLICK_MENU)); - m_toolTipCombo.Create(this, TTS_ALWAYSTIP | TTS_NOPREFIX); - return TRUE; - } + m_toolTipCombo.Enable(true); return FALSE; } @@ -203,37 +226,36 @@ BOOL CTrayPalette::EnsureTooltipExistance() void CTrayPalette::DoEditSelectedPieceText() { - ASSERT(m_listTray.GetSelCount() == 1); - int nSelItem; - m_listTray.GetSelItems(1, &nSelItem); + std::vector nSelItem = m_listTray->GetSelections(); + wxASSERT(nSelItem.size() == size_t(1)); - PieceID pid = m_listTray.MapIndexToItem(value_preserving_cast(nSelItem)); + PieceID pid = m_listTray->MapIndexToItem(nSelItem.front()); m_pDoc->DoEditPieceText(pid); } ///////////////////////////////////////////////////////////////////////////// -size_t CTrayPalette::GetSelectedTray() +size_t CTrayPalette::GetSelectedTray() const { - int nSel = m_comboYGrp.GetCurSel(); - if (nSel < 0) + int nSel = m_comboYGrp->GetSelection(); + if (nSel == wxNOT_FOUND) return Invalid_v; - return value_preserving_cast(m_comboYGrp.GetItemData(nSel)); + return value_preserving_cast(reinterpret_cast(m_comboYGrp->GetClientData(value_preserving_cast(nSel)))); } -int CTrayPalette::FindTrayIndex(size_t nTrayNum) +int CTrayPalette::FindTrayIndex(size_t nTrayNum) const { - if (m_comboYGrp.GetCount() <= 0) - return -1; + if (m_comboYGrp->GetCount() <= 0) + return wxNOT_FOUND; // @@@@@ TRACE1("m_comboYGrp.GetCount() = %d\n", m_comboYGrp.GetCount()); - for (int nIdx = 0; nIdx < m_comboYGrp.GetCount(); nIdx++) + for (unsigned nIdx = unsigned(0) ; nIdx < m_comboYGrp->GetCount() ; ++nIdx) { - if (value_preserving_cast(m_comboYGrp.GetItemData(nIdx)) == nTrayNum) - return nIdx; + if (value_preserving_cast(reinterpret_cast(m_comboYGrp->GetClientData(nIdx))) == nTrayNum) + return value_preserving_cast(nIdx); } // CAN HAPPEN! ASSERT(nIdx < m_comboYGrp.GetCount()); - return -1; + return wxNOT_FOUND; } /////////////////////////////////////////////////////////////////////// @@ -241,53 +263,49 @@ int CTrayPalette::FindTrayIndex(size_t nTrayNum) // message is posted during view initial update if the state of // the windows should be restored. -LRESULT CTrayPalette::OnMessageRestoreWinState(WPARAM, LPARAM) +void CTrayPalette::OnMessageRestoreWinState(WinStateRestoreEvent& /*event*/) { UpdatePaletteContents(); if (!m_bStateVarsArmed) - return (LRESULT)0; + return; - m_comboYGrp.SetCurSel(m_nComboIndex); + m_comboYGrp->SetSelection(value_preserving_cast(m_nComboIndex)); UpdateTrayList(); - for (int i = 0; i < m_tblListBoxSel.GetSize(); i++) - m_listTray.SetSel(m_tblListBoxSel[i]); - m_listTray.SetTopIndex(m_nListTopindex); + for (size_t i = size_t(0) ; i < m_tblListBoxSel.size() ; ++i) + m_listTray->SetSelection(m_tblListBoxSel[i]); + m_listTray->ScrollToRow(m_nListTopindex); m_bStateVarsArmed = FALSE; - return (LRESULT)0; } ///////////////////////////////////////////////////////////////////////////// -LRESULT CTrayPalette::OnPaletteHide(WPARAM, LPARAM) +void CTrayPalette::OnPaletteHide(wxCommandEvent& /*event*/) { GetMainFrame()->SendMessage(WM_COMMAND, - (WPARAM)(m_nID == 0 ? ID_VIEW_TRAYA : ID_VIEW_TRAYB)); - return (LRESULT)0; + (WPARAM)(m_nID)); } ///////////////////////////////////////////////////////////////////////////// -void CTrayPalette::DoMenu(CPoint point, bool rightButton) +void CTrayPalette::DoMenu(wxPoint point) { // remember clicked side in case of ID_ACT_TURNOVER_SELECT - CPoint clientPoint(point); - ScreenToClient(&clientPoint); - CWnd* child = ChildWindowFromPoint(clientPoint); - ASSERT(child == this || child == &m_listTray); - if (child == &m_listTray) - { - CRect rect; - MapWindowPoints(&m_listTray, &clientPoint, 1); + wxWindow* child = wxFindWindowAtPoint(point); + wxASSERT(child == &*m_bpMenuBtn || child == &*m_listTray); + if (child == &*m_listTray) + { + wxRect rect; + wxPoint clientPoint = m_listTray->ScreenToClient(point); /* KLUDGE: OnGetHitItemCodeAtPoint is public in base CGrafixListBox, but protected in derived CTrayListBox. Why? */ - menuGameElement = static_cast(m_listTray).OnGetHitItemCodeAtPoint(clientPoint, rect); + menuGameElement = static_cast(*m_listTray).OnGetHitItemCodeAtPoint(clientPoint, rect); // ASSERT(menuGameElement != Invalid_v --> menuGameElement.IsAPiece() - ASSERT(menuGameElement == Invalid_v || + wxASSERT(menuGameElement == Invalid_v || menuGameElement.IsAPiece()); } else @@ -295,39 +313,35 @@ void CTrayPalette::DoMenu(CPoint point, bool rightButton) menuGameElement = Invalid_v; } - CMenu bar; - if (bar.LoadMenuW(IDR_MENU_PLAYER_POPUPS)) + std::unique_ptr bar(wxXmlResource::Get()->LoadMenuBar("IDR_MENU_PLAYER_POPUPS")); + if (bar) { - CMenu& popup = *bar.GetSubMenu(MENU_PV_PIECE_TRAY); - ASSERT(popup.m_hMenu != NULL); + int index = bar->FindMenu("5=PV_PIECE_TRAY"); + wxASSERT(index != wxNOT_FOUND); + std::unique_ptr popup(bar->Remove(value_preserving_cast(index))); // Make sure we clean up even if exception is tossed. - TRY + try { - popup.TrackPopupMenu(TPM_LEFTBUTTON | - TPM_LEFTALIGN | - (rightButton ? TPM_RIGHTBUTTON : 0), - point.x, point.y, this); // Route commands through tray window + PopupMenu(&*popup, ScreenToClient(point)); + } + catch (...) + { + wxASSERT(!"exception"); } - END_TRY - } - else - { - ASSERT(!"LoadMenu error"); } } -void CTrayPalette::OnContextMenu(CWnd* pWnd, CPoint point) +void CTrayPalette::OnContextMenu(wxContextMenuEvent& event) { - DoMenu(point, true); + DoMenu(event.GetPosition()); } -void CTrayPalette::OnLButtonUp(UINT nFlags, CPoint point) +void CTrayPalette::OnMenuButton(wxCommandEvent& /*event*/) { - CRect rct; // Use the list box as a guide of where to place the menu - m_listTray.GetWindowRect(rct); - DoMenu(rct.TopLeft(), false); + wxRect rct = m_listTray->GetScreenRect(); + DoMenu(rct.GetTopLeft()); } ///////////////////////////////////////////////////////////////////////////// @@ -335,13 +349,12 @@ void CTrayPalette::OnLButtonUp(UINT nFlags, CPoint point) // of items. It gives the tray the chance to mess with the list's // contents prior to commiting it. -LRESULT CTrayPalette::OnOverrideSelectedItemList(WPARAM wParam, LPARAM lParam) +void CTrayPalette::OnOverrideSelectedItemList(OverrideSelectedItemListEvent& event) { - wchar_t prefix = value_preserving_cast(lParam); - ASSERT(prefix == L'P' && wParam); + OverrideSelectedItemListEvent& oil = event; size_t nSel = GetSelectedTray(); - if (nSel == Invalid_v || !wParam || prefix != L'P') - return (LRESULT)0; + if (nSel == Invalid_v) + return; CTrayManager& pYMgr = m_pDoc->GetTrayManager(); CTraySet& pYSet = pYMgr.GetTraySet(nSel); @@ -349,7 +362,7 @@ LRESULT CTrayPalette::OnOverrideSelectedItemList(WPARAM wParam, LPARAM lParam) if (pYSet.IsRandomPiecePull() || pYSet.IsRandomSidePull()) { - std::vector& pPceArray = *reinterpret_cast*>(wParam); + std::vector& pPceArray = oil.Vector(); uint32_t nRandSeed = m_pDoc->GetRandomNumberSeed(); @@ -391,57 +404,57 @@ LRESULT CTrayPalette::OnOverrideSelectedItemList(WPARAM wParam, LPARAM lParam) m_pDoc->SetRandomNumberSeed(nRandSeed); } - return (LRESULT)1; + return; } -LRESULT CTrayPalette::OnGetDragSize(WPARAM wParam, LPARAM /*lParam*/) +void CTrayPalette::OnGetDragSize(GetDragSizeEvent& event) { size_t nSel = GetSelectedTray(); if (nSel == Invalid_v) { - ASSERT(!"bad tray"); - return 0; + wxASSERT(!"bad tray"); + event.Skip(); + return; } CTrayManager& pYMgr = m_pDoc->GetTrayManager(); CTraySet& pYSet = pYMgr.GetTraySet(nSel); - std::vector items; + std::vector items; if (pYSet.IsRandomPiecePull() || pYSet.IsRandomSidePull()) { - items.reserve(value_preserving_cast(m_listTray.GetCount())); - for (int i = 0 ; i < m_listTray.GetCount() ; ++i) + items.reserve(m_listTray->GetItemCount()); + for (size_t i = size_t(0) ; i < m_listTray->GetItemCount() ; ++i) { items.push_back(i); } } else { - items.resize(value_preserving_cast(m_listTray.GetSelCount())); - m_listTray.GetSelItems(value_preserving_cast(items.size()), items.data()); + items = m_listTray->GetSelections(); } // check all sides of all items CPieceTable& pieceTable = m_pDoc->GetPieceTable(); CTileManager& tileMgr = m_pDoc->GetTileManager(); PlayerMask player = m_pDoc->GetCurrentPlayerMask(); - CSize retval(0, 0); - for (int item : items) + wxSize retval(0, 0); + for (size_t item : items) { - PieceID pid = m_listTray.MapIndexToItem(value_preserving_cast(item)); + PieceID pid = m_listTray->MapIndexToItem(item); std::vector tids = pieceTable.GetInactiveTileIDs(pid, TRUE); tids.push_back(pieceTable.GetActiveTileID(pid, TRUE)); for (TileID tid : tids) { - ASSERT(tid != nullTid); - CSize size = tileMgr.GetTile(tid).GetSize(); - retval.cx = std::max(retval.cx, size.cx); - retval.cy = std::max(retval.cy, size.cy); + wxASSERT(tid != nullTid); + wxSize size = CB::Convert(tileMgr.GetTile(tid).GetSize()); + retval.x = CB::max(retval.x, size.x); + retval.y = CB::max(retval.y, size.y); } } - CheckedDeref(reinterpret_cast(wParam)) = retval; - return 1; + event.SetSize(retval); + return; } ///////////////////////////////////////////////////////////////////////////// @@ -450,32 +463,35 @@ void CTrayPalette::Serialize(CArchive& ar) { if (ar.IsStoring()) { - ar << (DWORD)m_comboYGrp.GetCurSel(); - ar << (DWORD)m_listTray.GetTopIndex(); + ar << static_cast(value_preserving_cast(m_comboYGrp->GetSelection())); + ar << static_cast(value_preserving_cast(m_listTray->GetVisibleRowsBegin())); // Save the indexes of all the selected items. - m_tblListBoxSel.RemoveAll(); + m_tblListBoxSel.clear(); - int nNumSelected = m_listTray.GetSelCount(); - m_tblListBoxSel.SetSize(nNumSelected); - m_listTray.GetSelItems(nNumSelected, m_tblListBoxSel.GetData()); + std::vector selections = m_listTray->GetSelections(); + m_tblListBoxSel.reserve(selections.size()); + for (size_t i = size_t(0); i < selections.size(); ++i) + { + m_tblListBoxSel.push_back(value_preserving_cast(selections[i])); + } ar << m_tblListBoxSel; } else { if (CGamDoc::GetLoadingVersion() >= NumVersion(2, 90)) // V2.90 { - DWORD dwTmp; - ar >> dwTmp; m_nComboIndex = (int)dwTmp; - ar >> dwTmp; m_nListTopindex = (int)dwTmp; + uint32_t dwTmp; + ar >> dwTmp; m_nComboIndex = dwTmp; + ar >> dwTmp; m_nListTopindex = dwTmp; ar >> m_tblListBoxSel; m_bStateVarsArmed = TRUE; // Inform Create() data is good } else if (CGamDoc::GetLoadingVersion() >= NumVersion(2, 0)) // V2.0 { - DWORD dwTmp; - ar >> dwTmp; m_nComboIndex = (int)dwTmp; - ar >> dwTmp; m_nListTopindex = (int)dwTmp; + uint32_t dwTmp; + ar >> dwTmp; m_nComboIndex = dwTmp; + ar >> dwTmp; m_nListTopindex = dwTmp; ar >> m_tblListBoxSel; CWinPlacement wndSink; ar >> wndSink; // Eat this puppy @@ -483,7 +499,7 @@ void CTrayPalette::Serialize(CArchive& ar) } else // Pre 2.0 { - short sTmp; // Eat the old data and go with the default values + uint16_t sTmp; // Eat the old data and go with the default values ar >> sTmp; ar >> sTmp; ar >> sTmp; @@ -498,7 +514,7 @@ void CTrayPalette::LoadTrayNameList() { CTrayManager& pYMgr = m_pDoc->GetTrayManager(); - m_comboYGrp.ResetContent(); + m_comboYGrp->Clear(); for (size_t i = size_t(0); i < pYMgr.GetNumTraySets(); i++) { CTraySet& pYSet = pYMgr.GetTraySet(i); @@ -509,10 +525,10 @@ void CTrayPalette::LoadTrayNameList() pYSet.GetOwnerMask()).m_strName; strTrayName += " - " + strOwner; } - int nIdx = m_comboYGrp.AddString(strTrayName); - m_comboYGrp.SetItemData(nIdx, value_preserving_cast(i)); // Store the tray index in the data item + int nIdx = m_comboYGrp->Append(strTrayName); + m_comboYGrp->SetClientData(value_preserving_cast(nIdx), reinterpret_cast(value_preserving_cast(i))); // Store the tray index in the data item } - m_comboYGrp.SetCurSel(0); + m_comboYGrp->SetSelection(0); UpdateTrayList(); } @@ -533,47 +549,48 @@ void CTrayPalette::UpdatePaletteContents(const CTraySet* pTray) { LoadTrayNameList(); int nComboIndex = FindTrayIndex(nSel); - if (nComboIndex < 0) + if (nComboIndex == wxNOT_FOUND) nComboIndex = 0; - m_comboYGrp.SetCurSel(nComboIndex); + m_comboYGrp->SetSelection(nComboIndex); } UpdateTrayList(); } ///////////////////////////////////////////////////////////////////////////// -void CTrayPalette::ShowTrayIndex(size_t nGroup, int nPos) +void CTrayPalette::ShowTrayIndex(size_t nGroup, size_t nPos) { size_t nSel = GetSelectedTray(); if (nSel != nGroup) { - m_comboYGrp.SetCurSel(FindTrayIndex(nGroup)); + m_comboYGrp->SetSelection(FindTrayIndex(nGroup)); UpdateTrayList(); } - m_listTray.ShowListIndex(nPos); + m_listTray->ShowListIndex(nPos); } ///////////////////////////////////////////////////////////////////////////// void CTrayPalette::DeselectAll() { - if (m_hWnd != NULL) - m_listTray.DeselectAll(); + wxASSERT(m_listTray); + if (m_listTray) + m_listTray->DeselectAll(); } void CTrayPalette::SelectTrayPiece(size_t nGroup, PieceID pid, - const CB::string* pszNotificationTip /* = NULL */) + const CB::string* pszNotificationTip) { size_t nSel = GetSelectedTray(); if (nSel != nGroup) { - m_comboYGrp.SetCurSel(FindTrayIndex(nGroup)); + m_comboYGrp->SetSelection(FindTrayIndex(nGroup)); UpdateTrayList(); } - size_t nItem = m_listTray.SelectTrayPiece(pid); + size_t nItem = m_listTray->SelectTrayPiece(pid); if (pszNotificationTip != NULL) { - m_listTray.SetNotificationTip(value_preserving_cast(nItem), *pszNotificationTip); + m_listTray->SetNotificationTip(nItem, *pszNotificationTip); } } @@ -583,7 +600,7 @@ void CTrayPalette::UpdateTrayList() { CTrayManager& pYMgr = m_pDoc->GetTrayManager(); - m_toolTipCombo.DelTool(&m_comboYGrp); // Always delete current tool + m_toolTipCombo.Delete(*m_comboYGrp); // Always delete current tool size_t nSel = GetSelectedTray(); if (nSel == Invalid_v) @@ -591,21 +608,17 @@ void CTrayPalette::UpdateTrayList() // Get the name from the combo box since it has all the ownership // information added. - CB::string strTrayName = CB::string::GetLBText(m_comboYGrp, m_comboYGrp.GetCurSel()); + CB::string strTrayName = m_comboYGrp->GetString(m_comboYGrp->GetSelection()); - TOOLINFO ti; - m_toolTipCombo.FillInToolInfo(ti, &m_comboYGrp, 0); - ti.uFlags |= TTF_SUBCLASS | TTF_CENTERTIP; - ti.lpszText = const_cast(strTrayName.v_str()); - m_toolTipCombo.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti); + m_toolTipCombo.Add(*m_comboYGrp, strTrayName, CB::ToolTip::CENTER); CTraySet& pYSet = pYMgr.GetTraySet(nSel); const std::vector* pPieceTbl = &pYSet.GetPieceIDTable(); CB::string str = ""; - m_listTray.EnableDrag(TRUE); - m_listTray.EnableSelfDrop(TRUE); - m_listTray.SetTipsAllowed(TRUE); + m_listTray->EnableDrag(TRUE); + m_listTray->EnableSelfDrop(TRUE); + m_listTray->SetTipsAllowed(TRUE); TrayViz eViz = pYSet.GetTrayContentVisibility(); @@ -625,7 +638,7 @@ void CTrayPalette::UpdateTrayList() if (pYSet.IsRandomPiecePull()) { str = CB::string::LoadString(IDS_TRAY_RANDHIDDEN); - m_listTray.EnableSelfDrop(FALSE); + m_listTray->EnableSelfDrop(FALSE); } else str = CB::string::LoadString(IDS_TRAY_HIDDEN); @@ -635,7 +648,7 @@ void CTrayPalette::UpdateTrayList() if (pYSet.IsRandomPiecePull()) { str = CB::string::LoadString(IDS_TRAY_ALLRANDHIDDEN); - m_listTray.EnableSelfDrop(FALSE); + m_listTray->EnableSelfDrop(FALSE); } else str = CB::string::LoadString(IDS_TRAY_ALLHIDDEN); @@ -647,130 +660,132 @@ void CTrayPalette::UpdateTrayList() pPieceTbl = &m_dummyArray; } if (!m_pDoc->IsScenario() && pYSet.IsOwnedButNotByCurrentPlayer(*m_pDoc)) - m_listTray.SetTipsAllowed(FALSE); + m_listTray->SetTipsAllowed(FALSE); if (!m_pDoc->IsScenario() && pYSet.IsOwned() && !pYSet.IsOwnedBy(m_pDoc->GetCurrentPlayerMask()) && !pYSet.IsNonOwnerAccessAllowed()) { - m_listTray.EnableDrag(FALSE); - m_listTray.EnableSelfDrop(FALSE); + m_listTray->EnableDrag(FALSE); + m_listTray->EnableSelfDrop(FALSE); } - m_listTray.SetTrayContentVisibility(eViz, str); + m_listTray->SetTrayContentVisibility(eViz, str); - m_listTray.SetItemMap(pPieceTbl); + m_listTray->SetItemMap(pPieceTbl); } ///////////////////////////////////////////////////////////////////////////// -LRESULT CTrayPalette::OnDragItem(WPARAM wParam, LPARAM lParam) +void CTrayPalette::OnDragItem(DragDropEvent& event) { - if (wParam != GetProcessId(GetCurrentProcess())) + if (event.GetProcessId() != wxGetProcessId()) { - return -1; + return; } if (m_pDoc->IsPlaying()) - return -1; // Drags not supported during play + return; // Drags not supported during play - DragInfo* pdi = (DragInfo*)lParam; + const DragInfoWx& pdi = event.GetDragInfo(); - if (pdi->GetDragType() != DRAG_PIECE && pdi->GetDragType() != DRAG_SELECTLIST && - pdi->GetDragType() != DRAG_PIECELIST) - return -1; // Only piece drops allowed + if (pdi.GetDragType() != DRAG_PIECE && pdi.GetDragType() != DRAG_SELECTLIST && + pdi.GetDragType() != DRAG_PIECELIST) + return; // Only piece drops allowed - if (pdi->GetDragType() == DRAG_PIECE && pdi->GetSubInfo().m_gamDoc != &*m_pDoc || - pdi->GetDragType() == DRAG_SELECTLIST && pdi->GetSubInfo().m_gamDoc != &*m_pDoc || - pdi->GetDragType() == DRAG_PIECELIST && pdi->GetSubInfo().m_gamDoc != &*m_pDoc) - return -1; // Only pieces from our document. + if (pdi.GetDragType() == DRAG_PIECE && pdi.GetSubInfo().m_gamDoc != &*m_pDoc || + pdi.GetDragType() == DRAG_SELECTLIST && pdi.GetSubInfo().m_gamDoc != &*m_pDoc || + pdi.GetDragType() == DRAG_PIECELIST && pdi.GetSubInfo().m_gamDoc != &*m_pDoc) + return; // Only pieces from our document. - if (pdi->GetDragType() == DRAG_SELECTLIST) + if (pdi.GetDragType() == DRAG_SELECTLIST) { - if (!pdi->GetSubInfo().m_selectList->HasPieces()) - return -1; // Only piece drops allowed + if (!pdi.GetSubInfo().m_selectList->HasPieces()) + return; // Only piece drops allowed } // no size restriction size_t nGrpSel = GetSelectedTray(); if (nGrpSel == Invalid_v) - return -1; // No tray to drop on + return; // No tray to drop on - if (pdi->m_phase == PhaseDrag::Over) - return (LRESULT)(LPVOID)pdi->m_hcsrSuggest; - else if (pdi->m_phase == PhaseDrag::Drop) + if (pdi.m_phase == PhaseDrag::Over) + { + event.SetCursor(pdi.m_hcsrSuggest); + return; + } + else if (pdi.m_phase == PhaseDrag::Drop) { CTrayManager& pYMgr = m_pDoc->GetTrayManager(); CTraySet& pYGrp = pYMgr.GetTraySet(nGrpSel); // Force selection of item under the mouse - m_listTray.SetSelFromPoint(pdi->m_point); - int nSel = m_listTray.GetCount() <= 0 ? -1 : m_listTray.GetCurSel(); + m_listTray->SetSelFromPoint(pdi.m_point); + int nSel = m_listTray->GetSelectedCount() == size_t(0) ? wxNOT_FOUND : value_preserving_cast(m_listTray->GetSelections().front()); if (!m_pDoc->IsScenario() && pYGrp.IsOwnedButNotByCurrentPlayer(*m_pDoc) && pYGrp.GetTrayContentVisibility() == trayVizNone) - nSel = -1; // Always append pieces when dropping on single line view + nSel = wxNOT_FOUND; // Always append pieces when dropping on single line view - if (nSel >= 0) + if (nSel != wxNOT_FOUND) { // Check if the mouse is above or below the half point. // If above, insert before. If below, insert after. - CRect rct; - m_listTray.GetItemRect(nSel, &rct); - if (pdi->m_point.y > (rct.top + rct.bottom) / 2) + wxRect rct = m_listTray->GetItemRect(value_preserving_cast(nSel)); + if (pdi.m_point.y > GetMidRect(rct).y) nSel++; } size_t dropCount; - if (pdi->GetDragType() == DRAG_PIECE) + if (pdi.GetDragType() == DRAG_PIECE) { - ASSERT(!"untested code"); + wxASSERT(!"untested code"); dropCount = size_t(1); m_pDoc->AssignNewMoveGroup(); - m_pDoc->PlacePieceInTray(pdi->GetSubInfo().m_pieceID, pYGrp, nSel < 0 ? Invalid_v : value_preserving_cast(nSel)); + m_pDoc->PlacePieceInTray(pdi.GetSubInfo().m_pieceID, pYGrp, nSel == wxNOT_FOUND ? Invalid_v : value_preserving_cast(nSel)); // Select the last piece that was inserted - nSel = value_preserving_cast(pYGrp.GetPieceIDIndex(pdi->GetSubInfo().m_pieceID)); + nSel = value_preserving_cast(pYGrp.GetPieceIDIndex(pdi.GetSubInfo().m_pieceID)); } - else if (pdi->GetDragType() == DRAG_PIECELIST) + else if (pdi.GetDragType() == DRAG_PIECELIST) { m_pDoc->AssignNewMoveGroup(); - const std::vector& pieceIDList = CheckedDeref(pdi->GetSubInfo().m_pieceIDList); + const std::vector& pieceIDList = CheckedDeref(pdi.GetSubInfo().m_pieceIDList); dropCount = pieceIDList.size(); size_t temp = m_pDoc->PlacePieceListInTray(pieceIDList, - pYGrp, nSel < 0 ? Invalid_v : value_preserving_cast(nSel)); - nSel = temp == Invalid_v ? -1 : value_preserving_cast(temp); + pYGrp, nSel == wxNOT_FOUND ? Invalid_v : value_preserving_cast(nSel)); + nSel = temp == Invalid_v ? wxNOT_FOUND : value_preserving_cast(temp); } else // DRAG_SELECTLIST { - ASSERT(pdi->GetDragType() == DRAG_SELECTLIST); - std::vector> m_listPtr; - CSelList* pSLst = pdi->GetSubInfo().m_selectList; + wxASSERT(pdi.GetDragType() == DRAG_SELECTLIST); + std::vector> m_listPtr; + CSelList* pSLst = pdi.GetSubInfo().m_selectList; pSLst->LoadTableWithObjectPtrs(m_listPtr, CSelList::otAll, FALSE); pSLst->PurgeList(FALSE); dropCount = m_listPtr.size(); m_pDoc->AssignNewMoveGroup(); size_t temp = m_pDoc->PlaceObjectTableInTray(m_listPtr, - pYGrp, nSel < 0 ? Invalid_v : value_preserving_cast(nSel)); - nSel = temp == Invalid_v ? -1 : value_preserving_cast(temp); + pYGrp, nSel == wxNOT_FOUND ? Invalid_v : value_preserving_cast(nSel)); + nSel = temp == Invalid_v ? wxNOT_FOUND : value_preserving_cast(temp); m_pDoc->UpdateAllViews(NULL, HINT_UPDATESELECTLIST); } - if (nSel >= 0) + if (nSel != wxNOT_FOUND) { for (size_t i = size_t(0) ; i < dropCount ; ++i) { - m_listTray.SetSel(nSel - value_preserving_cast(i)); + m_listTray->SetSelection(nSel - value_preserving_cast(i)); } } - m_listTray.SetCurSel(nSel); + m_listTray->SetSelection(nSel); - // If the selection is out of view, force it into view. - CRect rctLBoxClient; - m_listTray.GetClientRect(&rctLBoxClient); - CRect rct; - m_listTray.GetItemRect(nSel, &rct); - if (!rct.IntersectRect(rct, rctLBoxClient)) - m_listTray.SetTopIndex(nSel); + if (nSel != wxNOT_FOUND) + { + // If the selection is out of view, force it into view. + wxRect rctLBoxClient = m_listTray->GetClientRect(); + wxRect rct = m_listTray->GetItemRect(value_preserving_cast(nSel)); + if (!rct.Intersects(rctLBoxClient)) + m_listTray->ScrollToRow(value_preserving_cast(nSel)); + } } - return 1; } ///////////////////////////////////////////////////////////////////////////// @@ -779,30 +794,25 @@ LRESULT CTrayPalette::OnDragItem(WPARAM wParam, LPARAM lParam) void CTrayPalette::LoadMenuButtonBitmap() { - HBITMAP hBMap = (HBITMAP)LoadImage(AfxGetResourceHandle(), - MAKEINTRESOURCE(IDB_MENU_ICON), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); - ASSERT(hBMap != NULL); - m_bmpMenuBtn.Attach(hBMap); - - BITMAP bmap; - m_bmpMenuBtn.GetBitmap(&bmap); - m_sizeMenuBtn.cx = bmap.bmWidth; - m_sizeMenuBtn.cy = bmap.bmHeight; - - CDC dc; - dc.CreateCompatibleDC(NULL); - CBitmap* prvBMap = dc.SelectObject(&m_bmpMenuBtn); - CBrush brush; - brush.CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); - CBrush* prvBrush = dc.SelectObject(&brush); - dc.ExtFloodFill(m_sizeMenuBtn.cx - 1, 0, RGB(0, 255, 255), FLOODFILLSURFACE); - dc.SelectObject(prvBrush); - dc.SelectObject(prvBMap); + wxBitmap hBMap(std::format("#{}", IDB_MENU_ICON), + wxBITMAP_TYPE_BMP_RESOURCE); + wxASSERT(hBMap.IsOk()); + m_bmpMenuBtn = hBMap; + + m_sizeMenuBtn.x = m_bmpMenuBtn.GetWidth(); + m_sizeMenuBtn.y = m_bmpMenuBtn.GetHeight(); + + wxMemoryDC dc; + dc.SelectObject(m_bmpMenuBtn); + wxBrush brush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE), wxBRUSHSTYLE_SOLID); + wxDCBrushChanger setBrush(dc, brush); + dc.FloodFill(m_sizeMenuBtn.x - 1, 0, wxColour(0, 255, 255), wxFLOOD_SURFACE); } ///////////////////////////////////////////////////////////////////////////// // CTrayPalette message handlers +#if 0 BOOL CTrayPalette::OnEraseBkgnd(CDC* pDC) { // Erase behind menu button only... @@ -823,6 +833,7 @@ BOOL CTrayPalette::OnEraseBkgnd(CDC* pDC) return TRUE; // controls take care of erase } +#if 0 LRESULT CTrayPalette::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) @@ -840,6 +851,7 @@ LRESULT CTrayPalette::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) } return CWnd::WindowProc(message, wParam, lParam); } +#endif void CTrayPalette::OnSize(UINT nType, int cx, int cy) { @@ -859,7 +871,7 @@ void CTrayPalette::OnSize(UINT nType, int cx, int cy) } } -void CTrayPalette::PostNcDestroy() +void CTrayPaletteContainer::PostNcDestroy() { /* DO NOTHING - FRAME CLASS WOULD DELETE SELF! */ } @@ -872,21 +884,22 @@ void CTrayPalette::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) if (m_comboYGrp.m_hWnd != NULL) m_comboYGrp.ShowDropDown(FALSE); } +#endif ///////////////////////////////////////////////////////////////////////////// -void CTrayPalette::OnTrayNameCbnSelchange() +void CTrayPalette::OnTrayNameCbnSelchange(wxCommandEvent& /*event*/) { UpdateTrayList(); } -void CTrayPalette::OnTrayListDoubleClick() +void CTrayPalette::OnTrayListDoubleClick(wxCommandEvent& /*event*/) { - if (!m_listTray.IsShowingTileImages()) + if (!m_listTray->IsShowingTileImages()) return; - int nIndex = m_listTray.GetCaretIndex(); - if (nIndex < 0 || nIndex > 65535) + int nIndex = m_listTray->GetCurrent(); + if (nIndex == wxNOT_FOUND) return; size_t nSel = GetSelectedTray(); @@ -899,15 +912,15 @@ void CTrayPalette::OnTrayListDoubleClick() return; } - PieceID pid = m_listTray.MapIndexToItem(value_preserving_cast(nIndex)); + PieceID pid = m_listTray->MapIndexToItem(value_preserving_cast(nIndex)); m_pDoc->DoEditPieceText(pid); } -void CTrayPalette::OnPieceTrayShuffle() +void CTrayPalette::OnPieceTrayShuffle(wxCommandEvent& /*event*/) { // Generate a shuffled index vector uint32_t nRandSeed = m_pDoc->GetRandomNumberSeed(); - size_t nNumIndices = value_preserving_cast(m_listTray.GetCount()); + size_t nNumIndices = m_listTray->GetItemCount(); std::vector pnIndices = AllocateAndCalcRandomIndexVector(nNumIndices, nNumIndices, nRandSeed, &nRandSeed); m_pDoc->SetRandomNumberSeed(nRandSeed); @@ -916,7 +929,7 @@ void CTrayPalette::OnPieceTrayShuffle() std::vector tblPids; tblPids.reserve(value_preserving_cast(nNumIndices)); for (size_t i = size_t(0) ; i < nNumIndices ; ++i) - tblPids.push_back(m_listTray.MapIndexToItem(pnIndices[i])); + tblPids.push_back(m_listTray->MapIndexToItem(pnIndices[i])); m_pDoc->AssignNewMoveGroup(); @@ -932,7 +945,7 @@ void CTrayPalette::OnPieceTrayShuffle() m_pDoc->PlacePieceListInTray(tblPids, pYMgr.GetTraySet(nSel), 0); } -void CTrayPalette::OnUpdatePieceTrayShuffle(CCmdUI* pCmdUI) +void CTrayPalette::OnUpdatePieceTrayShuffle(wxUpdateUIEvent& pCmdUI) { BOOL bNoOwnerRestrictions = TRUE; size_t nSel = GetSelectedTray(); @@ -943,30 +956,28 @@ void CTrayPalette::OnUpdatePieceTrayShuffle(CCmdUI* pCmdUI) bNoOwnerRestrictions = !(pYSet.IsOwnedButNotByCurrentPlayer(*m_pDoc) && !pYSet.IsNonOwnerAccessAllowed()); } - pCmdUI->Enable((m_pDoc->IsScenario() || bNoOwnerRestrictions) && - m_listTray.GetCount() > 1); + pCmdUI.Enable((m_pDoc->IsScenario() || bNoOwnerRestrictions) && + m_listTray->GetItemCount() > 1); } -void CTrayPalette::OnPieceTrayShuffleSelected() +void CTrayPalette::OnPieceTrayShuffleSelected(wxCommandEvent& /*event*/) { - size_t nNumSelected = value_preserving_cast(m_listTray.GetSelCount()); - std::vector tblListSel(nNumSelected); - m_listTray.GetSelItems(value_preserving_cast(nNumSelected), tblListSel.data()); + std::vector tblListSel = m_listTray->GetSelections(); + size_t nNumSelected = tblListSel.size(); - INT nTopSel = tblListSel[size_t(0)]; // This is where the shuffle is inserted + size_t nTopSel = tblListSel[size_t(0)]; // This is where the shuffle is inserted // Generate a shuffled index vector for the number of selected items uint32_t nRandSeed = m_pDoc->GetRandomNumberSeed(); - ASSERT(nNumSelected == tblListSel.size()); std::vector pnIndices = AllocateAndCalcRandomIndexVector(nNumSelected, nNumSelected, nRandSeed, &nRandSeed); m_pDoc->SetRandomNumberSeed(nRandSeed); // Build table of shuffled pieces std::vector tblPids; - tblPids.reserve(value_preserving_cast(nNumSelected)); + tblPids.reserve(nNumSelected); for (size_t i = size_t(0) ; i < nNumSelected ; ++i) - tblPids.push_back(m_listTray.MapIndexToItem(value_preserving_cast(tblListSel[pnIndices[i]]))); + tblPids.push_back(m_listTray->MapIndexToItem(tblListSel[pnIndices[i]])); m_pDoc->AssignNewMoveGroup(); @@ -982,7 +993,7 @@ void CTrayPalette::OnPieceTrayShuffleSelected() m_pDoc->PlacePieceListInTray(tblPids, pYMgr.GetTraySet(nSel), value_preserving_cast(nTopSel)); } -void CTrayPalette::OnUpdatePieceTrayShuffleSelected(CCmdUI* pCmdUI) +void CTrayPalette::OnUpdatePieceTrayShuffleSelected(wxUpdateUIEvent& pCmdUI) { BOOL bNoOwnerRestrictions = TRUE; size_t nSel = GetSelectedTray(); @@ -994,16 +1005,16 @@ void CTrayPalette::OnUpdatePieceTrayShuffleSelected(CCmdUI* pCmdUI) !pYSet.IsNonOwnerAccessAllowed()); } - pCmdUI->Enable((m_pDoc->IsScenario() || bNoOwnerRestrictions) && - m_listTray.GetSelCount() > 1 && m_listTray.IsShowingTileImages()); + pCmdUI.Enable((m_pDoc->IsScenario() || bNoOwnerRestrictions) && + m_listTray->GetSelectedCount() > size_t(1) && m_listTray->IsShowingTileImages()); } -void CTrayPalette::OnEditElementText() +void CTrayPalette::OnEditElementText(wxCommandEvent& event) { DoEditSelectedPieceText(); } -void CTrayPalette::OnUpdateEditElementText(CCmdUI* pCmdUI) +void CTrayPalette::OnUpdateEditElementText(wxUpdateUIEvent& pCmdUI) { BOOL bNoOwnerRestrictions = TRUE; size_t nSel = GetSelectedTray(); @@ -1013,68 +1024,71 @@ void CTrayPalette::OnUpdateEditElementText(CCmdUI* pCmdUI) CTraySet& pYSet = pYMgr.GetTraySet(nSel); bNoOwnerRestrictions = !pYSet.IsOwnedButNotByCurrentPlayer(*m_pDoc); } - pCmdUI->Enable((m_pDoc->IsScenario() || bNoOwnerRestrictions) && - m_listTray.GetSelCount() == 1 && m_listTray.IsShowingTileImages()); + pCmdUI.Enable((m_pDoc->IsScenario() || bNoOwnerRestrictions) && + m_listTray->GetSelectedCount() == size_t(1) && m_listTray->IsShowingTileImages()); } -BOOL CTrayPalette::OnActTurnOver(UINT id) +void CTrayPalette::OnActTurnOver(wxCommandEvent& event) { - CArray tblListSel; - int nNumSelected = m_listTray.GetSelCount(); - tblListSel.SetSize(nNumSelected); - m_listTray.GetSelItems(nNumSelected, tblListSel.GetData()); + int id = event.GetId(); + std::vector tblListSel = m_listTray->GetSelections(); - CArray tblListSubjects; - CArray* chosen; + std::vector tblListSubjects; + std::vector* chosen; - switch (id) + if (id == XRCID("ID_ACT_TURNOVER") || + id == XRCID("ID_ACT_TURNOVER_PREV") || + id == XRCID("ID_ACT_TURNOVER_RANDOM")) { - case ID_ACT_TURNOVER: - case ID_ACT_TURNOVER_PREV: - case ID_ACT_TURNOVER_RANDOM: - // operate on selected pieces - chosen = &tblListSel; - break; - case ID_ACT_TURNOVER_ALL: - case ID_ACT_TURNOVER_ALL_PREV: - case ID_ACT_TURNOVER_ALL_RANDOM: - // operate on all pieces - tblListSubjects.SetSize(m_listTray.GetCount()); - for (int i = 0; i < m_listTray.GetCount(); i++) - { - tblListSubjects[i] = i; - } - chosen = &tblListSubjects; - break; - case ID_ACT_TURNOVER_SELECT: - // operate on clicked side - tblListSubjects.Add(value_preserving_cast(m_listTray.MapItemToIndex(static_cast(menuGameElement)))); - chosen = &tblListSubjects; - break; - default: - AfxThrowInvalidArgException(); + // operate on selected pieces + chosen = &tblListSel; + } + else if (id == XRCID("ID_ACT_TURNOVER_ALL") || + id == XRCID("ID_ACT_TURNOVER_ALL_PREV") || + id == XRCID("ID_ACT_TURNOVER_ALL_RANDOM")) + { + // operate on all pieces + tblListSubjects.resize(m_listTray->GetItemCount()); + for (size_t i = size_t(0) ; i < m_listTray->GetItemCount() ; ++i) + { + tblListSubjects[i] = i; + } + chosen = &tblListSubjects; + } + else if (id == XRCID("ID_ACT_TURNOVER_SELECT")) + { + // operate on clicked side + tblListSubjects.push_back(m_listTray->MapItemToIndex(static_cast(menuGameElement))); + chosen = &tblListSubjects; + } + else + { + AfxThrowInvalidArgException(); } CPieceTable::Flip flip; - switch (id) + if (id == XRCID("ID_ACT_TURNOVER") || + id == XRCID("ID_ACT_TURNOVER_ALL")) { - case ID_ACT_TURNOVER: - case ID_ACT_TURNOVER_ALL: - flip = CPieceTable::fNext; - break; - case ID_ACT_TURNOVER_PREV: - case ID_ACT_TURNOVER_ALL_PREV: - flip = CPieceTable::fPrev; - break; - case ID_ACT_TURNOVER_RANDOM: - case ID_ACT_TURNOVER_ALL_RANDOM: - flip = CPieceTable::fRandom; - break; - case ID_ACT_TURNOVER_SELECT: - flip = CPieceTable::fSelect; - break; - default: - AfxThrowInvalidArgException(); + flip = CPieceTable::fNext; + } + else if (id == XRCID("ID_ACT_TURNOVER_PREV") || + id == XRCID("ID_ACT_TURNOVER_ALL_PREV")) + { + flip = CPieceTable::fPrev; + } + else if (id == XRCID("ID_ACT_TURNOVER_RANDOM") || + id == XRCID("ID_ACT_TURNOVER_ALL_RANDOM")) + { + flip = CPieceTable::fRandom; + } + else if (id == XRCID("ID_ACT_TURNOVER_SELECT")) + { + flip = CPieceTable::fSelect; + } + else + { + AfxThrowInvalidArgException(); } m_pDoc->AssignNewMoveGroup(); @@ -1082,13 +1096,13 @@ BOOL CTrayPalette::OnActTurnOver(UINT id) size_t nSel = GetSelectedTray(); if (m_pDoc->IsRecording() && flip == CPieceTable::fRandom) { - CB::string strMsg = CB::string::Format(IDS_TIP_TRAY_FLIPPED_RANDOM, chosen->GetCount()); - m_pDoc->RecordEventMessage(strMsg, nSel, m_listTray.MapIndexToItem(value_preserving_cast((*chosen)[0]))); + CB::string strMsg = CB::string::Format(IDS_TIP_TRAY_FLIPPED_RANDOM, chosen->size()); + m_pDoc->RecordEventMessage(strMsg, nSel, m_listTray->MapIndexToItem(chosen->front())); } - for (int i = 0; i < chosen->GetSize(); i++) + for (size_t i = size_t(0) ; i < chosen->size() ; ++i) { - PieceID pid = m_listTray.MapIndexToItem(value_preserving_cast((*chosen)[i])); + PieceID pid = m_listTray->MapIndexToItem((*chosen)[i]); size_t side; if (flip == CPieceTable::fSelect) { @@ -1107,34 +1121,36 @@ BOOL CTrayPalette::OnActTurnOver(UINT id) /* flipping pieces shouldn't change tray content, so restore selections */ - for (int i = 0; i < tblListSel.GetSize(); i++) + wxASSERT(m_listTray->GetSelectedCount() == size_t(0)); + for (size_t i = size_t(0) ; i < tblListSel.size() ; ++i) { - m_listTray.SetSel(tblListSel[i], true); + m_listTray->Select(tblListSel[i], true); } - - return true; } -void CTrayPalette::OnUpdateActTurnOver(CCmdUI* pCmdUI) +void CTrayPalette::OnUpdateActTurnOver(wxUpdateUIEvent& pCmdUI) { + int id = pCmdUI.GetId(); bool eligible; - switch (pCmdUI->m_nID) + if (id == XRCID("ID_ACT_TURNOVER") || + id == XRCID("ID_ACT_TURNOVER_PREV") || + id == XRCID("ID_ACT_TURNOVER_RANDOM")) { - case ID_ACT_TURNOVER: - case ID_ACT_TURNOVER_PREV: - case ID_ACT_TURNOVER_RANDOM: - eligible = m_listTray.GetSelCount() > 0; - break; - case ID_ACT_TURNOVER_ALL: - case ID_ACT_TURNOVER_ALL_PREV: - case ID_ACT_TURNOVER_ALL_RANDOM: - eligible = m_listTray.GetCount() > 0; - break; - case ID_ACT_TURNOVER_SELECT: - eligible = menuGameElement != Invalid_v; - break; - default: - AfxThrowInvalidArgException(); + eligible = m_listTray->GetSelectedCount() > size_t(0); + } + else if (id == XRCID("ID_ACT_TURNOVER_ALL") || + id == XRCID("ID_ACT_TURNOVER_ALL_PREV") || + id == XRCID("ID_ACT_TURNOVER_ALL_RANDOM")) + { + eligible = m_listTray->GetItemCount() > size_t(0); + } + else if (id == XRCID("ID_ACT_TURNOVER_SELECT")) + { + eligible = menuGameElement != Invalid_v; + } + else + { + AfxThrowInvalidArgException(); } BOOL bNoOwnerRestrictions = TRUE; @@ -1148,17 +1164,19 @@ void CTrayPalette::OnUpdateActTurnOver(CCmdUI* pCmdUI) bool enable = (m_pDoc->IsScenario() || bNoOwnerRestrictions) && eligible && - m_listTray.IsShowingTileImages(); - pCmdUI->Enable(enable); + m_listTray->IsShowingTileImages(); + pCmdUI.Enable(enable); +#if 0 if (pCmdUI->m_pSubMenu != NULL) { // Need to handle menu that the submenu is connected to. pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex, MF_BYPOSITION | (enable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED))); } +#endif } -void CTrayPalette::OnPieceTrayAbout() +void CTrayPalette::OnPieceTrayAbout(wxCommandEvent& event) { size_t nSel = GetSelectedTray(); if (nSel == Invalid_v) @@ -1183,7 +1201,7 @@ void CTrayPalette::OnPieceTrayAbout() strTmp = CB::string::LoadString(IDS_MSG_TVIZ_ALL_HIDDEN); break; default: - ASSERT(FALSE); + wxASSERT(FALSE); strTmp = CB::string::LoadString(IDS_ERR_TRAY_VIZ); } @@ -1224,15 +1242,16 @@ void CTrayPalette::OnPieceTrayAbout() strTmp = CB::string::LoadString(IDS_MSG_TVIZ_OWNER_FULL); strMsg += '\n' + strTmp; } - AfxMessageBox(strMsg, MB_ICONINFORMATION); + wxMessageBox(strMsg, CB::GetAppName(), wxICON_INFORMATION); } -void CTrayPalette::OnUpdatePieceTrayAbout(CCmdUI* pCmdUI) +void CTrayPalette::OnUpdatePieceTrayAbout(wxUpdateUIEvent& pCmdUI) { - int nSel = m_comboYGrp.GetCurSel(); - pCmdUI->Enable(nSel >= 0); + int nSel = m_comboYGrp->GetSelection(); + pCmdUI.Enable(nSel != wxNOT_FOUND); } +#if 0 BOOL CTrayPalette::OnHelpInfo(HELPINFO* pHelpInfo) { GetApp()->DoHelpTopic("gp-ref-pal-tray.htm"); @@ -1302,3 +1321,52 @@ void CTrayPalette::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu) state.m_nIndexMax = nCount; } } +#endif + +CTrayPaletteContainer::CTrayPaletteContainer(CGamDoc& pDoc, UINT palID) : + CB::wxNativeContainerWindowMixin(static_cast(*this)), + child(new CTrayPalette(*this, pDoc, palID)) +{ +} + +BOOL CTrayPaletteContainer::Create(CWnd& pOwnerWnd/*, DWORD dwStyle = 0, UINT nID = 0*/) +{ + DWORD dwStyle = WS_CHILD | WS_VISIBLE; + if (!CWnd::Create(AfxRegisterWndClass(0), NULL, dwStyle, + CRect(0, 0, 200, 100), &pOwnerWnd, 0)) + { + TRACE("Failed to create Tray palette container window.\n"); + return FALSE; + } + + return TRUE; +} + +int CTrayPaletteContainer::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (CWnd::OnCreate(lpCreateStruct) == -1) + { + return -1; + } + + if (!child->Create()) + { + TRACE("Failed to create Tray palette window.\n"); + return -1; + } + + return 0; +} + +// MFC puts the focus here, so move it to the useful window +void CTrayPaletteContainer::OnSetFocus(CWnd* pOldWnd) +{ + CWnd::OnSetFocus(pOldWnd); + child->SetFocus(); +} + +void CTrayPaletteContainer::OnSize(UINT nType, int cx, int cy) +{ + child->SetSize(0, 0, cx, cy); + return CWnd::OnSize(nType, cx, cy); +} diff --git a/GP/PalTray.h b/GP/PalTray.h index 1b725266..cd456303 100644 --- a/GP/PalTray.h +++ b/GP/PalTray.h @@ -1,6 +1,6 @@ // PalTray.h : header file // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,6 +25,7 @@ #ifndef _PALTRAY_H #define _PALTRAY_H +#include "Gp.h" #ifndef _LBOXTRAY_H #include "LBoxTray.h" #endif @@ -35,53 +36,50 @@ ///////////////////////////////////////////////////////////////////////////// +class CDockTrayPalette; class CGamDoc; +class CTrayPaletteContainer; class CTraySet; ///////////////////////////////////////////////////////////////////////////// // CTrayPalette window - Tray palette's are owned and reside in // the document object. -class CTrayPalette : public CWnd +class CTrayPalette : public wxPanel { - DECLARE_DYNAMIC(CTrayPalette) + wxDECLARE_CLASS(CTrayPalette); // Construction public: - CTrayPalette(CGamDoc& pDoc); + CTrayPalette(CTrayPaletteContainer& container, CGamDoc& pDoc, UINT palID); - BOOL Create(CWnd* pOwnerWnd, DWORD dwStyle = 0, UINT nID = 0); + BOOL Create(/*wxWindow& pOwnerWnd, DWORD dwStyle = 0, UINT nID = 0*/); // Attributes -public: +private: void SetPaletteID(UINT nID) { m_nID = nID; } - - CDockablePane* GetDockingFrame() { return m_pDockingFrame; } - void SetDockingFrame(CDockablePane* pDockingFrame) - { - m_pDockingFrame = pDockingFrame; - SetParent(pDockingFrame); - } +public: // Operations public: void DeselectAll(); - void SelectTrayPiece(size_t nGroup, PieceID pid, const CB::string* pszNotificationTip = NULL); - void ShowTrayIndex(size_t nGroup, int nPos); + void SelectTrayPiece(size_t nGroup, PieceID pid, const CB::string* pszNotificationTip); + void ShowTrayIndex(size_t nGroup, size_t nPos); void UpdatePaletteContents(const CTraySet* pTray = NULL); void Serialize(CArchive &ar); // Implementation - vars protected: + RefPtr m_pContainer; RefPtr m_pDoc; UINT m_nID; - CDockablePane* m_pDockingFrame; + CB::propagate_const m_pDockingFrame; - CBitmap m_bmpMenuBtn; - CSize m_sizeMenuBtn; - CToolTipCtrl m_toolTipMenu; - CToolTipCtrl m_toolTipCombo; // For combobox overlay + wxBitmap m_bmpMenuBtn; + wxSize m_sizeMenuBtn; + CB::ToolTip m_toolTipMenu; + CB::ToolTip m_toolTipCombo; // For combobox overlay // This dummy area only contains a single entry. It is used // when only single entry should be shown in the Tray listbox. @@ -90,29 +88,29 @@ class CTrayPalette : public CWnd std::vector m_dummyArray; // Enclosed controls.... - CComboBox m_comboYGrp; - CTrayListBox m_listTray; - CRect m_rctMenuBtn; // phony menu button dims + CB::propagate_const m_bpMenuBtn; + CB::propagate_const m_comboYGrp; + CB::propagate_const m_listTray; int m_nComboHeight; void LoadTrayNameList(); void UpdateTrayList(); - size_t GetSelectedTray(); - int FindTrayIndex(size_t nTrayNum); + size_t GetSelectedTray() const; + int FindTrayIndex(size_t nTrayNum) const; // Some temporary vars used during windows position restoration. // They are loaded during the de-serialization process. BOOL m_bStateVarsArmed; // Set so state restore is one-shot process - int m_nComboIndex; - int m_nListTopindex; + uint32_t m_nComboIndex; + uint32_t m_nListTopindex; - CWinPlacement m_wndPlace; - CArray m_tblListBoxSel; + std::vector m_tblListBoxSel; // Overrides public: - virtual void PostNcDestroy(); - virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); +#if 0 + LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam) override; +#endif // Implementation - methods protected: @@ -120,44 +118,89 @@ class CTrayPalette : public CWnd void DoEditSelectedPieceText(); BOOL EnsureTooltipExistance(); - void DoMenu(CPoint point, bool rightButton); + void DoMenu(wxPoint point); private: GameElement menuGameElement = Invalid_v; -// Generated message map functions protected: - //{{AFX_MSG(CTrayPalette) +#if 0 afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); - afx_msg void OnTrayNameCbnSelchange(); - afx_msg void OnTrayListDoubleClick(); - afx_msg LRESULT OnDragItem(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnOverrideSelectedItemList(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnGetDragSize(WPARAM wParam, LPARAM lParam); - afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnPieceTrayShuffle(); - afx_msg void OnUpdatePieceTrayShuffle(CCmdUI* pCmdUI); - afx_msg void OnPieceTrayShuffleSelected(); - afx_msg void OnUpdatePieceTrayShuffleSelected(CCmdUI* pCmdUI); - afx_msg void OnEditElementText(); - afx_msg void OnUpdateEditElementText(CCmdUI* pCmdUI); - afx_msg BOOL OnActTurnOver(UINT id); - afx_msg void OnUpdateActTurnOver(CCmdUI* pCmdUI); - afx_msg void OnPieceTrayAbout(); - afx_msg void OnUpdatePieceTrayAbout(CCmdUI* pCmdUI); +#endif + void OnTrayNameCbnSelchange(wxCommandEvent& event); + void OnTrayListDoubleClick(wxCommandEvent& event); + void OnDragItem(DragDropEvent& event); + void OnOverrideSelectedItemList(OverrideSelectedItemListEvent& event); + void OnGetDragSize(GetDragSizeEvent& event); + void OnContextMenu(wxContextMenuEvent& event); + void OnMenuButton(wxCommandEvent& event); + void OnPieceTrayShuffle(wxCommandEvent& event); + void OnUpdatePieceTrayShuffle(wxUpdateUIEvent& pCmdUI); + void OnPieceTrayShuffleSelected(wxCommandEvent& event); + void OnUpdatePieceTrayShuffleSelected(wxUpdateUIEvent& pCmdUI); + void OnEditElementText(wxCommandEvent& event); + void OnUpdateEditElementText(wxUpdateUIEvent& pCmdUI); + void OnActTurnOver(wxCommandEvent& event); + void OnUpdateActTurnOver(wxUpdateUIEvent& pCmdUI); + void OnPieceTrayAbout(wxCommandEvent& event); + void OnUpdatePieceTrayAbout(wxUpdateUIEvent& pCmdUI); +#if 0 afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnMouseMove(UINT nFlags, CPoint point); - //}}AFX_MSG afx_msg BOOL OnToolTipShow(UINT id, NMHDR *pNMH, LRESULT *pResult); - afx_msg LRESULT OnMessageRestoreWinState(WPARAM, LPARAM); - afx_msg LRESULT OnPaletteHide(WPARAM, LPARAM); +#endif + void OnMessageRestoreWinState(WinStateRestoreEvent& event); + void OnPaletteHide(wxCommandEvent& event); +#if 0 afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu); +#endif + + wxDECLARE_EVENT_TABLE(); +}; + +class CTrayPaletteContainer : public CWnd, + public CB::wxNativeContainerWindowMixin +{ +public: + CTrayPaletteContainer(CGamDoc& pDoc, UINT palID); + BOOL Create(CWnd& pOwnerWnd/*, DWORD dwStyle = 0, UINT nID = 0*/); +#if 0 + void PostNcDestroy() override; +#endif + + operator const CTrayPalette& () const { return *child; } + operator CTrayPalette& () + { + return const_cast(static_cast(std::as_const(*this))); + } + const CTrayPalette* operator->() const { return &static_cast(*this); } + CTrayPalette* operator->() + { + return const_cast(std::as_const(*this).operator->()); + } + + const CDockTrayPalette* GetDockingFrame() const { return m_pDockingFrame.get(); } + CDockTrayPalette* GetDockingFrame() + { + return const_cast(std::as_const(*this).GetDockingFrame()); + } + void SetDockingFrame(CDockTrayPalette* pDockingFrame); + + void Serialize(CArchive& ar) override { wxASSERT(false); AfxThrowNotSupportedException(); } + +private: + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnSize(UINT nType, int cx, int cy); DECLARE_MESSAGE_MAP() + + CB::propagate_const m_pDockingFrame = nullptr; + // owned by wx + CB::propagate_const child = nullptr; }; ///////////////////////////////////////////////////////////////////////////// diff --git a/GP/SelOPlay.cpp b/GP/SelOPlay.cpp index 83f6cc70..abaf3e9d 100644 --- a/GP/SelOPlay.cpp +++ b/GP/SelOPlay.cpp @@ -1,6 +1,6 @@ // SelOPlay.cpp // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -49,10 +49,12 @@ const int handleHalfWidth = 3; ///////////////////////////////////////////////////////////////////// // Class level variables -CPen NEAR CSelection::c_penDot(PS_DOT, 1, RGB(0,0,0)); +const wxPen CSelection::c_penDot(*wxLIGHT_GREY, 1, wxPENSTYLE_SHORT_DASH); +#if 0 int NEAR CSelection::c_nPrvROP2; CPen* NEAR CSelection::c_pPrvPen = NULL; CBrush* NEAR CSelection::c_pPrvBrush = NULL; +#endif ///////////////////////////////////////////////////////////////////// @@ -83,7 +85,7 @@ void CHandleList::AddHandle(POINT pntNew) ///////////////////////////////////////////////////////////////////// -void CSelection::DrawTracker(CDC& pDC, TrackMode eMode) const +void CSelection::DrawTracker(wxDC& pDC, TrackMode eMode) const { if (eMode == trkSelected) DrawHandles(pDC); @@ -91,13 +93,16 @@ void CSelection::DrawTracker(CDC& pDC, TrackMode eMode) const DrawTrackingImage(pDC, eMode); } -void CSelection::DrawHandles(CDC& pDC) const +void CSelection::DrawHandles(wxDC& pDC) const { int n = GetHandleCount(); + CB::DCLogicalFunctionChanger setLogFunc(pDC, wxXOR); + wxDCPenChanger setPen(pDC, *wxWHITE_PEN); + wxDCBrushChanger setBrush(pDC, *wxWHITE_BRUSH); for (int i = 0; i < n; i++) { - CRect rect = GetHandleRect(i); - pDC.PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), DSTINVERT); + wxRect rect = CB::Convert(GetHandleRect(i)); + pDC.DrawRectangle(rect); } } @@ -118,7 +123,7 @@ void CSelection::InvalidateHandles() for (int i = 0; i < n; i++) { CRect rct = GetHandleRect(i); - m_pView->InvalidateWorkspaceRect(&rct, FALSE); + m_pView->InvalidateWorkspaceRect(CB::Convert(rct), FALSE); } } @@ -126,24 +131,24 @@ void CSelection::InvalidateHandles() CRect CSelection::GetHandleRect(int nHandleID) const { // Get the center of the handle in logical coords - CPoint point = GetHandleLoc(nHandleID); + wxPoint point = CB::Convert(GetHandleLoc(nHandleID)); // Convert point to client coords - m_pView->WorkspaceToClient(point); + point = m_pView->WorkspaceToClient(point); // Calc CRect of handle in device coords - CRect rect(point.x-3, point.y-3, point.x+3, point.y+3); + wxRect rect(wxPoint(point.x-3, point.y-3), wxSize(6, 6)); - m_pView->ClientToWorkspace(rect); + rect = m_pView->ClientToWorkspace(rect); - return rect; + return CB::Convert(rect); } void CSelection::Invalidate() { CRect rct = m_rect; rct = m_pObj->GetEnclosingRect(); - m_pView->InvalidateWorkspaceRect(&rct, FALSE); + m_pView->InvalidateWorkspaceRect(CB::Convert(rct), FALSE); } void CSelection::Open() @@ -151,25 +156,18 @@ void CSelection::Open() if (m_pObj->GetType() == CDrawObj::drawMarkObj || m_pObj->GetType() == CDrawObj::drawPieceObj) { - m_pView->SendMessage(WM_COMMAND, MAKEWPARAM(uint16_t(ID_EDIT_ELEMENT_TEXT), uint16_t(0))); + wxCommandEvent event(wxEVT_MENU, XRCID("ID_EDIT_ELEMENT_TEXT")); + m_pView->ProcessWindowEvent(event); } } //=---------------------------------------------------=// // Static methods... -void CSelection::SetupTrackingDraw(CDC& pDC) +CSelection::DCSetupTrackingDraw::DCSetupTrackingDraw(wxDC& pDC) : + setPen(pDC, c_penDot), + setBrush(pDC, *wxTRANSPARENT_BRUSH) { - c_nPrvROP2 = pDC.SetROP2(R2_XORPEN); - c_pPrvPen = pDC.SelectObject(&c_penDot); - c_pPrvBrush = (CBrush*)pDC.SelectStockObject(NULL_BRUSH); -} - -void CSelection::CleanUpTrackingDraw(CDC& pDC) -{ - pDC.SetROP2(c_nPrvROP2); - pDC.SelectObject(c_pPrvPen); - pDC.SelectObject(c_pPrvBrush); } ///////////////////////////////////////////////////////////////////// @@ -181,28 +179,32 @@ void CSelLine::AddHandles(CHandleList& listHandles) listHandles.AddHandle(GetHandleLoc(hitPtB)); } -void CSelLine::DrawTrackingImage(CDC& pDC, TrackMode eMode) const +void CSelLine::DrawTrackingImage(wxDC& pDC, TrackMode eMode) const { +#if 0 SetupTrackingDraw(pDC); pDC.MoveTo(m_rect.left, m_rect.top); pDC.LineTo(m_rect.right, m_rect.bottom); CleanUpTrackingDraw(pDC); +#else + wxASSERT(!"TODO:"); +#endif } -HCURSOR CSelLine::GetHandleCursor(int nHandleID) const +wxCursor CSelLine::GetHandleCursor(int nHandleID) const { - const CB::string::value_type* id; + wxStockCursor id; switch (nHandleID) { case hitPtA: case hitPtB: - id = IDC_CROSS; + id = wxCURSOR_CROSS; break; default: ASSERT(FALSE); - id = nullptr; + id = wxCURSOR_NONE; } - return AfxGetApp()->LoadStandardCursor(id); + return wxCursor(id); } // Returns handle location in logical coords. @@ -245,15 +247,16 @@ void CSelLine::UpdateObject(BOOL bInvalidate, CLine& pObj = static_cast(*m_pObj); if (bInvalidate) { - CRect rctA = pObj.GetEnclosingRect(); - CRect rctB; - pObj.GetLine(rctB); - rctB.NormalizeRect(); - m_pView->WorkspaceToClient(rctB); - rctB.InflateRect(handleHalfWidth, handleHalfWidth); - m_pView->ClientToWorkspace(rctB); - rctA |= rctB; // Make sure we erase the handles - m_pView->InvalidateWorkspaceRect(&rctA, FALSE); + wxRect rctA = CB::Convert(pObj.GetEnclosingRect()); + CRect rctBMfc; + pObj.GetLine(rctBMfc); + rctBMfc.NormalizeRect(); + wxRect rctB = CB::Convert(rctBMfc); + rctB = m_pView->WorkspaceToClient(rctB); + rctB.Inflate(handleHalfWidth, handleHalfWidth); + rctB = m_pView->ClientToWorkspace(rctB); + rctA.Union(rctB); // Make sure we erase the handles + m_pView->InvalidateWorkspaceRect(rctA, FALSE); } pObj.SetLine(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); if (bUpdateObjectExtent) @@ -270,7 +273,7 @@ void CSelLine::UpdateObject(BOOL bInvalidate, if (bInvalidate) { CRect rct = pObj.GetEnclosingRect(); - m_pView->InvalidateWorkspaceRect(&rct); + m_pView->InvalidateWorkspaceRect(CB::Convert(rct)); } } @@ -285,11 +288,10 @@ void CSelGeneric::AddHandles(CHandleList& listHandles) listHandles.AddHandle(GetHandleLoc(hitBottomLeft)); } -void CSelGeneric::DrawTrackingImage(CDC& pDC, TrackMode eMode) const +void CSelGeneric::DrawTrackingImage(wxDC& pDC, TrackMode eMode) const { - SetupTrackingDraw(pDC); - pDC.Rectangle(m_rect); - CleanUpTrackingDraw(pDC); + DCSetupTrackingDraw setupTrackingDraw(pDC); + pDC.DrawRectangle(CB::Convert(m_rect)); } // Returns handle location in logical coords. @@ -314,11 +316,11 @@ void CSelGeneric::UpdateObject(BOOL bInvalidate, { if (bInvalidate) { - CRect rct = m_pObj->GetRect(); - m_pView->WorkspaceToClient(rct); - rct.InflateRect(handleHalfWidth, handleHalfWidth); - m_pView->ClientToWorkspace(rct); - m_pView->InvalidateWorkspaceRect(&rct); + wxRect rct = CB::Convert(m_pObj->GetRect()); + rct = m_pView->WorkspaceToClient(rct); + rct.Inflate(handleHalfWidth, handleHalfWidth); + rct = m_pView->ClientToWorkspace(rct); + m_pView->InvalidateWorkspaceRect(rct); } if (bUpdateObjectExtent) { @@ -335,7 +337,7 @@ void CSelGeneric::UpdateObject(BOOL bInvalidate, if (bInvalidate) { CRect rct = m_pObj->GetEnclosingRect(); - m_pView->InvalidateWorkspaceRect(&rct); + m_pView->InvalidateWorkspaceRect(CB::Convert(rct)); } } @@ -475,13 +477,13 @@ void CSelList::Offset(CPoint ptDelta) // Called by view OnDraw(). This entry makes it possible // to turn off handles during a drag operation. -void CSelList::OnDraw(CDC& pDC) +void CSelList::OnDraw(wxDC& pDC) { if (m_eTrkMode == trkSelected) DrawTracker(pDC); } -void CSelList::DrawTracker(CDC& pDC, TrackMode eTrkMode) +void CSelList::DrawTracker(wxDC& pDC, TrackMode eTrkMode) { if (eTrkMode != trkCurrent) m_eTrkMode = eTrkMode; @@ -491,11 +493,16 @@ void CSelList::DrawTracker(CDC& pDC, TrackMode eTrkMode) // Drawing selection handles. Draw them using the // handle list so when an even number of identical // points don't XOR themselves out of existance. + CB::DCLogicalFunctionChanger setLogFunc(pDC, wxXOR); + wxDCPenChanger setPen(pDC, *wxWHITE_PEN); + wxDCBrushChanger setBrush(pDC, *wxWHITE_BRUSH); POSITION pos = m_listHandles.GetHeadPosition(); while (pos != NULL) { POINT pnt = m_listHandles.GetNext(pos); - pDC.PatBlt(pnt.x-3, pnt.y-3, 6, 6, DSTINVERT); + wxRect rect(wxPoint(pnt.x - 3, pnt.y - 3), + wxSize(6, 6)); + pDC.DrawRectangle(rect); } } else @@ -520,7 +527,7 @@ void CSelList::InvalidateListHandles(BOOL bUpdate) bFoundOne = TRUE; } if (bFoundOne && bUpdate) - m_pView->UpdateWindow(); + m_pView->Update(); } void CSelList::InvalidateList(BOOL bUpdate) @@ -534,7 +541,7 @@ void CSelList::InvalidateList(BOOL bUpdate) bFoundOne = TRUE; } if (bFoundOne && bUpdate) - m_pView->UpdateWindow(); + m_pView->Update(); } void CSelList::PurgeList(BOOL bInvalidate) @@ -621,7 +628,7 @@ void CSelList::LoadTableWithObjectPtrs(std::vector>& pTb // This is a bit of a cheat....Since we know the originating view and // thus the board associated with it, we can call the draw list // method the arrange the pieces in the proper visual order. - CDrawList* pDwg = m_pView->GetPlayBoard()->GetPieceList(); + CDrawList* pDwg = m_pView->GetPlayBoard().GetPieceList(); ASSERT(pDwg != NULL); if (bVisualOrder) pDwg->ArrangeObjectPtrTableInVisualOrder(pTbl); @@ -629,6 +636,14 @@ void CSelList::LoadTableWithObjectPtrs(std::vector>& pTb pDwg->ArrangeObjectPtrTableInDrawOrder(pTbl); } +void CSelList::LoadTableWithObjectPtrs(std::vector>& pTbl, ObjTypes objTypes, + BOOL bVisualOrder) +{ + std::vector> temp; + LoadTableWithObjectPtrs(temp, objTypes, bVisualOrder); + pTbl = ToRefPtr(temp); +} + BOOL CSelList::HasPieces() const { for (const_iterator pos = begin() ; pos != end() ; ++pos) @@ -642,7 +657,7 @@ BOOL CSelList::HasPieces() const BOOL CSelList::HasNonOwnedPieces() const { - const CPieceTable& pPTbl = m_pView->GetDocument()->GetPieceTable(); + const CPieceTable& pPTbl = m_pView->GetDocument().GetPieceTable(); for (const_iterator pos = begin() ; pos != end() ; ++pos) { const CSelection& pSel = **pos; @@ -658,7 +673,7 @@ BOOL CSelList::HasNonOwnedPieces() const BOOL CSelList::HasOwnedPieces() const { - const CPieceTable& pPTbl = m_pView->GetDocument()->GetPieceTable(); + const CPieceTable& pPTbl = m_pView->GetDocument().GetPieceTable(); for (const_iterator pos = begin() ; pos != end() ; ++pos) { const CSelection& pSel = **pos; @@ -674,7 +689,7 @@ BOOL CSelList::HasOwnedPieces() const BOOL CSelList::HasOwnedPiecesNotMatching(PlayerMask dwOwnerMask) const { - const CPieceTable& pPTbl = m_pView->GetDocument()->GetPieceTable(); + const CPieceTable& pPTbl = m_pView->GetDocument().GetPieceTable(); for (const_iterator pos = begin() ; pos != end() ; ++pos) { const CSelection& pSel = **pos; @@ -709,7 +724,7 @@ BOOL CSelList::HasFlippablePieces() const const CSelection& pSel = **pos; if (pSel.m_pObj->GetType() == CDrawObj::drawPieceObj) { - if (m_pView->GetDocument()->GetPieceTable().GetSides( + if (m_pView->GetDocument().GetPieceTable().GetSides( static_cast(*pSel.m_pObj).m_pid) >= size_t(2)) return TRUE; } @@ -772,7 +787,7 @@ void CSelList::LoadTableWithPieceIDs(std::vector& pTbl, BOOL bVisualOrd // This is a bit of a cheat....Since we know the originating view and // thus the board associated with it, we can call the draw list // method the arrange the pieces in the proper visual order. - CDrawList* pDwg = m_pView->GetPlayBoard()->GetPieceList(); + CDrawList* pDwg = m_pView->GetPlayBoard().GetPieceList(); ASSERT(pDwg != NULL); if (bVisualOrder) pDwg->ArrangePieceTableInVisualOrder(pTbl); @@ -783,7 +798,7 @@ void CSelList::LoadTableWithPieceIDs(std::vector& pTbl, BOOL bVisualOrd void CSelList::LoadTableWithOwnerStatePieceIDs(std::vector& pTbl, LoadFilter eWantOwned, BOOL bVisualOrder /* = TRUE */) { - CPieceTable& pPTbl = m_pView->GetDocument()->GetPieceTable(); + CPieceTable& pPTbl = m_pView->GetDocument().GetPieceTable(); pTbl.clear(); pTbl.reserve(size()); @@ -806,7 +821,7 @@ void CSelList::LoadTableWithOwnerStatePieceIDs(std::vector& pTbl, LoadF // This is a bit of a cheat....Since we know the originating view and // thus the board associated with it, we can call the draw list // method the arrange the pieces in the proper visual order. - CDrawList* pDwg = m_pView->GetPlayBoard()->GetPieceList(); + CDrawList* pDwg = m_pView->GetPlayBoard().GetPieceList(); ASSERT(pDwg != NULL); if (bVisualOrder) pDwg->ArrangePieceTableInVisualOrder(pTbl); diff --git a/GP/SelOPlay.h b/GP/SelOPlay.h index a642614d..f92584a6 100644 --- a/GP/SelOPlay.h +++ b/GP/SelOPlay.h @@ -1,7 +1,7 @@ // SelOPlay.h -- contains class definitions for selection proxies. Used // in concert with the selection tool. // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -84,8 +84,8 @@ class CSelection RefPtr m_pObj; // Associated object that is selected CRect m_rect; // Enclosing rect for selected object - virtual HCURSOR GetHandleCursor(int nHandle) const /* override */ - { return AfxGetApp()->LoadStandardCursor(IDC_ARROW); } + virtual wxCursor GetHandleCursor(int nHandle) const /* override */ + { return wxCursor(wxCURSOR_ARROW); } virtual CRect GetRect() const /* override */ { return m_rect; } // Operations @@ -95,7 +95,7 @@ class CSelection virtual void MoveHandle(int m_nHandle, CPoint point) /* override */ {} virtual void Offset(CPoint ptDelta) /* override */ { m_rect += ptDelta; } // ------- // - virtual void DrawTracker(CDC& pDC, TrackMode eMode) const /* override */; + virtual void DrawTracker(wxDC& pDC, TrackMode eMode) const /* override */; virtual void InvalidateHandles() /* override */; virtual void Invalidate() /* override */; virtual void UpdateObject(BOOL bInvalidate = TRUE, @@ -109,20 +109,28 @@ class CSelection virtual CRect GetHandleRect(int nHandleID) const /* override */; virtual CPoint GetHandleLoc(int nHandleID) const /* override */ = 0; virtual int GetHandleCount() const /* override */ = 0; - virtual void DrawHandles(CDC& pDC) const /* override */; - virtual void DrawTrackingImage(CDC& pDC, TrackMode eMode) const /* override */ = 0; + virtual void DrawHandles(wxDC& pDC) const /* override */; + virtual void DrawTrackingImage(wxDC& pDC, TrackMode eMode) const /* override */ = 0; // Implementation protected: RefPtr m_pView; // Selection's view // -- Class level support methods -- // - static void SetupTrackingDraw(CDC& pDC); - static void CleanUpTrackingDraw(CDC& pDC); + class DCSetupTrackingDraw + { + public: + DCSetupTrackingDraw(wxDC& pDC); + private: + wxDCPenChanger setPen; + wxDCBrushChanger setBrush; + }; // -- Class variables -- // - static CPen NEAR c_penDot; + static const wxPen c_penDot; +#if 0 static int NEAR c_nPrvROP2; static CPen* NEAR c_pPrvPen; static CBrush* NEAR c_pPrvBrush; +#endif }; ///////////////////////////////////////////////////////////////////// @@ -141,12 +149,12 @@ class CSelLine : public CSelection // Overrides public: - virtual HCURSOR GetHandleCursor(int nHandleID) const override; + wxCursor GetHandleCursor(int nHandleID) const override; virtual void MoveHandle(int m_nHandle, CPoint point) override; protected: virtual void AddHandles(CHandleList& listHandles) override; - virtual void DrawTrackingImage(CDC& pDC, TrackMode eMode) const override; + virtual void DrawTrackingImage(wxDC& pDC, TrackMode eMode) const override; virtual CPoint GetHandleLoc(int nHandleID) const override; virtual int GetHandleCount() const override { return 2; } virtual void UpdateObject(BOOL bInvalidate = TRUE, @@ -167,13 +175,13 @@ class CSelGeneric : public CSelection // Overrides public: - virtual HCURSOR GetHandleCursor(int nHandleID) const override - { return AfxGetApp()->LoadStandardCursor(IDC_ARROW); } + wxCursor GetHandleCursor(int nHandleID) const override + { return wxCursor(wxCURSOR_ARROW); } virtual void MoveHandle(int m_nHandle, CPoint point) override {} protected: virtual void AddHandles(CHandleList& listHandles) override; - virtual void DrawTrackingImage(CDC& pDC, TrackMode eMode) const override; + virtual void DrawTrackingImage(wxDC& pDC, TrackMode eMode) const override; virtual CPoint GetHandleLoc(int nHandleID) const override; virtual int GetHandleCount() const override { return 4; } virtual void UpdateObject(BOOL bInvalidate = TRUE, @@ -239,6 +247,8 @@ class CSelList : private std::list> enum ObjTypes { otInvalid, otPieces, otPiecesMarks, otAll }; void LoadTableWithObjectPtrs(std::vector>& pTbl, ObjTypes objTypes, BOOL bVisualOrder); + void LoadTableWithObjectPtrs(std::vector>& pTbl, ObjTypes objTypes, + BOOL bVisualOrder); void LoadTableWithPieceIDs(std::vector& pTbl, BOOL bVisualOrder = TRUE); // -------- // enum LoadFilter { LF_NOTOWNED, LF_OWNED, LF_BOTH }; @@ -256,8 +266,8 @@ class CSelList : private std::list> void Offset(CPoint ptDelta); void MoveHandle(int m_nHandle, CPoint point); // -------- // - void OnDraw(CDC& pDC); // Called by view OnDraw() - void DrawTracker(CDC& pDC, TrackMode eTrkMode = trkCurrent); + void OnDraw(wxDC& pDC); // Called by view OnDraw() + void DrawTracker(wxDC& pDC, TrackMode eTrkMode = trkCurrent); // -------- // void UpdateObjects(BOOL bInvalidate = TRUE, BOOL bUpdateObjectExtent = TRUE ); diff --git a/GP/ToolPlay.cpp b/GP/ToolPlay.cpp index cab40fac..96dae2f9 100644 --- a/GP/ToolPlay.cpp +++ b/GP/ToolPlay.cpp @@ -1,6 +1,6 @@ // ToolPlay.cpp // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -42,17 +42,13 @@ static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif -///////////////////////////////////////////////////////////////// - -const int scrollZone = 16; // From INI? - ///////////////////////////////////////////////////////////////// // Class variables std::vector CPlayTool::c_toolLib; // Tool library -CPoint CPlayTool::c_ptDown; // Mouse down location -CPoint CPlayTool::c_ptLast; // Last mouse location +wxPoint CPlayTool::c_ptDown; // Mouse down location +wxPoint CPlayTool::c_ptLast; // Last mouse location // The playing board tool objects... @@ -82,54 +78,59 @@ CPlayTool& CPlayTool::GetTool(PToolType eToolType) return retval; } -void CPlayTool::OnLButtonDown(CPlayBoardView* pView, UINT nFlags, CPoint point) +void CPlayTool::OnLButtonDown(CPlayBoardView& pView, int /*nMods*/, wxPoint point) { - pView->SetCapture(); + pView.CaptureMouse(); c_ptDown = point; c_ptLast = point; } -void CPlayTool::OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point) +void CPlayTool::OnMouseMove(CPlayBoardView& pView, int /*nMods*/, wxPoint point) { - if (CWnd::GetCapture() == pView) + if (pView.HasCapture()) c_ptLast = point; - SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); + pView.SetCursor(wxCursor(wxCURSOR_ARROW)); } -bool CPlayTool::OnLButtonUp(CPlayBoardView* pView, UINT, CPoint point) +bool CPlayTool::OnLButtonUp(CPlayBoardView& pView, int /*nMods*/, wxPoint /*point*/) { - if (CWnd::GetCapture() != pView) + if (!pView.HasCapture()) return false; - ReleaseCapture(); + pView.ReleaseMouse(); return true; } +void CPlayTool::OnMouseCaptureLost(CPlayBoardView& pView) +{ + // mouse already released +} + //////////////////////////////////////////////////////////////////////// // CPSelectTool - Object Selection/Manipulation tool -void CPSelectTool::OnLButtonDown(CPlayBoardView* pView, UINT nFlags, - CPoint point) +void CPSelectTool::OnLButtonDown(CPlayBoardView& pView, int nMods, + wxPoint point) { - CSelList* pSLst = pView->GetSelectList(); - CPlayBoard *pPBoard = pView->GetPlayBoard(); + CSelList& pSLst = pView.GetSelectList(); + CPlayBoard& pPBoard = pView.GetPlayBoard(); // If a a handle is clicked on, immediately start tracking the // resize. - if ((m_nHandleID = pSLst->HitTestHandles(point)) >= 0) + if ((m_nHandleID = pSLst.HitTestHandles(CB::Convert(point))) >= 0) { - StartSizingOperation(pView, nFlags, point); + StartSizingOperation(pView, nMods, point); return; } - CDrawObj* pObj = pView->ObjectHitTest(point); + CDrawObj* pObj = pView.ObjectHitTest(point); BOOL bOwnedButNotOkToSelect = FALSE; if (pObj != NULL && pObj->GetType() == CDrawObj::drawPieceObj) { CPieceObj* pPObj = (CPieceObj*)pObj; - PlayerMask dwCurrentPlayer = pView->GetDocument()->GetCurrentPlayerMask(); - bOwnedButNotOkToSelect = !pView->GetDocument()->IsScenario() && - !pPBoard->IsNonOwnerAccessAllowed() && + PlayerMask dwCurrentPlayer = pView.GetDocument().GetCurrentPlayerMask(); + bOwnedButNotOkToSelect = !pView.GetDocument().IsScenario() && + !pPBoard.IsNonOwnerAccessAllowed() && pPObj->IsOwned() && !pPObj->IsOwnedBy(dwCurrentPlayer); } @@ -138,103 +139,77 @@ void CPSelectTool::OnLButtonDown(CPlayBoardView* pView, UINT nFlags, // than the current player. if (pObj == NULL || bOwnedButNotOkToSelect || - (pPBoard->GetLocksEnforced() && (pObj->GetDObjFlags() & dobjFlgLockDown))) + (pPBoard.GetLocksEnforced() && (pObj->GetDObjFlags() & dobjFlgLockDown))) { - if ((nFlags & MK_SHIFT) == 0) // Shift click adds to list - pSLst->PurgeList(TRUE); // Clear current select list + if ((nMods & wxMOD_SHIFT) == 0) // Shift click adds to list + pSLst.PurgeList(TRUE); // Clear current select list // No objects were under the mouse click. m_eSelMode = smodeNet; // Net type selection - CPlayTool::OnLButtonDown(pView, nFlags, point); - CClientDC dc(pView); - pView->OnPrepareScaledDC(dc, TRUE); - DrawNetRect(&dc, pView); + CPlayTool::OnLButtonDown(pView, nMods, point); + wxOverlayDC dc(pView.GetOverlay(), &pView); + pView.OnPrepareScaledDC(dc, true); + dc.Clear(); + DrawNetRect(dc, pView); return; } // Object is under mouse. See if also selected. If not, // add to list. - if (!pSLst->IsObjectSelected(*pObj)) + if (!pSLst.IsObjectSelected(*pObj)) { - if ((nFlags & MK_SHIFT) == 0) // Shift click adds to list - pSLst->PurgeList(TRUE); // Clear current select list - if ((nFlags & MK_CONTROL) != 0) // Control click drills down - pView->SelectAllUnderPoint(point); + if ((nMods & wxMOD_SHIFT) == 0) // Shift click adds to list + pSLst.PurgeList(TRUE); // Clear current select list + if ((nMods & wxMOD_CONTROL) != 0) // Control click drills down + pView.SelectAllUnderPoint(point); else { - pSLst->AddObject(*pObj, TRUE); + pSLst.AddObject(*pObj, TRUE); if (pObj->GetType() == CDrawObj::drawPieceObj || pObj->GetType() == CDrawObj::drawMarkObj) - pView->NotifySelectListChange(); + pView.NotifySelectListChange(); } - CPlayTool::OnLButtonDown(pView, nFlags, point); + CPlayTool::OnLButtonDown(pView, nMods, point); StartDragTimer(pView); - CRect rct = pSLst->GetEnclosingRect(); - CSize sizeOff = point - rct.TopLeft(); - pSLst->SetMouseOffset(sizeOff); + wxRect rct = CB::Convert(pSLst.GetEnclosingRect()); + wxPoint sizeOff = point - rct.GetTopLeft(); + pSLst.SetMouseOffset(CSize(sizeOff.x, sizeOff.y)); return; } // At this point we know s/he clicked on an object that was // already selected. If SHIFT is held we'll remove it from // the list. Otherwise, a timer is started and drag tracking // wont start until it expires. - if ((nFlags & MK_SHIFT) != 0) + if ((nMods & wxMOD_SHIFT) != 0) { - pSLst->RemoveObject(*pObj, TRUE); + pSLst.RemoveObject(*pObj, TRUE); return; } - CPlayTool::OnLButtonDown(pView, nFlags, point); + CPlayTool::OnLButtonDown(pView, nMods, point); - pSLst->SetSnapReferenceObject(pObj); - CRect rct = pSLst->GetSnapReferenceRect(); - CSize sizeOff = point - rct.TopLeft(); - pSLst->SetMouseOffset(sizeOff); + pSLst.SetSnapReferenceObject(pObj); + wxRect rct = CB::Convert(pSLst.GetSnapReferenceRect()); + wxPoint sizeOff = point - rct.GetTopLeft(); + pSLst.SetMouseOffset(CSize(sizeOff.x, sizeOff.y)); StartDragTimer(pView); } -void CPSelectTool::OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point) +void CPSelectTool::OnMouseMove(CPlayBoardView& pView, int nMods, wxPoint point) { - CSelList* pSLst = pView->GetSelectList(); + CSelList& pSLst = pView.GetSelectList(); - if (CWnd::GetCapture() != pView) + if (!pView.HasCapture()) return; - if (m_eSelMode != smodeNormal && m_eSelMode != smodeMove) - { - // Autoscroll initiate possibility processing (sounds like a - // scifi flic). Autoscroll is enabled when the mouse is captured - // and the mouse is outside of the client area. - CRect rct; - CPoint pt; - GetCursorPos(&pt); - pView->ScreenToClient(&pt); - pView->GetClientRect(&rct); - if (rct.PtInRect(pt)) // In client area - { - rct.InflateRect(-scrollZone, -scrollZone); - rct.NormalizeRect(); // Just in case client is too small - if (!rct.PtInRect(pt)) - { - // It's in the scroll zone - if (m_nTimerID == uintptr_t(0)) // Only start if not scrolling - StartScrollTimer(pView); - } - else - KillScrollTimer(pView); - } - else - KillScrollTimer(pView); - } - // If we get here, the mouse has been captured. Check if // we are doing a "net select". if (m_eSelMode == smodeNet) { - CClientDC dc(pView); - pView->OnPrepareScaledDC(dc, TRUE); - DrawNetRect(&dc, pView); // Erase previous position - CPlayTool::OnMouseMove(pView, nFlags, point); // Update position - DrawNetRect(&dc, pView); // Draw new position rect + wxOverlayDC dc(pView.GetOverlay(), &pView); + pView.OnPrepareScaledDC(dc, true); + dc.Clear(); + CPlayTool::OnMouseMove(pView, nMods, point); // Update position + DrawNetRect(dc, pView); // Draw new position rect return; } // If object(s) are being moved or sized, removed last tracking @@ -242,63 +217,60 @@ void CPSelectTool::OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point) // tracking image. if (m_eSelMode == smodeMove) { - pView->WorkspaceToClient(point); + point = pView.WorkspaceToClient(point); DoDragDrop(pView, point); return; } else if (m_eSelMode == smodeSizing) { - pView->AdjustPoint(point); + point = pView.AdjustPoint(point); if (point == c_ptLast) return; - CClientDC dc(pView); - pView->OnPrepareScaledDC(dc, TRUE); - - pSLst->DrawTracker(dc, trkSizing); // Erase previous tracker + wxOverlayDC dc(pView.GetOverlay(), &pView); + pView.OnPrepareScaledDC(dc, true); + dc.Clear(); MoveSelections(pSLst, point); - pSLst->DrawTracker(dc, trkSizing); // Erase previous tracker + pSLst.DrawTracker(dc, trkSizing); // Draw tracker } c_ptLast = point; // Save new 'last' position } -bool CPSelectTool::OnLButtonUp(CPlayBoardView* pView, UINT nFlags, CPoint point) +bool CPSelectTool::OnLButtonUp(CPlayBoardView& pView, int nMods, wxPoint point) { bool retval = true; - if (CWnd::GetCapture() == pView) + if (pView.HasCapture()) { if (m_eSelMode == smodeNet) { - CClientDC dc(pView); - pView->OnPrepareScaledDC(dc, TRUE); - DrawNetRect(&dc, pView); // Erase previous position + pView.GetOverlay().Reset(); // If the control key is down when button was released, fields // that intersect the select rect will selected. Otherwise only // those fields that are entirely within the select rect // will be selected. - CRect rect(c_ptDown.x, c_ptDown.y, c_ptLast.x, c_ptLast.y); - rect.NormalizeRect(); - pView->SelectWithinRect(rect, (nFlags & MK_CONTROL) != 0); - CSelList* pSLst = pView->GetSelectList(); - pSLst->InvalidateListHandles(); + wxRect rect(wxPoint(std::min(c_ptDown.x, c_ptLast.x), std::min(c_ptDown.y, c_ptLast.y)), + wxSize(std::abs(c_ptLast.x - c_ptDown.x), std::abs(c_ptLast.y - c_ptDown.y))); + pView.SelectWithinRect(rect, (nMods & wxMOD_CONTROL) != 0); + CSelList& pSLst = pView.GetSelectList(); + pSLst.InvalidateListHandles(); } else if (m_eSelMode != smodeNormal) { - CSelList* pSLst = pView->GetSelectList(); + CSelList& pSLst = pView.GetSelectList(); if (m_eSelMode == smodeMove) { - CPoint pnt = point; - pSLst->SetTrackingMode(trkSelected); - pView->WorkspaceToClient(pnt); + wxPoint pnt = point; + pSLst.SetTrackingMode(trkSelected); + pnt = pView.WorkspaceToClient(pnt); retval = DoDragDropEnd(pView, pnt) && retval; } else { - pSLst->SetTrackingMode(trkSelected); - pSLst->UpdateObjects(TRUE); - pSLst->InvalidateListHandles(); + pSLst.SetTrackingMode(trkSelected); + pSLst.UpdateObjects(TRUE); + pSLst.InvalidateListHandles(); } } } @@ -308,22 +280,31 @@ bool CPSelectTool::OnLButtonUp(CPlayBoardView* pView, UINT nFlags, CPoint point) } m_eSelMode = smodeNormal; KillDragTimer(pView); // Make sure timers are released - KillScrollTimer(pView); - return CPlayTool::OnLButtonUp(pView, nFlags, point) && retval; + return CPlayTool::OnLButtonUp(pView, nMods, point) && retval; } -void CPSelectTool::OnTimer(CPlayBoardView* pView, uintptr_t nIDEvent) +void CPSelectTool::OnMouseCaptureLost(CPlayBoardView& pView) { - if (CWnd::GetCapture() != pView) + pView.GetOverlay().Reset(); + pView.SetCursor(wxCursor(wxCURSOR_ARROW)); + m_eSelMode = smodeNormal; + KillDragTimer(pView); // Make sure timers are released + CPlayTool::OnMouseCaptureLost(pView); +} + +void CPSelectTool::OnTimer(CPlayBoardView& pView, int nIDEvent) +{ + wxASSERT(nIDEvent == XRCID("timerIDSelectDelay") && + nIDEvent == m_nTimerID); + if (!pView.HasCapture()) { m_eSelMode = smodeNormal; KillDragTimer(pView); - KillScrollTimer(pView); return; } if (m_eSelMode == smodeNormal) { - CSelList* pSLst = pView->GetSelectList(); + CSelList& pSLst = pView.GetSelectList(); // Mouse is captured and no particular drag operation // is underway. Therefore we want a move that draws @@ -331,443 +312,340 @@ void CPSelectTool::OnTimer(CPlayBoardView* pView, uintptr_t nIDEvent) m_eSelMode = smodeMove; KillDragTimer(pView); - CClientDC dc(pView); - pView->OnPrepareScaledDC(dc, TRUE); - pSLst->DrawTracker(dc, trkSelected); // Turn off handles + wxOverlayDC dc(pView.GetOverlay(), &pView); + pView.OnPrepareScaledDC(dc); + dc.Clear(); - CPoint point; - GetCursorPos(&point); - pView->ScreenToClient(&point); - pView->ClientToWorkspace(point); + wxPoint point = wxGetMouseState().GetPosition(); + point = pView.ScreenToClient(point); + point = pView.ClientToWorkspace(point); - pSLst->SetTrackingMode(trkMoving); + pSLst.SetTrackingMode(trkMoving); DoDragDropStart(pView); - pView->WorkspaceToClient(point); + point = pView.WorkspaceToClient(point); DoDragDrop(pView, point); } - else if (m_eSelMode != smodeMove) - { - if (!ProcessAutoScroll(pView)) - KillScrollTimer(pView); - } } -void CPSelectTool::OnLButtonDblClk(CPlayBoardView* pView, UINT nFlags, - CPoint point) +void CPSelectTool::OnLButtonDblClk(CPlayBoardView& pView, int nMods, + wxPoint point) { // Normal DblClk opens some property view of the selected // object. Only recognized if only one selection is active. - CPlayTool::OnLButtonDblClk(pView, nFlags, point); - pView->GetSelectList()->Open(); + CPlayTool::OnLButtonDblClk(pView, nMods, point); + pView.GetSelectList().Open(); } -BOOL CPSelectTool::OnSetCursor(CPlayBoardView* pView, UINT nHitTest) +wxCursor CPSelectTool::OnSetCursor(const CPlayBoardView& pView, const wxPoint& point) const { - // Process only within the client area - if (nHitTest != HTCLIENT) - return FALSE; - - // Convert cursor position to document coordinates - CPoint point; - GetCursorPos(&point); - pView->ScreenToClient(&point); - pView->ClientToWorkspace(point); - // Check for movement through handle areas. Set the // cursor to the appropriate shape. - CSelList* pSLst = pView->GetSelectList(); - if (pSLst->IsSingleSelect()) + const CSelList& pSLst = pView.GetSelectList(); + if (pSLst.IsSingleSelect()) { // Check if cursor is over a handle. If it is, // get handle cursor. - CSelection& pSelObj = *pSLst->front(); - int nHandle = pSelObj.HitTestHandles(point); + const CSelection& pSelObj = *pSLst.front(); + int nHandle = pSelObj.HitTestHandles(CB::Convert(point)); if (nHandle >= 0) { - SetCursor(pSelObj.GetHandleCursor(nHandle)); - return TRUE; + return pSelObj.GetHandleCursor(nHandle); } } - return FALSE; // Show default cursor + return wxCursor(); // Show default cursor } -void CPSelectTool::StartSizingOperation(CPlayBoardView* pView, UINT nFlags, - CPoint point, int nHandleID) +void CPSelectTool::StartSizingOperation(CPlayBoardView& pView, int nMods, + const wxPoint& point, int nHandleID) { - CSelList* pSLst = pView->GetSelectList(); + CSelList& pSLst = pView.GetSelectList(); if (nHandleID != -1) m_nHandleID = nHandleID; m_eSelMode = smodeSizing; - CPlayTool::OnLButtonDown(pView, nFlags, point); - CClientDC dc(pView); - pView->OnPrepareScaledDC(dc, TRUE); - pSLst->DrawTracker(dc, trkSizing); + CPlayTool::OnLButtonDown(pView, nMods, point); + wxOverlayDC dc(pView.GetOverlay(), &pView); + pView.OnPrepareScaledDC(dc, true); + dc.Clear(); + pSLst.DrawTracker(dc, trkSizing); } -void CPSelectTool::DrawSelectionRect(CDC* pDC, CRect* pRct) +void CPSelectTool::DrawSelectionRect(wxDC& pDC, const wxRect& pRct) const { - CPen pen; - pen.CreateStockObject(WHITE_PEN); - CPen* pPrvPen = pDC->SelectObject(&pen); - int nPrvROP2 = pDC->SetROP2(R2_XORPEN); - - pDC->MoveTo(pRct->TopLeft()); - pDC->LineTo(pRct->right, pRct->top); - pDC->LineTo(pRct->BottomRight()); - pDC->LineTo(pRct->left, pRct->bottom); - pDC->LineTo(pRct->TopLeft()); + wxDCPenChanger setPen(pDC, *wxLIGHT_GREY); + wxDCBrushChanger setBrush(pDC, *wxTRANSPARENT_BRUSH); - pDC->SetROP2(nPrvROP2); - pDC->SelectObject(pPrvPen); + pDC.DrawRectangle(pRct); } -void CPSelectTool::DrawNetRect(CDC* pDC, CPlayBoardView* pView) +void CPSelectTool::DrawNetRect(wxDC& pDC, const CPlayBoardView& /*pView*/) const { - CRect rect(c_ptDown.x, c_ptDown.y, c_ptLast.x, c_ptLast.y); - rect.NormalizeRect(); - DrawSelectionRect(pDC, &rect); + wxRect rect(wxPoint(std::min(c_ptDown.x, c_ptLast.x), std::min(c_ptDown.y, c_ptLast.y)), + wxSize(std::abs(c_ptLast.x - c_ptDown.x), std::abs(c_ptLast.y - c_ptDown.y))); + DrawSelectionRect(pDC, rect); } -BOOL CPSelectTool::ProcessAutoScroll(CPlayBoardView* pView) -{ - CPoint point; - CRect rectClient; - CRect rect; - - GetCursorPos(&point); - pView->ScreenToClient(&point); - pView->GetClientRect(&rectClient); - rect = rectClient; - rect.InflateRect(-scrollZone, -scrollZone); - rect.NormalizeRect(); - - UINT nScrollID = MAKEWORD(-1, -1); - if (rectClient.PtInRect(point) && !rect.PtInRect(point)) - { - // Mouse is in the scroll zone.... - // Determine which way to scroll along both X & Y axis - if (point.x < rect.left) - nScrollID = MAKEWORD(SB_LINEUP, HIBYTE(nScrollID)); - else if (point.x >= rect.right) - nScrollID = MAKEWORD(SB_LINEDOWN, HIBYTE(nScrollID)); - if (point.y < rect.top) - nScrollID = MAKEWORD(LOBYTE(nScrollID), SB_LINEUP); - else if (point.y >= rect.bottom) - nScrollID = MAKEWORD(LOBYTE(nScrollID), SB_LINEDOWN); - ASSERT(nScrollID != MAKEWORD(-1, -1)); - // First check if scroll can happen. - BOOL bValidScroll = pView->OnScroll(nScrollID, 0, FALSE); - if (bValidScroll) - { - CSelList* pSLst = pView->GetSelectList(); - pView->ClientToWorkspace(point); - - CClientDC dc(pView); - pView->OnPrepareScaledDC(dc, TRUE); - - if (m_eSelMode == smodeNet) - { - // Erase previous position - CRect rect(c_ptDown.x, c_ptDown.y, c_ptLast.x, c_ptLast.y); - rect.NormalizeRect(); - DrawSelectionRect(&dc, &rect); - } - else - pSLst->DrawTracker(dc); // Turn off tracker - - pView->OnScroll(nScrollID, 0, TRUE); - pView->UpdateWindow(); // Redraw image content. - - AdjustPoint(pView, point); - - MoveSelections(pSLst, point); // Offset the tracking data - c_ptLast = point; // Save new 'last' position - - pView->OnPrepareScaledDC(dc, TRUE); - if (m_eSelMode == smodeNet) - { - GetCursorPos(&point); - pView->ScreenToClient(&point); - pView->ClientToWorkspace(point); - c_ptLast = point; // Set new 'last' position - // Draw updated net rect - CRect rect(c_ptDown.x, c_ptDown.y, c_ptLast.x, c_ptLast.y); - rect.NormalizeRect(); - DrawSelectionRect(&dc, &rect); - } - else - { - MoveSelections(pSLst, point);// Offset the tracking data - c_ptLast = point; // Save new 'last' position - pSLst->DrawTracker(dc); // Turn off tracker - } - return TRUE; - } - } - return FALSE; -} - -void CPSelectTool::MoveSelections(CSelList *pSLst, CPoint point) +void CPSelectTool::MoveSelections(CSelList &pSLst, const wxPoint& point) { if (m_eSelMode == smodeMove) { - CPoint ptDelta = (CPoint)(point - c_ptLast); - pSLst->Offset(ptDelta); + wxPoint ptDelta = point - c_ptLast; + pSLst.Offset(CB::Convert(ptDelta)); } else - pSLst->MoveHandle(m_nHandleID, point); + pSLst.MoveHandle(m_nHandleID, CB::Convert(point)); } -BOOL CPSelectTool::AdjustPoint(CPlayBoardView* pView, CPoint& point) +wxPoint CPSelectTool::AdjustPoint(const CPlayBoardView& pView, wxPoint point) const { - pView->AdjustPoint(point); + point = pView.AdjustPoint(point); if (point == c_ptLast) - return FALSE; + return point; if (m_eSelMode == smodeMove) { - CRect rct = pView->GetSelectList()->GetEnclosingRect(); - CPoint pnt = pView->GetWorkspaceDim(); - if (rct.left + point.x - c_ptLast.x < 0) // Clamp - point.x = c_ptLast.x - rct.left; - if (rct.top + point.y - c_ptLast.y < 0) // Clamp - point.y = c_ptLast.y - rct.top; - if (rct.right + point.x - c_ptLast.x > pnt.x) // Clamp - point.x = pnt.x - (rct.right - c_ptLast.x); - if (rct.bottom + point.y - c_ptLast.y > pnt.y) // Clamp - point.y = pnt.y - (rct.bottom - c_ptLast.y); + wxRect rct = CB::Convert(pView.GetSelectList().GetEnclosingRect()); + wxPoint pnt = pView.GetWorkspaceDim(); + if (rct.GetLeft() + point.x - c_ptLast.x < 0) // Clamp + point.x = c_ptLast.x - rct.GetLeft(); + if (rct.GetTop() + point.y - c_ptLast.y < 0) // Clamp + point.y = c_ptLast.y - rct.GetTop(); + if (rct.GetRight() + point.x - c_ptLast.x > pnt.x) // Clamp + point.x = pnt.x - (rct.GetRight() - c_ptLast.x); + if (rct.GetBottom() + point.y - c_ptLast.y > pnt.y) // Clamp + point.y = pnt.y - (rct.GetBottom() - c_ptLast.y); } - return TRUE; + return point; } -void CPSelectTool::StartDragTimer(CPlayBoardView* pView) +void CPSelectTool::StartDragTimer(CPlayBoardView& pView) { - m_nTimerID = pView->SetTimer(timerIDSelectDelay, - timerSelDelay, NULL); + pView.SetTimer(XRCID("timerIDSelectDelay"), + timerSelDelay); + m_nTimerID = XRCID("timerIDSelectDelay"); } -void CPSelectTool::KillDragTimer(CPlayBoardView* pView) +void CPSelectTool::KillDragTimer(CPlayBoardView& pView) { - if (m_nTimerID != uintptr_t(0)) + if (m_nTimerID != static_cast(wxID_NONE)) { - pView->KillTimer(m_nTimerID); - m_nTimerID = uintptr_t(0); - } -} - -void CPSelectTool::StartScrollTimer(CPlayBoardView* pView) -{ - m_nTimerID = pView->SetTimer(timerIDAutoScroll, timerAutoScroll, NULL); -} - -void CPSelectTool::KillScrollTimer(CPlayBoardView* pView) -{ - if (m_nTimerID != uintptr_t(0)) - { - pView->KillTimer(m_nTimerID); - m_nTimerID = uintptr_t(0); + pView.KillTimer(m_nTimerID); + m_nTimerID = static_cast(wxID_NONE); } } //////////////////////////////////////////////////////////////////////// // Note: The CSelList should have had the mouse offset value set at // this time. -void CPSelectTool::DoDragDropStart(CPlayBoardView* pView) +void CPSelectTool::DoDragDropStart(CPlayBoardView& pView) { m_di.SetDragType(DRAG_SELECTLIST); - m_di.GetSubInfo().m_selectList = pView->GetSelectList(); - m_di.GetSubInfo().m_gamDoc = pView->GetDocument(); - m_di.m_hcsrSuggest = g_res.hcrDragTile; + m_di.GetSubInfo().m_selectList = &pView.GetSelectList(); + m_di.GetSubInfo().m_gamDoc = &pView.GetDocument(); + m_di.m_hcsrSuggest = g_res.hcrDragTileWx; m_hLastWnd = NULL; } -void CPSelectTool::DoDragDrop(CPlayBoardView* pView, CPoint pntClient) +void CPSelectTool::DoDragDrop(CPlayBoardView& pView, const wxPoint& pntClient) { - CPoint pnt = pntClient; - pView->ClientToScreen(&pnt); - CWnd* pWnd = GetWindowFromPoint(pnt); + wxPoint pnt = pntClient; + pnt = pView.ClientToScreen(pnt); + wxWindow* pWnd = wxFindWindowAtPoint(pnt); - HWND hWnd = pWnd ? pWnd->m_hWnd : NULL; // Get actual window handle - if (hWnd != m_hLastWnd) + if (pWnd != m_hLastWnd) { if (m_hLastWnd != NULL) { // Signal previous window we are leaving them - CWnd* pLstWnd = CWnd::FromHandle(m_hLastWnd); + wxWindow& pLstWnd = CheckedDeref(m_hLastWnd); m_di.m_phase = PhaseDrag::Exit; - pLstWnd->SendMessage(WM_DRAGDROP, GetProcessId(GetCurrentProcess()), - (LPARAM)(LPVOID)&m_di); + DragDropEvent dragDropEvent(wxGetProcessId(), m_di); + pLstWnd.ProcessWindowEvent(dragDropEvent); } // Signal new window we have entered it. if (pWnd != NULL) { m_di.m_phase = PhaseDrag::Enter; - pWnd->SendMessage(WM_DRAGDROP, GetProcessId(GetCurrentProcess()), - (LPARAM)(LPVOID)&m_di); + DragDropEvent dragDropEvent(wxGetProcessId(), m_di); + pWnd->ProcessWindowEvent(dragDropEvent); } } - HCURSOR hCursor = NULL; - if (hWnd != NULL) + wxCursor hCursor; + if (pWnd != NULL) { m_di.m_point = pntClient; - pView->ClientToScreen(&m_di.m_point); // Move point into new coord system - pWnd->ScreenToClient(&m_di.m_point); + m_di.m_point = pView.ClientToScreen(m_di.m_point); // Move point into new coord system + m_di.m_point = pWnd->ScreenToClient(m_di.m_point); m_di.m_phase = PhaseDrag::Over; - hCursor = (HCURSOR)pWnd->SendMessage(WM_DRAGDROP, GetProcessId(GetCurrentProcess()), - (LPARAM)(LPVOID)&m_di); + DragDropEvent dragDropEvent(wxGetProcessId(), m_di); + pWnd->ProcessWindowEvent(dragDropEvent); + hCursor = dragDropEvent.GetCursor(); } - m_hLastWnd = hWnd; + m_hLastWnd = pWnd; - if (hCursor) - SetCursor(hCursor); + wxWindow& capture = CheckedDeref(wxWindow::GetCapture()); + if (hCursor.IsOk()) + { + wxASSERT(&capture == &pView); + capture.SetCursor(hCursor); + } else - SetCursor(g_res.hcrNoDrop); + { + wxASSERT(&capture == &pView); + capture.SetCursor(g_res.hcrNoDropWx); + } } -bool CPSelectTool::DoDragDropEnd(CPlayBoardView* pView, CPoint pntClient) +bool CPSelectTool::DoDragDropEnd(CPlayBoardView& pView, const wxPoint& pntClient) { - SetCursor(LoadCursor(NULL, IDC_ARROW)); + pView.SetCursor(wxCursor(wxCURSOR_ARROW)); - CPoint pnt = pntClient; - pView->ClientToScreen(&pnt); - CWnd* pWnd = GetWindowFromPoint(pnt); + wxPoint pnt = pntClient; + pnt = pView.ClientToScreen(pnt); + wxWindow* pWnd = wxFindWindowAtPoint(pnt); if (pWnd == NULL) return false; + if (pWnd != &pView) + { + pWnd->SetCursor(wxCursor(wxCURSOR_ARROW)); + } m_di.m_point = pntClient; - pView->ClientToScreen(&m_di.m_point); - pWnd->ScreenToClient(&m_di.m_point); + m_di.m_point = pView.ClientToScreen(m_di.m_point); + m_di.m_point = pWnd->ScreenToClient(m_di.m_point); m_di.m_phase = PhaseDrag::Drop; - return pWnd->SendMessage(WM_DRAGDROP, GetProcessId(GetCurrentProcess()), (LPARAM)(LPVOID)&m_di) == 1; + DragDropEvent dragDropEvent(wxGetProcessId(), m_di); + pWnd->ProcessWindowEvent(dragDropEvent); + return dragDropEvent.GetResult() && + *dragDropEvent.GetResult(); } //////////////////////////////////////////////////////////////////////// // CPShapeTool - tool used to create rectangles. -void CPShapeTool::OnLButtonDown(CPlayBoardView* pView, UINT nFlags, CPoint point) +void CPShapeTool::OnLButtonDown(CPlayBoardView& pView, int nMods, wxPoint point) { - CSelList* pSLst = pView->GetSelectList(); - pSLst->PurgeList(TRUE); // Clear current select list + wxASSERT(!"dead code"); + CSelList& pSLst = pView.GetSelectList(); + pSLst.PurgeList(TRUE); // Clear current select list int nDragHandle; - pView->AdjustPoint(point); + point = pView.AdjustPoint(point); m_pObj = CreateDrawObj(pView, point, nDragHandle); - pSLst->AddObject(*m_pObj, TRUE); - s_plySelectTool.StartSizingOperation(pView, nFlags, point, nDragHandle); + pSLst.AddObject(*m_pObj, TRUE); + s_plySelectTool.StartSizingOperation(pView, nMods, point, nDragHandle); } -bool CPShapeTool::OnLButtonUp(CPlayBoardView* pView, UINT nFlags, CPoint point) +bool CPShapeTool::OnLButtonUp(CPlayBoardView& pView, int nMods, wxPoint point) { - if (CWnd::GetCapture() != pView) + wxASSERT(!"dead code"); + if (!pView.HasCapture()) return false; bool retval = true; - retval = s_plySelectTool.OnLButtonUp(pView, nFlags, point) && retval; - pView->GetSelectList()->PurgeList(TRUE); // Clear current select list + retval = s_plySelectTool.OnLButtonUp(pView, nMods, point) && retval; + pView.GetSelectList().PurgeList(TRUE); // Clear current select list if (!IsEmptyObject()) - pView->AddDrawObject(m_pObj); + pView.AddDrawObject(std::move(m_pObj)); else { - delete m_pObj; m_pObj = NULL; } return true; } -void CPShapeTool::OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point) +void CPShapeTool::OnMouseMove(CPlayBoardView& pView, int nMods, wxPoint point) { - if (CWnd::GetCapture() == pView) - s_plySelectTool.OnMouseMove(pView, nFlags, point); + wxASSERT(!"dead code"); + if (pView.HasCapture()) + s_plySelectTool.OnMouseMove(pView, nMods, point); } -void CPShapeTool::OnTimer(CPlayBoardView* pView, uintptr_t nIDEvent) +void CPShapeTool::OnTimer(CPlayBoardView& pView, int nIDEvent) { + wxASSERT(!"dead code"); s_plySelectTool.OnTimer(pView, nIDEvent); } -BOOL CPShapeTool::OnSetCursor(CPlayBoardView* pView, UINT nHitTest) +wxCursor CPShapeTool::OnSetCursor(const CPlayBoardView& /*pView*/, const wxPoint& /*point*/) const { - if (nHitTest != HTCLIENT) - return FALSE; - SetCursor(g_res.hcrCrossHair); - return TRUE; + wxASSERT(!"dead code"); + return g_res.hcrCrossHairWx; } //////////////////////////////////////////////////////////////////////// // CPLineTool - tool used to create lines -CDrawObj* CPLineTool::CreateDrawObj(CPlayBoardView* pView, CPoint point, - int& nHandle) +OwnerPtr CPLineTool::CreateDrawObj(CPlayBoardView& pView, const wxPoint& point, + int& nHandle) const { - CLine* pObj = new CLine; + wxASSERT(!"dead code"); + OwnerPtr pObj = MakeOwner(); pObj->SetLine(point.x, point.y, point.x, point.y); - pObj->SetForeColor(pView->GetLineColor()); - pObj->SetLineWidth(pView->GetLineWidth()); + pObj->SetForeColor(CB::Convert(pView.GetLineColor())); + pObj->SetLineWidth(pView.GetLineWidth()); nHandle = hitPtB; return pObj; } -BOOL CPLineTool::IsEmptyObject() +BOOL CPLineTool::IsEmptyObject() const { - CRect rct = ((CLine*)m_pObj)->GetRect(); + wxASSERT(!"dead code"); + wxASSERT(dynamic_cast(&*m_pObj)); + CRect rct = static_cast(*m_pObj).GetRect(); return rct.Width() < 3 && rct.Height() < 3; } //////////////////////////////////////////////////////////////////////// // CPTextBoxTool - Text box drawing object tool -void CPTextBoxTool::OnLButtonDown(CPlayBoardView* pView, UINT nFlags, - CPoint point) +void CPTextBoxTool::OnLButtonDown(CPlayBoardView& pView, int nMods, + wxPoint poin) { + wxASSERT(!"dead code"); // pView->DoCreateTextDrawingObject(point); } -BOOL CPTextBoxTool::OnSetCursor(CPlayBoardView* pView, UINT nHitTest) +wxCursor CPTextBoxTool::OnSetCursor(const CPlayBoardView& /*pView*/, const wxPoint& /*point*/) const { - if (nHitTest != HTCLIENT) - return FALSE; - SetCursor(g_res.hcrCrossHair); - return TRUE; + wxASSERT(!"dead code"); + return g_res.hcrCrossHairWx; } //////////////////////////////////////////////////////////////////////// // CPPlotTool - move plot tool -void CPPlotTool::OnLButtonDown(CPlayBoardView* pView, UINT nFlags, - CPoint point) +void CPPlotTool::OnLButtonDown(CPlayBoardView& pView, int nMods, + wxPoint point) { - CGamDoc* pDoc = pView->GetDocument(); - CPlayBoard* pPBrd = pView->GetPlayBoard(); - ASSERT(pPBrd->GetPlotMoveMode()); + CGamDoc& pDoc = pView.GetDocument(); + CPlayBoard& pPBrd = pView.GetPlayBoard(); + wxASSERT(pPBrd.GetPlotMoveMode()); - if (pPBrd->m_bSnapMovePlot) - pView->AdjustPoint(point); // Keep on the grid (if enabled) + if (pPBrd.m_bSnapMovePlot) + point = pView.AdjustPoint(point); // Keep on the grid (if enabled) - CPoint pntPrev = pPBrd->GetPrevPlotPoint(); + wxPoint pntPrev = CB::Convert(pPBrd.GetPrevPlotPoint()); - if (pntPrev == CPoint(-1, -1)) + if (pntPrev == wxPoint(-1, -1)) { // Draw a line for each piece to the opening location - std::vector> listObjs; - pView->GetSelectList()->LoadTableWithObjectPtrs(listObjs, CSelList::otAll, FALSE); + std::vector> listObjs; + pView.GetSelectList().LoadTableWithObjectPtrs(listObjs, CSelList::otAll, FALSE); for (auto pos = listObjs.begin() ; pos != listObjs.end() ; ++pos) { CDrawObj& pObj = **pos; - ASSERT(pObj.GetType() == CDrawObj::drawPieceObj || + wxASSERT(pObj.GetType() == CDrawObj::drawPieceObj || pObj.GetType() == CDrawObj::drawMarkObj); - CRect rct = pObj.GetRect(); - CPoint pnt = GetMidRect(rct); - pDoc->IndicateBoardPlotLine(*pPBrd, pnt, point); + wxRect rct = CB::Convert(pObj.GetRect()); + wxPoint pnt = GetMidRect(rct); + pDoc.IndicateBoardPlotLine(pPBrd, CB::Convert(pnt), CB::Convert(point)); } } else - pDoc->IndicateBoardPlotLine(*pPBrd, pntPrev, point); - pPBrd->SetPrevPlotPoint(point); + pDoc.IndicateBoardPlotLine(pPBrd, CB::Convert(pntPrev), CB::Convert(point)); + pPBrd.SetPrevPlotPoint(CB::Convert(point)); } -BOOL CPPlotTool::OnSetCursor(CPlayBoardView* pView, UINT nHitTest) +wxCursor CPPlotTool::OnSetCursor(const CPlayBoardView& /*pView*/, const wxPoint& /*point*/) const { - if (nHitTest != HTCLIENT) - return FALSE; - SetCursor(g_res.hcrCrossHair); - return TRUE; + return g_res.hcrCrossHairWx; } diff --git a/GP/ToolPlay.h b/GP/ToolPlay.h index 54e25497..5aceab6e 100644 --- a/GP/ToolPlay.h +++ b/GP/ToolPlay.h @@ -1,6 +1,6 @@ // ToolPlay.h // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -31,9 +31,9 @@ class CPlayBoardView; -const UINT timerIDSelectDelay = 666; // Select timer ID +// XRCID("timerIDSelectDelay"); // Select timer ID const UINT timerIDAutoScroll = 999; // Autoscroll timer ID -const int timerSelDelay = 250; // Delay until select +const unsigned timerSelDelay = 250; // Delay until select const int timerAutoScroll = 80; // Interval of autoscrolls enum PToolType { ptypeUnknown, ptypeSelect, ptypeLine, ptypeTextBox, @@ -55,13 +55,14 @@ class CPlayTool public: static CPlayTool& GetTool(PToolType eType); // ----------- // - virtual void OnLButtonDown(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual void OnLButtonDblClk(CPlayBoardView* pView, UINT nFlags, CPoint point) {} - virtual bool OnLButtonUp(CPlayBoardView* pView, UINT nFlags, CPoint point) /* override */; - virtual void OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual void OnTimer(CPlayBoardView* pView, uintptr_t nIDEvent) /*override*/ {} - virtual BOOL OnSetCursor(CPlayBoardView* pView, UINT nHitTest) - { return FALSE; } + virtual void OnLButtonDown(CPlayBoardView& pView, int nMods, wxPoint point) /* override */; + virtual void OnLButtonDblClk(CPlayBoardView& /*pView*/, int /*nMods*/, wxPoint /*point*/) /* override */ {} + virtual bool OnLButtonUp(CPlayBoardView& pView, int nMods, wxPoint point) /* override */; + virtual void OnMouseMove(CPlayBoardView& pView, int nMods, wxPoint point) /* override */; + virtual void OnMouseCaptureLost(CPlayBoardView& pView) /* override */; + virtual void OnTimer(CPlayBoardView& /*pView*/, int /*nIDEvent*/) /*override*/ {} + virtual wxCursor OnSetCursor(const CPlayBoardView& /*pView*/, const wxPoint& /*point*/) const /*override*/ + { return wxCursor(); } // Implementation private: @@ -69,8 +70,26 @@ class CPlayTool static std::vector c_toolLib; protected: // Drag related vars.... - static CPoint c_ptDown; // Document coords. - static CPoint c_ptLast; + static wxPoint c_ptDown; // Document coords. + static wxPoint c_ptLast; +}; + +template T, typename CharT> +struct std::formatter : private std::formatter +{ +private: + using BASE = formatter; +public: + using BASE::parse; + + template + FormatContext::iterator format(const CPlayTool& o, FormatContext& ctx) const + { + return std::format_to(ctx.out(), + "{}({})", + typeid(o).name(), + static_cast(&o)); + } }; //////////////////////////////////////////////////////////////////////// @@ -80,7 +99,7 @@ class CPSelectTool : public CPlayTool { // Constructors public: - CPSelectTool() : CPlayTool(ptypeSelect) { m_nTimerID = uintptr_t(0); } + CPSelectTool() : CPlayTool(ptypeSelect) { m_nTimerID = static_cast(wxID_NONE); } // Attributes public: @@ -90,39 +109,37 @@ class CPSelectTool : public CPlayTool SelectMode m_eSelMode; int m_nHandleID; // Inter-view Drag/Drop processing support - DragInfo m_di; - HWND m_hLastWnd; + DragInfoWx m_di; + wxWindow* m_hLastWnd; // Operations public: - virtual void OnLButtonDown(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual void OnLButtonDblClk(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual bool OnLButtonUp(CPlayBoardView* pView, UINT nFlags, CPoint point) override; - virtual void OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual void OnTimer(CPlayBoardView* pView, uintptr_t nIDEvent) override; - virtual BOOL OnSetCursor(CPlayBoardView* pView, UINT nHitTest); + void OnLButtonDown(CPlayBoardView& pView, int nMods, wxPoint point) override; + void OnLButtonDblClk(CPlayBoardView& pView, int nMods, wxPoint point) override; + bool OnLButtonUp(CPlayBoardView& pView, int nMods, wxPoint point) override; + void OnMouseMove(CPlayBoardView& pView, int nMods, wxPoint point) override; + void OnMouseCaptureLost(CPlayBoardView& pView) override; + void OnTimer(CPlayBoardView& pView, int nIDEvent) override; + wxCursor OnSetCursor(const CPlayBoardView& pView, const wxPoint& point) const override; // Implementation public: - uintptr_t m_nTimerID; - CRect m_rectMultiBorder; + int m_nTimerID; + wxRect m_rectMultiBorder; // ------- // - BOOL ProcessAutoScroll(CPlayBoardView* pView); - void DrawSelectionRect(CDC* pDC, CRect* pRct); - void DrawNetRect(CDC* pDC, CPlayBoardView* pView); - BOOL AdjustPoint(CPlayBoardView* pView, CPoint& point); - void MoveSelections(CSelList *pSLst, CPoint point); - void StartDragTimer(CPlayBoardView* pView); - void KillDragTimer(CPlayBoardView* pView); - void StartScrollTimer(CPlayBoardView* pView); - void KillScrollTimer(CPlayBoardView* pView); + void DrawSelectionRect(wxDC& pDC, const wxRect& pRct) const; + void DrawNetRect(wxDC& pDC, const CPlayBoardView& pView) const; + [[nodiscard]] wxPoint AdjustPoint(const CPlayBoardView& pView, wxPoint point) const; + void MoveSelections(CSelList &pSLst, const wxPoint& point); + void StartDragTimer(CPlayBoardView& pView); + void KillDragTimer(CPlayBoardView& pView); // ------- // - void DoDragDropStart(CPlayBoardView* pView); - void DoDragDrop(CPlayBoardView* pView, CPoint pntClient); - bool DoDragDropEnd(CPlayBoardView* pView, CPoint pntClient); + void DoDragDropStart(CPlayBoardView& pView); + void DoDragDrop(CPlayBoardView& pView, const wxPoint& pntClient); + bool DoDragDropEnd(CPlayBoardView& pView, const wxPoint& pntClient); // ------- // - void StartSizingOperation(CPlayBoardView* pView, UINT nFlags, - CPoint point, int nHandleID = -1); + void StartSizingOperation(CPlayBoardView& pView, int nMods, + const wxPoint& point, int nHandleID = -1); }; //////////////////////////////////////////////////////////////////////// @@ -136,20 +153,20 @@ class CPShapeTool : public CPlayTool // Operations public: - virtual void OnLButtonDown(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual void OnLButtonDblClk(CPlayBoardView* pView, UINT nFlags, CPoint point) {} - virtual bool OnLButtonUp(CPlayBoardView* pView, UINT nFlags, CPoint point) override; - virtual void OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual void OnTimer(CPlayBoardView* pView, uintptr_t nIDEvent) override; - virtual BOOL OnSetCursor(CPlayBoardView* pView, UINT nHitTest); + void OnLButtonDown(CPlayBoardView& pView, int nMods, wxPoint point) override; + void OnLButtonDblClk(CPlayBoardView& /*pView*/, int /*nMods*/, wxPoint /*point*/) override {} + bool OnLButtonUp(CPlayBoardView& pView, int nMods, wxPoint point) override; + void OnMouseMove(CPlayBoardView& pView, int nMods, wxPoint point) override; + void OnTimer(CPlayBoardView& pView, int nIDEvent) override; + wxCursor OnSetCursor(const CPlayBoardView& pView, const wxPoint& point) const override; // Implementation public: - virtual CDrawObj* CreateDrawObj(CPlayBoardView* pView, CPoint point, - int& nHandle) = 0; - virtual BOOL IsEmptyObject() = 0; + virtual OwnerPtr CreateDrawObj(CPlayBoardView& pView, const wxPoint& point, + int& nHandle) const = 0; + virtual BOOL IsEmptyObject() const = 0; // --------- // - CDrawObj* m_pObj; + OwnerOrNullPtr m_pObj; }; //////////////////////////////////////////////////////////////////////// @@ -163,9 +180,9 @@ class CPLineTool : public CPShapeTool // Implementation public: - virtual CDrawObj* CreateDrawObj(CPlayBoardView* pView, CPoint point, - int& nHandle); - virtual BOOL IsEmptyObject(); + OwnerPtr CreateDrawObj(CPlayBoardView& pView, const wxPoint& point, + int& nHandle) const override; + BOOL IsEmptyObject() const override; }; //////////////////////////////////////////////////////////////////////// @@ -179,12 +196,12 @@ class CPTextBoxTool : public CPlayTool // Operations public: - virtual void OnLButtonDown(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual void OnLButtonDblClk(CPlayBoardView* pView, UINT nFlags, CPoint point) {} - virtual bool OnLButtonUp(CPlayBoardView* pView, UINT nFlags, CPoint point) override { return true; } - virtual void OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point) {} - virtual void OnTimer(CPlayBoardView* pView, uintptr_t nIDEvent) override {} - virtual BOOL OnSetCursor(CPlayBoardView* pView, UINT nHitTest); + void OnLButtonDown(CPlayBoardView& pView, int nMods, wxPoint point) override; + void OnLButtonDblClk(CPlayBoardView& /*pView*/, int /*nMods*/, wxPoint /*point*/) override {} + bool OnLButtonUp(CPlayBoardView& /*pView*/, int /*nMods*/, wxPoint /*point*/) override { return true; } + void OnMouseMove(CPlayBoardView& /*pView*/, int /*nMods*/, wxPoint /*point*/) override {} + void OnTimer(CPlayBoardView& /*pView*/, int /*nIDEvent*/) override {} + wxCursor OnSetCursor(const CPlayBoardView& pView, const wxPoint& point) const override; // Implementation public: @@ -202,12 +219,12 @@ class CPPlotTool : public CPlayTool // Operations public: - virtual void OnLButtonDown(CPlayBoardView* pView, UINT nFlags, CPoint point); - virtual void OnLButtonDblClk(CPlayBoardView* pView, UINT nFlags, CPoint point) {} - virtual bool OnLButtonUp(CPlayBoardView* pView, UINT nFlags, CPoint point) override { return true; } - virtual void OnMouseMove(CPlayBoardView* pView, UINT nFlags, CPoint point) {} - virtual void OnTimer(CPlayBoardView* pView, uintptr_t nIDEvent) override {} - virtual BOOL OnSetCursor(CPlayBoardView* pView, UINT nHitTest); + void OnLButtonDown(CPlayBoardView& pView, int nMods, wxPoint point) override; + void OnLButtonDblClk(CPlayBoardView& /*pView*/, int /*nMods*/, wxPoint /*point*/) override {} + bool OnLButtonUp(CPlayBoardView& /*pView*/, int /*nMods*/, wxPoint /*point*/) override { return true; } + void OnMouseMove(CPlayBoardView& /*pView*/, int /*nMods*/, wxPoint /*point*/) override {} + void OnTimer(CPlayBoardView& /*pView*/, int /*nIDEvent*/) override {} + wxCursor OnSetCursor(const CPlayBoardView& pView, const wxPoint& point) const override; // Implementation public: diff --git a/GP/VwPbrd.cpp b/GP/VwPbrd.cpp index 6560a604..75326868 100644 --- a/GP/VwPbrd.cpp +++ b/GP/VwPbrd.cpp @@ -1,6 +1,6 @@ // VwPbrd.cpp : implementation of the CPlayBoardView class // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -49,7 +49,7 @@ static char THIS_FILE[] = __FILE__; #endif -IMPLEMENT_DYNCREATE(CPlayBoardView, CScrollView) +IMPLEMENT_DYNCREATE(CPlayBoardViewContainer, CView) #ifdef _DEBUG #define new DEBUG_NEW @@ -57,118 +57,227 @@ IMPLEMENT_DYNCREATE(CPlayBoardView, CScrollView) ///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CPlayBoardView, CScrollView) - //{{AFX_MSG_MAP(CPlayBoardView) - ON_COMMAND(ID_VIEW_FULLSCALEBRD, OnViewFullScaleBrd) - ON_UPDATE_COMMAND_UI(ID_VIEW_FULLSCALEBRD, OnUpdateViewFullScaleBrd) - ON_COMMAND(ID_VIEW_HALFSCALEBRD, OnViewHalfScaleBrd) - ON_UPDATE_COMMAND_UI(ID_VIEW_HALFSCALEBRD, OnUpdateViewHalfScaleBrd) - ON_REGISTERED_MESSAGE(WM_DRAGDROP, OnDragItem) - ON_MESSAGE(WM_ROTATEPIECE_DELTA, OnMessageRotateRelative) - ON_MESSAGE(WM_CENTERBOARDONPOINT, OnMessageCenterBoardOnPoint) - ON_WM_LBUTTONDOWN() - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONUP() - ON_WM_TIMER() - ON_WM_LBUTTONDBLCLK() - ON_WM_SETCURSOR() - ON_WM_KEYDOWN() - ON_WM_CHAR() - ON_COMMAND_EX(ID_PTOOL_SELECT, OnPlayTool) - ON_UPDATE_COMMAND_UI(ID_PTOOL_SELECT, OnUpdatePlayTool) - ON_COMMAND(ID_ACT_STACK, OnActStack) - ON_UPDATE_COMMAND_UI(ID_ACT_STACK, OnUpdateActStack) - ON_COMMAND(ID_ACT_TOBACK, OnActToBack) - ON_UPDATE_COMMAND_UI(ID_ACT_TOBACK, OnUpdateActToBack) - ON_COMMAND(ID_ACT_TOFRONT, OnActToFront) - ON_UPDATE_COMMAND_UI(ID_ACT_TOFRONT, OnUpdateActToFront) - ON_COMMAND_EX(ID_ACT_TURNOVER, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_PREV, OnActTurnOver) - ON_COMMAND_EX(ID_ACT_TURNOVER_RANDOM, OnActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_PREV, OnUpdateActTurnOver) - ON_UPDATE_COMMAND_UI(ID_ACT_TURNOVER_RANDOM, OnUpdateActTurnOver) - ON_COMMAND(ID_PTOOL_PLOTMOVE, OnActPlotMove) - ON_UPDATE_COMMAND_UI(ID_PTOOL_PLOTMOVE, OnUpdateActPlotMove) - ON_COMMAND(ID_ACT_PLOTDONE, OnActPlotDone) - ON_UPDATE_COMMAND_UI(ID_ACT_PLOTDONE, OnUpdateActPlotDone) - ON_COMMAND(ID_ACT_PLOTDISCARD, OnActPlotDiscard) - ON_UPDATE_COMMAND_UI(ID_ACT_PLOTDISCARD, OnUpdateActPlotDiscard) - ON_UPDATE_COMMAND_UI(ID_INDICATOR_CELLNUM, OnUpdateIndicatorCellNum) - ON_COMMAND(ID_VIEW_SNAPGRID, OnViewSnapGrid) - ON_UPDATE_COMMAND_UI(ID_VIEW_SNAPGRID, OnUpdateViewSnapGrid) - ON_COMMAND(ID_EDIT_SELALLMARKERS, OnEditSelAllMarkers) - ON_UPDATE_COMMAND_UI(ID_EDIT_SELALLMARKERS, OnUpdateEditSelAllMarkers) +const int scrollZone = 16; // From INI? + +wxBEGIN_EVENT_TABLE(CPlayBoardView, CPlayBoardView::BASE) + EVT_MENU(XRCID("ID_VIEW_FULLSCALEBRD"), OnViewFullScaleBrd) + EVT_UPDATE_UI(XRCID("ID_VIEW_FULLSCALEBRD"), OnUpdateViewFullScaleBrd) + EVT_MENU(XRCID("ID_VIEW_HALFSCALEBRD"), OnViewHalfScaleBrd) + EVT_UPDATE_UI(XRCID("ID_VIEW_HALFSCALEBRD"), OnUpdateViewHalfScaleBrd) + EVT_DRAGDROP(OnDragItem) + EVT_ROTATEPIECE_DELTA(OnMessageRotateRelative) + EVT_CENTERBOARDONPOINT(OnMessageCenterBoardOnPoint) + EVT_LEFT_DOWN(OnLButtonDown) + EVT_MOTION(OnMouseMove) + EVT_LEFT_UP(OnLButtonUp) + EVT_MOUSE_CAPTURE_LOST(OnMouseCaptureLost) + EVT_TIMER(wxID_ANY, OnTimer) + EVT_LEFT_DCLICK(OnLButtonDblClk) + EVT_SET_CURSOR(OnSetCursor) + EVT_KEY_DOWN(OnKeyDown) + EVT_CHAR(OnChar) + EVT_MENU(XRCID("ID_PTOOL_SELECT"), OnPlayTool) + EVT_UPDATE_UI(XRCID("ID_PTOOL_SELECT"), OnUpdatePlayTool) + EVT_MENU(XRCID("ID_ACT_STACK"), OnActStack) + EVT_UPDATE_UI(XRCID("ID_ACT_STACK"), OnUpdateActStack) + EVT_MENU(XRCID("ID_ACT_TOBACK"), OnActToBack) + EVT_UPDATE_UI(XRCID("ID_ACT_TOBACK"), OnUpdateActToBack) + EVT_MENU(XRCID("ID_ACT_TOFRONT"), OnActToFront) + EVT_UPDATE_UI(XRCID("ID_ACT_TOFRONT"), OnUpdateActToFront) + EVT_MENU(XRCID("ID_ACT_TURNOVER"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_PREV"), OnActTurnOver) + EVT_MENU(XRCID("ID_ACT_TURNOVER_RANDOM"), OnActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_PREV"), OnUpdateActTurnOver) + EVT_UPDATE_UI(XRCID("ID_ACT_TURNOVER_RANDOM"), OnUpdateActTurnOver) + EVT_MENU(XRCID("ID_PTOOL_PLOTMOVE"), OnActPlotMove) + EVT_UPDATE_UI(XRCID("ID_PTOOL_PLOTMOVE"), OnUpdateActPlotMove) + EVT_MENU(XRCID("ID_ACT_PLOTDONE"), OnActPlotDone) + EVT_UPDATE_UI(XRCID("ID_ACT_PLOTDONE"), OnUpdateActPlotDone) + EVT_MENU(XRCID("ID_ACT_PLOTDISCARD"), OnActPlotDiscard) + EVT_UPDATE_UI(XRCID("ID_ACT_PLOTDISCARD"), OnUpdateActPlotDiscard) + EVT_UPDATE_UI(XRCID("ID_INDICATOR_CELLNUM"), OnUpdateIndicatorCellNum) + EVT_MENU(XRCID("ID_VIEW_SNAPGRID"), OnViewSnapGrid) + EVT_UPDATE_UI(XRCID("ID_VIEW_SNAPGRID"), OnUpdateViewSnapGrid) + EVT_MENU(XRCID("ID_EDIT_SELALLMARKERS"), OnEditSelAllMarkers) + EVT_UPDATE_UI(XRCID("ID_EDIT_SELALLMARKERS"), OnUpdateEditSelAllMarkers) +#if 0 ON_COMMAND(ID_ACT_ROTATE, OnActRotate) ON_UPDATE_COMMAND_UI(ID_ACT_ROTATE, OnUpdateActRotate) - ON_COMMAND(ID_VIEW_TOGGLESCALE, OnViewToggleScale) - ON_UPDATE_COMMAND_UI(ID_VIEW_TOGGLESCALE, OnUpdateViewToggleScale) - ON_COMMAND(ID_VIEW_PIECES, OnViewPieces) - ON_UPDATE_COMMAND_UI(ID_VIEW_PIECES, OnUpdateViewPieces) - ON_COMMAND(ID_EDIT_COPY, OnEditCopy) - ON_COMMAND(ID_EDIT_BRD2FILE, OnEditBoardToFile) - ON_COMMAND(ID_EDIT_BRDPROP, OnEditBoardProperties) - ON_COMMAND(ID_ACT_ROTATEREL, OnActRotateRelative) - ON_UPDATE_COMMAND_UI(ID_ACT_ROTATEREL, OnUpdateActRotateRelative) - ON_COMMAND(ID_EDIT_CLEAR, OnEditClear) - ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateEditClear) - ON_WM_CONTEXTMENU() - ON_COMMAND(ID_VIEW_DRAW_IND_ON_TOP, OnViewDrawIndOnTop) - ON_UPDATE_COMMAND_UI(ID_VIEW_DRAW_IND_ON_TOP, OnUpdateViewDrawIndOnTop) - ON_COMMAND(ID_EDIT_ELEMENT_TEXT, OnEditElementText) - ON_UPDATE_COMMAND_UI(ID_EDIT_ELEMENT_TEXT, OnUpdateEditElementText) - ON_COMMAND(ID_ACT_LOCKOBJECT, OnActLockObject) - ON_UPDATE_COMMAND_UI(ID_ACT_LOCKOBJECT, OnUpdateActLockObject) - ON_COMMAND(ID_ACT_LOCK_SUSPEND, OnActLockSuspend) - ON_UPDATE_COMMAND_UI(ID_ACT_LOCK_SUSPEND, OnUpdateActLockSuspend) - ON_COMMAND(ID_ACT_SHUFFLE_SELECTED, OnActShuffleSelectedObjects) - ON_UPDATE_COMMAND_UI(ID_ACT_SHUFFLE_SELECTED, OnUpdateActShuffleSelectedObjects) - ON_COMMAND(ID_ACT_AUTOSTACK_DECK, OnActAutostackDeck) - ON_UPDATE_COMMAND_UI(ID_ACT_AUTOSTACK_DECK, OnUpdateActAutostackDeck) - ON_COMMAND(ID_ACT_TAKE_OWNERSHIP, OnActTakeOwnership) - ON_UPDATE_COMMAND_UI(ID_ACT_TAKE_OWNERSHIP, OnUpdateActTakeOwnership) - ON_COMMAND(ID_ACT_RELEASE_OWNERSHIP, OnActReleaseOwnership) - ON_UPDATE_COMMAND_UI(ID_ACT_RELEASE_OWNERSHIP, OnUpdateActReleaseOwnership) - ON_COMMAND(ID_ACT_SET_OWNER, OnActSetOwner) - ON_UPDATE_COMMAND_UI(ID_ACT_SET_OWNER, OnUpdateActSetOwner) - ON_COMMAND(ID_VIEW_SMALLSCALEBRD, OnViewSmallScaleBoard) - ON_UPDATE_COMMAND_UI(ID_VIEW_SMALLSCALEBRD, OnUpdateViewSmallScaleBoard) - ON_COMMAND_EX(ID_PTOOL_LINE, OnPlayTool) - ON_COMMAND_EX(ID_PTOOL_TEXTBOX, OnPlayTool) - ON_UPDATE_COMMAND_UI(ID_PTOOL_LINE, OnUpdatePlayTool) - ON_UPDATE_COMMAND_UI(ID_PTOOL_TEXTBOX, OnUpdatePlayTool) +#endif + EVT_MENU(XRCID("ID_VIEW_TOGGLESCALE"), OnViewToggleScale) + EVT_UPDATE_UI(XRCID("ID_VIEW_TOGGLESCALE"), OnUpdateViewToggleScale) + EVT_MENU(XRCID("ID_VIEW_PIECES"), OnViewPieces) + EVT_UPDATE_UI(XRCID("ID_VIEW_PIECES"), OnUpdateViewPieces) + EVT_MENU(wxID_COPY, OnEditCopy) + EVT_UPDATE_UI(wxID_COPY, OnUpdateEnable) + EVT_MENU(XRCID("ID_EDIT_BRD2FILE"), OnEditBoardToFile) + EVT_UPDATE_UI(XRCID("ID_EDIT_BRD2FILE"), OnUpdateEnable) + EVT_MENU(XRCID("ID_EDIT_BRDPROP"), OnEditBoardProperties) + EVT_UPDATE_UI(XRCID("ID_EDIT_BRDPROP"), OnUpdateEnable) + EVT_MENU(XRCID("ID_ACT_ROTATEREL"), OnActRotateRelative) + EVT_UPDATE_UI(XRCID("ID_ACT_ROTATEREL"), OnUpdateActRotateRelative) + EVT_MENU(wxID_CLEAR, OnEditClear) + EVT_UPDATE_UI(wxID_CLEAR, OnUpdateEditClear) + EVT_CONTEXT_MENU(OnContextMenu) + EVT_MENU(XRCID("ID_VIEW_DRAW_IND_ON_TOP"), OnViewDrawIndOnTop) + EVT_UPDATE_UI(XRCID("ID_VIEW_DRAW_IND_ON_TOP"), OnUpdateViewDrawIndOnTop) + EVT_MENU(XRCID("ID_EDIT_ELEMENT_TEXT"), OnEditElementText) + EVT_UPDATE_UI(XRCID("ID_EDIT_ELEMENT_TEXT"), OnUpdateEditElementText) + EVT_MENU(XRCID("ID_ACT_LOCKOBJECT"), OnActLockObject) + EVT_UPDATE_UI(XRCID("ID_ACT_LOCKOBJECT"), OnUpdateActLockObject) + EVT_MENU(XRCID("ID_ACT_LOCK_SUSPEND"), OnActLockSuspend) + EVT_UPDATE_UI(XRCID("ID_ACT_LOCK_SUSPEND"), OnUpdateActLockSuspend) + EVT_MENU(XRCID("ID_ACT_SHUFFLE_SELECTED"), OnActShuffleSelectedObjects) + EVT_UPDATE_UI(XRCID("ID_ACT_SHUFFLE_SELECTED"), OnUpdateActShuffleSelectedObjects) + EVT_MENU(XRCID("ID_ACT_AUTOSTACK_DECK"), OnActAutostackDeck) + EVT_UPDATE_UI(XRCID("ID_ACT_AUTOSTACK_DECK"), OnUpdateActAutostackDeck) + EVT_MENU(XRCID("ID_ACT_TAKE_OWNERSHIP"), OnActTakeOwnership) + EVT_UPDATE_UI(XRCID("ID_ACT_TAKE_OWNERSHIP"), OnUpdateActTakeOwnership) + EVT_MENU(XRCID("ID_ACT_RELEASE_OWNERSHIP"), OnActReleaseOwnership) + EVT_UPDATE_UI(XRCID("ID_ACT_RELEASE_OWNERSHIP"), OnUpdateActReleaseOwnership) + EVT_MENU(XRCID("ID_ACT_SET_OWNER"), OnActSetOwner) + EVT_UPDATE_UI(XRCID("ID_ACT_SET_OWNER"), OnUpdateActSetOwner) + EVT_MENU(XRCID("ID_VIEW_SMALLSCALEBRD"), OnViewSmallScaleBoard) + EVT_UPDATE_UI(XRCID("ID_VIEW_SMALLSCALEBRD"), OnUpdateViewSmallScaleBoard) + EVT_MENU(XRCID("ID_PTOOL_LINE"), OnPlayTool) + EVT_MENU(XRCID("ID_PTOOL_TEXTBOX"), OnPlayTool) + EVT_UPDATE_UI(XRCID("ID_PTOOL_LINE"), OnUpdatePlayTool) + EVT_UPDATE_UI(XRCID("ID_PTOOL_TEXTBOX"), OnUpdatePlayTool) +#if 0 ON_WM_MOUSEWHEEL() - ON_COMMAND(ID_VIEW_BOARD_ROTATE180, OnViewBoardRotate180) - ON_UPDATE_COMMAND_UI(ID_VIEW_BOARD_ROTATE180, OnUpdateViewBoardRotate180) - ON_COMMAND(ID_ACT_ROTATEGROUP, OnActRotateGroupRelative) - ON_UPDATE_COMMAND_UI(ID_ACT_ROTATEGROUP, OnUpdateActRotateGroupRelative) - //}}AFX_MSG_MAP - ON_COMMAND_RANGE(ID_ACT_ROTATE_0, (ID_ACT_ROTATE_0 + 360 / 5), OnRotatePiece) - ON_UPDATE_COMMAND_UI_RANGE(ID_ACT_ROTATE_0, (ID_ACT_ROTATE_0 + 360 / 5), OnUpdateRotatePiece) +#endif + EVT_MENU(XRCID("ID_VIEW_BOARD_ROTATE180"), OnViewBoardRotate180) + EVT_UPDATE_UI(XRCID("ID_VIEW_BOARD_ROTATE180"), OnUpdateViewBoardRotate180) + EVT_MENU(XRCID("ID_ACT_ROTATEGROUP"), OnActRotateGroupRelative) + EVT_UPDATE_UI(XRCID("ID_ACT_ROTATEGROUP"), OnUpdateActRotateGroupRelative) + /* ID_ACT_ROTATE_0: can't use wx event tables with range + because XRCID doesn't allow controlling values, so use + wxEvtHandler::Bind */ +#if 0 + /* ID_MRKGROUP_FIRST involves modifying the menu item count, + but the menus aren't ported to wx yet */ ON_COMMAND_RANGE(ID_MRKGROUP_FIRST, ID_MRKGROUP_FIRST + 64, OnSelectGroupMarkers) ON_UPDATE_COMMAND_UI_RANGE(ID_MRKGROUP_FIRST, ID_MRKGROUP_FIRST + 64, OnUpdateSelectGroupMarkers) +#else + /* ID_MRKGROUP_FIRST_0: can't use wx event tables with range + because XRCID doesn't allow controlling values, so use + wxEvtHandler::Bind */ + /* wxUpdateEventUI doesn't support modifying menu, + so use EVT_MENU_OPEN */ + EVT_MENU_OPEN(OnMenuOpen) +#endif + EVT_WINSTATE(OnMessageWindowState) + EVT_SELECT_BOARD_OBJLIST(OnMessageSelectBoardObjectList) + EVT_SCROLLWIN_LINEDOWN(OnScrollWinLine) + EVT_SCROLLWIN_LINEUP(OnScrollWinLine) + EVT_TIMER(XRCID("ID_TIP_MSG_TIMER"), NotificationTipTimeoutHandler) +wxEND_EVENT_TABLE() + +// helper for wxEvtHandler::Bind for ID_ACT_ROTATE_0 +namespace { + // avoid trying to use XRC before wxApp initialized + const std::map& GetRotateMap() + { + static const std::map retval = []{ + std::map retval; + for (int degrees : { + 0, + 30, + 45, + 60, + 90, + 120, + 135, + 150, + 180, + 210, + 225, + 240, + 270, + 300, + 315, + 330, + }) + { + wxString name = wxString::Format("ID_ACT_ROTATE_%d", degrees); + retval[XRCID(name)] = degrees; + } + return retval; + }(); + return retval; + } +} + +// helpers for wxEvtHandler::Bind for ID_MRKGROUP_FIRST_0 +namespace { + std::map ids; + std::map indices; + int MarkerIndexToXrcid(int index) + { + auto it = ids.lower_bound(index); + if (it != ids.end() && it->first == index) + { + return it->second; + } + wxString name = wxString::Format("ID_MRKGROUP_FIRST_%d", index); + int id = XRCID(name); + ids.insert(it, std::make_pair(index, id)); + indices.insert(std::make_pair(id, index)); + return id; + } + int MarkerXrcidToIndex(int id) + { + return indices.at(id); + } +} + + +BEGIN_MESSAGE_MAP(CPlayBoardViewContainer, CPlayBoardViewContainer::BASE) + ON_WM_CREATE() + ON_WM_SETFOCUS() + ON_WM_SIZE() ON_MESSAGE(WM_WINSTATE, OnMessageWindowState) - ON_MESSAGE(WM_SELECT_BOARD_OBJLIST, OnMessageSelectBoardObjectList) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CPlayBoardView construction/destruction -CPlayBoardView::CPlayBoardView() : - m_selList(*this) +CPlayBoardView::CPlayBoardView(CPlayBoardViewContainer& p) : + m_selList(*this), + parent(&p), + document(dynamic_cast(parent->GetDocument())), + m_pPBoard(static_cast(document->GetNewViewParameter())), + m_toolMsgTipTimer(this, XRCID("ID_TIP_MSG_TIMER")) { - m_pPBoard = NULL; + EnableAutoScrollInside(scrollZone); + DisableAutoScrollOutside(); + + // use wxEvtHandler::Bind for ID_ACT_ROTATE_0 + for (auto pair : GetRotateMap()) + { + Bind(wxEVT_MENU, &CPlayBoardView::OnRotatePiece, this, pair.first); + Bind(wxEVT_UPDATE_UI, &CPlayBoardView::OnUpdateRotatePiece, this, pair.first); + } + m_nZoom = fullScale; - m_nCurToolID = ID_PTOOL_SELECT; + m_nCurToolID = XRCID("ID_PTOOL_SELECT"); m_bInDrag = FALSE; m_pDragSelList = NULL; - m_nTimerID = uintptr_t(0); + + // use sizers for scrolling + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); + SetSizer(sizer); + sizer->Add(0, 0); + BASE::Create(*parent, 0); + OnInitialUpdate(); } CPlayBoardView::~CPlayBoardView() { } +#if 0 BOOL CPlayBoardView::PreCreateWindow(CREATESTRUCT& cs) { if (!CScrollView::PreCreateWindow(cs)) @@ -180,30 +289,32 @@ BOOL CPlayBoardView::PreCreateWindow(CREATESTRUCT& cs) return TRUE; } +#endif ///////////////////////////////////////////////////////////////////////////// void CPlayBoardView::OnInitialUpdate() { - m_toolMsgTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOPREFIX); - m_toolMsgTip.SetMaxTipWidth(MAX_PLAYBOARD_TIP_WIDTH); - m_toolHitTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOPREFIX); - m_toolHitTip.SetMaxTipWidth(MAX_PLAYBOARD_TIP_WIDTH); + m_toolMsgTip.SetBalloonMode(true); + m_toolMsgTip.SetMaxWidth(MAX_PLAYBOARD_TIP_WIDTH); + m_toolHitTip.SetBalloonMode(true); + m_toolHitTip.SetMaxWidth(MAX_PLAYBOARD_TIP_WIDTH); m_pCurTipObj = NULL; - m_pPBoard = (CPlayBoard*)GetDocument()->GetNewViewParameter(); +#if 0 + m_pPBoard = (CPlayBoard*)GetDocument().GetNewViewParameter(); if (m_pPBoard == NULL) { // See if we can get our playing board from the (0, 0) pane in the splitter. CSplitterWndEx* pParent = (CSplitterWndEx*)GetParent(); CPlayBoardView* pPlay = (CPlayBoardView*)pParent->GetPane(0, 0); - m_pPBoard = pPlay->GetPlayBoard(); + m_pPBoard = &pPlay->GetPlayBoard(); } ASSERT(m_pPBoard != NULL); +#endif SetOurScrollSizes(m_nZoom); - CScrollView::OnInitialUpdate(); } void CPlayBoardView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) @@ -216,27 +327,27 @@ void CPlayBoardView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) else if (lHint == HINT_BOARDCHANGE) { // Make sure we still exist! - if (GetDocument()->GetPBoardManager().FindPBoardByRef(CheckedDeref(m_pPBoard)) == Invalid_v) + if (GetDocument().GetPBoardManager().FindPBoardByRef(*m_pPBoard) == Invalid_v) { - CFrameWnd* pFrm = GetParentFrame(); - ASSERT(pFrm != NULL); + CFrameWnd* pFrm = parent->GetParentFrame(); + wxASSERT(pFrm != NULL); pFrm->PostMessage(WM_CLOSE, 0, 0L); } } else if (lHint == HINT_UPDATEOBJECT && ph->GetArgs().m_pPBoard == m_pPBoard) { - CRect rct; - rct = ph->GetArgs().m_pDrawObj->GetEnclosingRect(); // In board coords. - InvalidateWorkspaceRect(&rct); + wxRect rct; + rct = CB::Convert(ph->GetArgs().m_pDrawObj->GetEnclosingRect()); // In board coords. + InvalidateWorkspaceRect(rct); } else if (lHint == HINT_UPDATEOBJLIST && ph->GetArgs().m_pPBoard == m_pPBoard) { - const std::vector>& pPtrList = CheckedDeref(ph->GetArgs().m_pPtrList); + const std::vector>& pPtrList = CheckedDeref(ph->GetArgs().m_pPtrList); for (size_t i = size_t(0); i < pPtrList.size(); ++i) { - CDrawObj& pDObj = *pPtrList[i]; - CRect rct = pDObj.GetEnclosingRect(); // In board coords. - InvalidateWorkspaceRect(&rct); + const CDrawObj& pDObj = *pPtrList[i]; + wxRect rct = CB::Convert(pDObj.GetEnclosingRect()); // In board coords. + InvalidateWorkspaceRect(rct); } } else if (lHint == HINT_SELECTOBJ) @@ -265,7 +376,7 @@ void CPlayBoardView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) NotifySelectListChange(); } } - else if (lHint == HINT_UPDATESELECTLIST && pSender != this) + else if (lHint == HINT_UPDATESELECTLIST && pSender != &*parent) { // Resync the select list to ensure that all objects still exist // and that the handles track objct movements for those that still @@ -284,23 +395,21 @@ void CPlayBoardView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) else if (lHint == HINT_INVALIDATERECT && ph->GetArgs().m_pPBoard == m_pPBoard) { const CRect& rect = CheckedDeref(ph->GetArgs().m_pRect); - InvalidateWorkspaceRect(rect, true); + InvalidateWorkspaceRect(CB::Convert(rect), true); } else if (lHint == HINT_GAMESTATEUSED) { m_selList.PurgeList(TRUE); - Invalidate(FALSE); - BeginWaitCursor(); - UpdateWindow(); - EndWaitCursor(); + Refresh(FALSE); + wxBusyCursor busyCursor; + Update(); } else if (lHint == HINT_ALWAYSUPDATE || (lHint == HINT_UPDATEBOARD && ph->GetArgs().m_pPBoard == m_pPBoard)) { - Invalidate(FALSE); - BeginWaitCursor(); - UpdateWindow(); - EndWaitCursor(); + Refresh(FALSE); + wxBusyCursor busyCursor; + Update(); } else if (lHint == HINT_CLEARINDTIP) { @@ -315,14 +424,13 @@ void CPlayBoardView::NotifySelectListChange() CGamDocHint hint; hint.GetArgs().m_pPBoard = m_pPBoard.get(); hint.GetArgs().m_pSelList = &m_selList; - GetDocument()->UpdateAllViews(this, HINT_UPDATESELECT, &hint); + GetDocument().UpdateAllViews(&*parent, HINT_UPDATESELECT, &hint); } /////////////////////////////////////////////////////////////////////// void CPlayBoardView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) { - CScrollView::OnActivateView(bActivate, pActivateView, pDeactiveView); if (bActivate && pActivateView != pDeactiveView) NotifySelectListChange(); } @@ -331,62 +439,63 @@ void CPlayBoardView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* // This message is sent when a document is being saved. // WPARAM = CPlayBoard*, LPARAM = const std::vector>* -LRESULT CPlayBoardView::OnMessageSelectBoardObjectList(WPARAM wParam, LPARAM lParam) +void CPlayBoardView::OnMessageSelectBoardObjectList(SelectBoardObjListEvent& event) { - if ((CPlayBoard*)wParam != m_pPBoard) - return (LRESULT)0; - const std::vector>& pList = *(const std::vector>*)lParam; + if (&event.GetBoard() != m_pPBoard) + { + event.Skip(); + return; + } + const std::vector>& pList = event.GetObjList(); m_selList.PurgeList(); // Deselect current set of selections SelectAllObjectsInList(pList); // Select the new set - return (LRESULT)1; } /////////////////////////////////////////////////////////////////////// // This message is sent when a document is being saved. // WPARAM = CArchive*, LPARAM = 0 if save, 1 if restore -LRESULT CPlayBoardView::OnMessageWindowState(WPARAM wParam, LPARAM lParam) +void CPlayBoardView::OnMessageWindowState(WinStateEvent& event) { - ASSERT(wParam != NULL); - CArchive& ar = *((CArchive*)wParam); + CArchive& ar = event.GetArchive(); if (ar.IsStoring()) { - ar << (WORD)m_nZoom; + ar << static_cast(m_nZoom); - CPoint pnt = GetScrollPosition(); - ar << (DWORD)pnt.x; - ar << (DWORD)pnt.y; + wxPoint pnt = GetViewStart(); + ar << value_preserving_cast(pnt.x); + ar << value_preserving_cast(pnt.y); // Save the select list if (!m_selList.empty()) { - std::vector> tblObjPtrs; + std::vector> tblObjPtrs; m_selList.LoadTableWithObjectPtrs(tblObjPtrs, CSelList::otPiecesMarks, TRUE); - ar << value_preserving_cast(tblObjPtrs.size()); - for (size_t i = 0; i < tblObjPtrs.size(); i++) + ar << value_preserving_cast(tblObjPtrs.size()); + for (size_t i = size_t(0); i < tblObjPtrs.size(); i++) { CDrawObj& pObj = *tblObjPtrs.at(i); - ar << GetDocument()->GetGameElementCodeForObject(pObj); + ar << GetDocument().GetGameElementCodeForObject(pObj); } } else - ar << (DWORD)0; + ar << uint32_t(0); } else { - CPoint pnt; - WORD wTmp; - DWORD dwTmp; + wxPoint pnt; + uint16_t wTmp; + uint32_t dwTmp; - ar >> wTmp; DoViewScaleBrd((TileScale)wTmp); + ar >> wTmp; DoViewScaleBrd(static_cast(wTmp)); - ar >> dwTmp; pnt.x = (LONG)dwTmp; - ar >> dwTmp; pnt.y = (LONG)dwTmp; + ar >> dwTmp; pnt.x = value_preserving_cast(dwTmp); + ar >> dwTmp; pnt.y = value_preserving_cast(dwTmp); - ScrollToPosition(pnt); + Scroll(pnt); // Restore the select list. m_selList.PurgeList(); - DWORD dwSelCount; + uint32_t dwSelCount; ar >> dwSelCount; while (dwSelCount--) { @@ -401,11 +510,45 @@ LRESULT CPlayBoardView::OnMessageWindowState(WPARAM wParam, LPARAM lParam) m_selList.AddObject(*pObj, TRUE); } } - return (LRESULT)1; +} + +/* This view should support scrolling by individual pixels, + but don't make the line-up and line-down scrolling that + slow. */ +void CPlayBoardView::OnScrollWinLine(wxScrollWinEvent& event) +{ + int type = event.GetEventType(); + wxASSERT(type == static_cast(wxEVT_SCROLLWIN_LINEDOWN) || + type == static_cast(wxEVT_SCROLLWIN_LINEUP)); + + int orient = event.GetOrientation(); + wxASSERT(orient == static_cast(wxHORIZONTAL) || + orient == static_cast(wxVERTICAL)); + + int oldPos; + int offset; + if (orient == static_cast(wxHORIZONTAL)) + { + oldPos = GetViewStart().x; + offset = m_xScrollPixelsPerLine; + } + else + { + oldPos = GetViewStart().y; + offset = m_yScrollPixelsPerLine; + } + if (type == static_cast(wxEVT_SCROLLWIN_LINEUP)) + { + offset = -offset; + } + + wxScrollWinEvent thumbEvent(wxEVT_SCROLLWIN_THUMBTRACK, oldPos + offset, orient); + ProcessWindowEvent(thumbEvent); } ///////////////////////////////////////////////////////////////////////////// +#if 0 BOOL CPlayBoardView::PreTranslateMessage(MSG* pMsg) { // RelayEvent is required for CToolTipCtrl objects - @@ -416,52 +559,77 @@ BOOL CPlayBoardView::PreTranslateMessage(MSG* pMsg) return CScrollView::PreTranslateMessage(pMsg); } +#endif ///////////////////////////////////////////////////////////////////////////// void CPlayBoardView::SetOurScrollSizes(TileScale nZoom) { + if (nZoom == fullScale) + { + /* KLUDGE: without this, the optimization in + wxDC::SetUserScale() that returns immediately if + the new scale equals the old scale sometimes + leaves the wxDC with wrong scale behavior */ + overlay = MakeOwner(); + } CBoard* pBoard = m_pPBoard->GetBoard(); - HDC hDC = ::GetDC(NULL); - int xWidth = GetDeviceCaps(hDC, HORZRES); - int yHeight = GetDeviceCaps(hDC, VERTRES); - CSize sizeCell = pBoard->GetCellSize(nZoom); - int nPageX = sizeCell.cx > xWidth / 8 ? xWidth / 32 : sizeCell.cx; - int nPageY = sizeCell.cy > yHeight / 8 ? yHeight / 32 : sizeCell.cy; + wxSizer& sizer = CheckedDeref(GetSizer()); + wxSizerItemList& items = sizer.GetChildren(); + wxASSERT(items.size() == 1); + wxSizerItem& item = CheckedDeref(items[0]); + wxASSERT(item.IsSpacer()); + + item.AssignSpacer(CB::Convert(pBoard->GetSize(m_nZoom))); + SetScrollRate(1, 1); + sizer.FitInside(this); - SetScrollSizes(MM_TEXT, pBoard->GetSize(m_nZoom), sizeDefault, - CSize(nPageX, nPageY)); + // use size of cell as line increment + const CCellForm& cf = pBoard->GetBoardArray().GetCellForm(m_nZoom); + wxSize cellSize = CB::Convert(cf.GetCellSize()); + switch (cf.GetCellType()) + { + case cformHexFlat: + (cellSize.x *= 3) /= 4; + break; + case cformHexPnt: + (cellSize.y *= 3) /= 4; + break; + default: + ; // do nothing + } + m_xScrollPixelsPerLine = cellSize.x; + m_yScrollPixelsPerLine = cellSize.y; } ///////////////////////////////////////////////////////////////////////////// // CPlayBoardView drawing -void CPlayBoardView::OnDraw(CDC* pDC) +void CPlayBoardView::OnDraw(wxDC& pDC) { + GetOverlay().Reset(); CBoard* pBoard = m_pPBoard->GetBoard(); - CDC dcMem; - CRect oRct; - CRect oRctSave; - CBitmap* pPrvBMap; + wxMemoryDC dcMem; + wxRect oRct; + wxRect oRctSave; - pDC->GetClipBox(&oRct); + pDC.GetClippingBox(oRct); - if (oRct.IsRectEmpty()) + if (oRct.IsEmpty()) return; // Nothing to do - OwnerPtr bmMem = CDib::CreateDIBSection( - oRct.Width(), oRct.Height()); - dcMem.CreateCompatibleDC(pDC); - pPrvBMap = dcMem.SelectObject(&*bmMem); + wxBitmap bmMem( + oRct.GetWidth(), oRct.GetHeight(), pDC); + dcMem.SelectObject(bmMem); if (m_pPBoard->IsBoardRotated180()) { oRctSave = oRct; - CSize sizeBrd = pBoard->GetSize(m_nZoom); - oRct = CRect(CPoint(sizeBrd.cx - oRct.left - oRct.Width(), - sizeBrd.cy - oRct.top - oRct.Height()), oRct.Size()); + wxSize sizeBrd = CB::Convert(pBoard->GetSize(m_nZoom)); + oRct = wxRect(wxPoint(sizeBrd.x - oRct.GetLeft() - oRct.GetWidth(), + sizeBrd.y - oRct.GetTop() - oRct.GetHeight()), oRct.GetSize()); } - dcMem.SetViewportOrg(-oRct.left, -oRct.top); + dcMem.SetDeviceOrigin(-oRct.GetLeft(), -oRct.GetTop()); // Draw base board image... pBoard->SetMaxDrawLayer(); // Make sure all layers are drawn @@ -470,67 +638,77 @@ void CPlayBoardView::OnDraw(CDC* pDC) // Draw pieces etc..... - CRect rct(&oRct); - SetupDrawListDC(dcMem, rct); + wxRect rct(oRct); + { + DCSetupDrawListDC setupDrawListDC(*this, dcMem, rct); - m_pPBoard->Draw(dcMem, &rct, m_nZoom); + m_pPBoard->Draw(dcMem, rct, m_nZoom); - wxASSERT(!pDC->IsPrinting()); - if (!pDC->IsPrinting() && GetPlayBoard()->GetPiecesVisible()) + wxASSERT(!dynamic_cast(&pDC)); + if (!dynamic_cast(&pDC) && GetPlayBoard().GetPiecesVisible()) m_selList.OnDraw(dcMem); // Handle selections. - RestoreDrawListDC(dcMem); + } if (m_pPBoard->IsBoardRotated180()) { // Xfer to output - dcMem.SetViewportOrg(0, 0); - pDC->StretchBlt(oRctSave.left, oRctSave.top, oRctSave.Width(), oRctSave.Height(), - &dcMem, oRctSave.Width() - 1, oRctSave.Height() - 1, - -oRctSave.Width(), -oRctSave.Height(), SRCCOPY); + dcMem.SetDeviceOrigin(0, 0); + pDC.StretchBlit(oRctSave.GetLeft(), oRctSave.GetTop(), oRctSave.GetWidth(), oRctSave.GetHeight(), + &dcMem, oRctSave.GetWidth() - 1, oRctSave.GetHeight() - 1, + -oRctSave.GetWidth(), -oRctSave.GetHeight()); } else { // Xfer to output - pDC->BitBlt(oRct.left, oRct.top, oRct.Width(), oRct.Height(), - &dcMem, oRct.left, oRct.top, SRCCOPY); + pDC.Blit(oRct.GetLeft(), oRct.GetTop(), oRct.GetWidth(), oRct.GetHeight(), + &dcMem, oRct.GetLeft(), oRct.GetTop()); } - - dcMem.SelectObject(pPrvBMap); } ///////////////////////////////////////////////////////////////////////////// -LRESULT CPlayBoardView::OnDragItem(WPARAM wParam, LPARAM lParam) +void CPlayBoardView::OnDragItem(DragDropEvent& event) { - if (wParam != GetProcessId(GetCurrentProcess())) + if (event.GetProcessId() != wxGetProcessId()) { - return -1; + return; } - if (GetDocument()->IsPlaying()) - return -1; // Drags not supported during play + if (GetDocument().IsPlaying()) + return; // Drags not supported during play - DragInfo& pdi = CheckedDeref(reinterpret_cast(lParam)); + const DragInfoWx& pdi = event.GetDragInfo(); if (pdi.GetDragType() == DRAG_PIECE) - return DoDragPiece(pdi); + { + DoDragPiece(pdi); + return; + } if (pdi.GetDragType() == DRAG_PIECELIST) - return DoDragPieceList(pdi); + { + DoDragPieceList(event); + return; + } if (pdi.GetDragType() == DRAG_MARKER) - return DoDragMarker(pdi); + { + DoDragMarker(event); + return; + } if (pdi.GetDragType() == DRAG_SELECTLIST) - return DoDragSelectList(pdi); - - return 0; + { + DoDragSelectList(event); + return; + } } -LRESULT CPlayBoardView::DoDragPiece(DragInfo& pdi) +void CPlayBoardView::DoDragPiece(const DragInfoWx& pdi) { - ASSERT(FALSE); //!!!NOT USED???? //TODO: WHAT'S GOING ON HERE? 20200618 - if (pdi.GetSubInfo().m_gamDoc != GetDocument()) + wxASSERT(FALSE); //!!!NOT USED???? //TODO: WHAT'S GOING ON HERE? 20200618 +#if 0 + if (pdi.GetSubInfo().m_gamDoc != &GetDocument()) return -1; // Only pieces from our document. // if piece can't fit on board, reject drop @@ -554,59 +732,65 @@ LRESULT CPlayBoardView::DoDragPiece(DragInfo& pdi) else if (pdi.m_phase == PhaseDrag::Drop) { CPoint pnt = pdi.m_point; - ClientToWorkspace(pnt); + pnt = ClientToWorkspace(pnt); AddPiece(pnt, pdi.GetSubInfo().m_pieceID); DragKillAutoScroll(); } return 1; +#endif } -LRESULT CPlayBoardView::DoDragPieceList(DragInfo& pdi) +void CPlayBoardView::DoDragPieceList(DragDropEvent& event) { - if (pdi.GetSubInfo().m_gamDoc != GetDocument()) - return -1; // Only pieces from our document. + const DragInfoWx& pdi = event.GetDragInfo(); + if (pdi.GetSubInfo().m_gamDoc != &GetDocument()) + return; // Only pieces from our document. // if piece can't fit on board, reject drop - CSize limit = m_pPBoard->GetBoard()->GetSize(fullScale); - if (pdi.GetSubInfo().m_size.cx > limit.cx || - pdi.GetSubInfo().m_size.cy > limit.cy) + wxSize limit = CB::Convert(m_pPBoard->GetBoard()->GetSize(fullScale)); + if (pdi.GetSubInfo().m_size.x > limit.x || + pdi.GetSubInfo().m_size.y > limit.y) { - return pdi.m_phase == PhaseDrag::Over ? - reinterpret_cast(g_res.hcrNoDropTooBig) - : - -1; + if (pdi.m_phase == PhaseDrag::Over) + { + event.SetCursor(g_res.hcrNoDropTooBigWx); + } + return; } if (pdi.m_phase == PhaseDrag::Exit) - DragKillAutoScroll(); + DisableAutoscrollWithoutCapture(); + else if (pdi.m_phase == PhaseDrag::Enter) + { + EnableAutoscrollWithoutCapture(); + } else if (pdi.m_phase == PhaseDrag::Over) { - DragCheckAutoScroll(); - return (LRESULT)(LPVOID)pdi.m_hcsrSuggest; + event.SetCursor(pdi.m_hcsrSuggest); } else if (pdi.m_phase == PhaseDrag::Drop) { - CGamDoc* pDoc = GetDocument(); - CPoint pnt = pdi.m_point; + CGamDoc& pDoc = GetDocument(); + wxPoint pnt = pdi.m_point; const std::vector& pTbl = CheckedDeref(pdi.GetSubInfo().m_pieceIDList); - ClientToWorkspace(pnt); + pnt = ClientToWorkspace(pnt); // If the snap grid is on, adjust the point. - CSize sz = GetDocument()->GetPieceTable().GetStackedSize(pTbl, - m_pPBoard->m_xStackStagger, m_pPBoard->m_yStackStagger); - ASSERT(sz.cx != 0 && sz.cy != 0); - CRect rct(CPoint(pnt.x - sz.cx/2, pnt.y - sz.cy/2), sz); - AdjustRect(rct); + wxSize sz = CB::Convert(GetDocument().GetPieceTable().GetStackedSize(pTbl, + m_pPBoard->m_xStackStagger, m_pPBoard->m_yStackStagger)); + wxASSERT(sz.x != 0 && sz.y != 0); + wxRect rct(wxPoint(pnt.x - sz.x/2, pnt.y - sz.y/2), sz); + rct = AdjustRect(rct); pnt = GetMidRect(rct); m_selList.PurgeList(TRUE); // Purge former selections - GetDocument()->AssignNewMoveGroup(); - GetDocument()->PlacePieceListOnBoard(pnt, pTbl, + GetDocument().AssignNewMoveGroup(); + GetDocument().PlacePieceListOnBoard(CB::Convert(pnt), pTbl, m_pPBoard->m_xStackStagger, m_pPBoard->m_yStackStagger, m_pPBoard.get()); - if (!pDoc->HasPlayers() || !m_pPBoard->IsOwned() || + if (!pDoc.HasPlayers() || !m_pPBoard->IsOwned() || m_pPBoard->IsNonOwnerAccessAllowed() || - m_pPBoard->IsOwnedBy(pDoc->GetCurrentPlayerMask())) + m_pPBoard->IsOwnedBy(pDoc.GetCurrentPlayerMask())) { CDrawList* pDwg = m_pPBoard->GetPieceList(); std::vector> pceList; @@ -616,56 +800,68 @@ LRESULT CPlayBoardView::DoDragPieceList(DragInfo& pdi) SelectAllObjectsInList(temp); // Reselect pieces dropped on board } - DragKillAutoScroll(); + DisableAutoscrollWithoutCapture(); } - return 1; + return; } #define MARKER_DROP_GAP_X 8 -LRESULT CPlayBoardView::DoDragMarker(DragInfo& pdi) +void CPlayBoardView::DoDragMarker(DragDropEvent& event) { - ASSERT(pdi.GetDragType() == DRAG_MARKER); - CGamDoc* pDoc = GetDocument(); - if (pdi.GetSubInfo().m_gamDoc != pDoc) - return -1; // Only markers from our document. + const DragInfoWx& pdi = event.GetDragInfo(); + wxASSERT(pdi.GetDragType() == DRAG_MARKER); + CGamDoc& pDoc = GetDocument(); + if (pdi.GetSubInfo().m_gamDoc != &pDoc) + return; // Only markers from our document. + + // allow autoscroll while this is drag destination + switch (pdi.m_phase) + { + case PhaseDrag::Enter: + EnableAutoscrollWithoutCapture(); + break; + case PhaseDrag::Exit: + case PhaseDrag::Drop: + DisableAutoscrollWithoutCapture(); + break; + } // if marker can't fit on board, reject drop - CSize limit = m_pPBoard->GetBoard()->GetSize(fullScale); - if (pdi.GetSubInfo().m_size.cx > limit.cx || - pdi.GetSubInfo().m_size.cy > limit.cy) + wxSize limit = CB::Convert(m_pPBoard->GetBoard()->GetSize(fullScale)); + if (pdi.GetSubInfo().m_size.x > limit.x || + pdi.GetSubInfo().m_size.y > limit.y) { - return pdi.m_phase == PhaseDrag::Over ? - reinterpret_cast(g_res.hcrNoDropTooBig) - : - -1; + if (pdi.m_phase == PhaseDrag::Over) + { + event.SetCursor(g_res.hcrNoDropTooBigWx); + } + return; } - if (pdi.m_phase == PhaseDrag::Exit) - DragKillAutoScroll(); - else if (pdi.m_phase == PhaseDrag::Over) + if (pdi.m_phase == PhaseDrag::Over) { - DragCheckAutoScroll(); - return (LRESULT)(LPVOID)pdi.m_hcsrSuggest; + event.SetCursor(pdi.m_hcsrSuggest); + return; } else if (pdi.m_phase == PhaseDrag::Drop) { - CMarkManager& pMMgr = pDoc->GetMarkManager(); - CPoint pnt = pdi.m_point; + CMarkManager& pMMgr = pDoc.GetMarkManager(); + wxPoint pnt = pdi.m_point; MarkID mid = pdi.GetSubInfo().m_markID; - ClientToWorkspace(pnt); + pnt = ClientToWorkspace(pnt); // If Control is held and the marker tray is set to // deliver random markers, prompt for a count of markers // and randomly select that many of them. The snap grid is // ignored for this sort of placement. - if (GetKeyState(VK_CONTROL) < 0) + if (wxGetKeyState(WXK_CONTROL)) { // I'm going to cheat. I happen to know that marker drops // can only originate at the marker palette. I can find out // the current marker set this way. - size_t nMrkGrp = pDoc->m_palMark.GetSelectedMarkerGroup(); - ASSERT(nMrkGrp != Invalid_v); + size_t nMrkGrp = (*pDoc.m_palMark)->GetSelectedMarkerGroup(); + wxASSERT(nMrkGrp != Invalid_v); if (nMrkGrp == Invalid_v) goto NASTY_GOTO_TARGET; CMarkSet& pMSet = pMMgr.GetMarkSet(nMrkGrp); @@ -684,7 +880,7 @@ LRESULT CPlayBoardView::DoDragMarker(DragInfo& pdi) // Pull markers randomly from the marker group. tblMarks.reserve(1); tblMarks.push_back(mid); // Add the first one that was dropped - pMSet.GetRandomSelection(value_preserving_cast(dlg.m_nMarkerCount - 1), tblMarks, pDoc); + pMSet.GetRandomSelection(value_preserving_cast(dlg.m_nMarkerCount - 1), tblMarks, &pDoc); } else { @@ -694,48 +890,48 @@ LRESULT CPlayBoardView::DoDragMarker(DragInfo& pdi) tblMarks.push_back(mid); // Add the first one that was dropped } // First figure out the minimum size required. - CSize sizeMin(0, 0); + wxSize sizeMin(0, 0); int i; for (i = 0; i < dlg.m_nMarkerCount; i++) { - CSize size = pMMgr.GetMarkSize(tblMarks[value_preserving_cast(i)]); - sizeMin.cx += size.cx; - sizeMin.cy = CB::max(sizeMin.cy, size.cy); + wxSize size = CB::Convert(pMMgr.GetMarkSize(tblMarks[value_preserving_cast(i)])); + sizeMin.x += size.x; + sizeMin.y = CB::max(sizeMin.y, size.y); if (i < dlg.m_nMarkerCount - 1) - sizeMin += CSize(MARKER_DROP_GAP_X, 0); + sizeMin += wxSize(MARKER_DROP_GAP_X, 0); } - CRect rct(CPoint(pnt.x - sizeMin.cx/2, pnt.y - sizeMin.cy), sizeMin); - LimitRect(rct); // Make sure stays on board. + wxRect rct(wxPoint(pnt.x - sizeMin.x/2, pnt.y - sizeMin.y), sizeMin); + rct = LimitRect(rct); // Make sure stays on board. - pDoc->AssignNewMoveGroup(); - int x = rct.right; - int y = (rct.top + rct.bottom) / 2; + pDoc.AssignNewMoveGroup(); + int x = rct.GetRight(); + int y = (rct.GetTop() + rct.GetBottom()) / 2; // Load the list from right ot left so the objects // show up in the select list in top to bottom // corresponding to left to right. for (i = dlg.m_nMarkerCount - 1; i >= 0; i--) { - CSize size = pMMgr.GetMarkSize(tblMarks[value_preserving_cast(i)]); - CDrawObj& pObj = pDoc->CreateMarkerObject(m_pPBoard.get(), tblMarks[value_preserving_cast(i)], - CPoint(x - size.cx / 2, y), ObjectID()); - x -= size.cx + MARKER_DROP_GAP_X; + wxSize size = CB::Convert(pMMgr.GetMarkSize(tblMarks[value_preserving_cast(i)])); + CDrawObj& pObj = pDoc.CreateMarkerObject(m_pPBoard.get(), tblMarks[value_preserving_cast(i)], + CB::Convert(wxPoint(x - size.x / 2, y)), ObjectID()); + x -= size.x + MARKER_DROP_GAP_X; m_selList.AddObject(pObj, TRUE); } NotifySelectListChange(); - return 1; + return; } NASTY_GOTO_TARGET: m_selList.PurgeList(); // If the snap grid is on, adjust the point. - CSize sz = pMMgr.GetMarkSize(mid); - ASSERT(sz.cx != 0 && sz.cy != 0); - CRect rct(CPoint(pnt.x - sz.cx/2, pnt.y - sz.cy/2), sz); - AdjustRect(rct); + wxSize sz = CB::Convert(pMMgr.GetMarkSize(mid)); + wxASSERT(sz.x != 0 && sz.y != 0); + wxRect rct(wxPoint(pnt.x - sz.x/2, pnt.y - sz.y/2), sz); + rct = AdjustRect(rct); pnt = GetMidRect(rct); - pDoc->AssignNewMoveGroup(); - CDrawObj& pObj = pDoc->CreateMarkerObject(m_pPBoard.get(), mid, pnt, ObjectID()); + pDoc.AssignNewMoveGroup(); + CDrawObj& pObj = pDoc.CreateMarkerObject(m_pPBoard.get(), mid, CB::Convert(pnt), ObjectID()); // If marker is set to prompt for text on drop, show the // dialog. @@ -743,76 +939,93 @@ LRESULT CPlayBoardView::DoDragMarker(DragInfo& pdi) { CEditElementTextDialog dlg; - dlg.m_strText = pDoc->GetGameElementString(MakeMarkerElement(mid)); + dlg.m_strText = pDoc.GetGameElementString(MakeMarkerElement(mid)); if (dlg.ShowModal() == wxID_OK) { - GameElement elem = pDoc->GetGameElementCodeForObject(pObj); - pDoc->SetObjectText(elem, dlg.m_strText.empty() ? NULL : + GameElement elem = pDoc.GetGameElementCodeForObject(pObj); + pDoc.SetObjectText(elem, dlg.m_strText.empty() ? NULL : &dlg.m_strText); } } } - return 1; + return; } -LRESULT CPlayBoardView::DoDragSelectList(DragInfo& pdi) +void CPlayBoardView::DoDragSelectList(DragDropEvent& event) { - if (pdi.GetSubInfo().m_gamDoc != GetDocument()) - return -1; // Only pieces from our document. + const DragInfoWx& pdi = event.GetDragInfo(); + if (pdi.GetSubInfo().m_gamDoc != &GetDocument()) + return; // Only pieces from our document. - ClientToWorkspace(pdi.m_point); + // allow autoscroll while this is drag destination + switch (pdi.m_phase) + { + case PhaseDrag::Enter: + EnableAutoscrollWithoutCapture(); + break; + case PhaseDrag::Exit: + case PhaseDrag::Drop: + DisableAutoscrollWithoutCapture(); + break; + } + + wxPoint pdi_m_point = ClientToWorkspace(pdi.m_point); CSelList *pSLst = pdi.GetSubInfo().m_selectList; - CDC& pDC = CheckedDeref(GetDC()); + wxOverlayDC pDC(GetOverlay(), this); OnPrepareScaledDC(pDC, TRUE); + pDC.Clear(); if (pdi.m_phase == PhaseDrag::Exit || pdi.m_phase == PhaseDrag::Drop || pdi.m_phase == PhaseDrag::Over) { // Remove previous drag image. +#if 0 pSLst->DrawTracker(pDC, trkMoving); +#elif 0 + GetOverlay().Reset(); +#endif } - if (pdi.m_phase == PhaseDrag::Exit) - DragKillAutoScroll(); - CRect rctSnapRef = pSLst->GetSnapReferenceRect(); - CPoint pntSnapRefTopLeft = rctSnapRef.TopLeft(); + wxRect rctSnapRef = CB::Convert(pSLst->GetSnapReferenceRect()); + wxPoint pntSnapRefTopLeft = rctSnapRef.GetTopLeft(); - CPoint pntMseOff = pntSnapRefTopLeft + pSLst->GetMouseOffset(); - CSize sizeDelta = pdi.m_point - pntMseOff; // Trial delta + wxPoint pntMseOff = pntSnapRefTopLeft + CB::Convert(pSLst->GetMouseOffset()); + wxPoint sizeDelta = pdi_m_point - pntMseOff; // Trial delta - rctSnapRef += (CPoint)sizeDelta; // Calc trial new position - AdjustRect(rctSnapRef); // Force onto grid. - sizeDelta = rctSnapRef.TopLeft() - pntSnapRefTopLeft; // Calc actual offset + rctSnapRef.Offset(sizeDelta); // Calc trial new position + rctSnapRef = AdjustRect(rctSnapRef); // Force onto grid. + sizeDelta = rctSnapRef.GetTopLeft() - pntSnapRefTopLeft; // Calc actual offset - if (sizeDelta.cx != 0 || sizeDelta.cy != 0) + if (sizeDelta.x != 0 || sizeDelta.y != 0) { // We still have to make sure the larger rect hasn't left the // playing area. - CRect rctObjs = pSLst->GetEnclosingRect(); - rctObjs += (CPoint)sizeDelta; // Calc trial new position + wxRect rctObjs = CB::Convert(pSLst->GetEnclosingRect()); + rctObjs.Offset(sizeDelta); // Calc trial new position BOOL bXOK, bYOK; if (!IsRectFullyOnBoard(rctObjs, &bXOK, &bYOK)) { - CRect temp = rctObjs; - LimitRect(temp); + wxRect temp = rctObjs; + temp = LimitRect(temp); // if enclosing rect can't fit on board, reject drop if (!IsRectFullyOnBoard(temp, &bXOK, &bYOK)) { - return pdi.m_phase == PhaseDrag::Over ? - reinterpret_cast(g_res.hcrNoDropTooBig) - : - -1; + if (pdi.m_phase == PhaseDrag::Over) + { + event.SetCursor(g_res.hcrNoDropTooBigWx); + } + return; } - sizeDelta += temp.TopLeft() - rctObjs.TopLeft(); + sizeDelta += temp.GetTopLeft() - rctObjs.GetTopLeft(); } - if (sizeDelta.cx != 0 || sizeDelta.cy != 0) // Check 'em again (what a pain!) - pSLst->Offset((CPoint)sizeDelta); + if (sizeDelta.x != 0 || sizeDelta.y != 0) // Check 'em again (what a pain!) + pSLst->Offset(CB::Convert(sizeDelta)); } - CRect rctObjs = pSLst->GetEnclosingRect(); - CPoint pntTopLeft = rctObjs.TopLeft(); + wxRect rctObjs = CB::Convert(pSLst->GetEnclosingRect()); + wxPoint pntTopLeft = rctObjs.GetTopLeft(); if (pdi.m_phase == PhaseDrag::Over || pdi.m_phase == PhaseDrag::Enter) { @@ -820,218 +1033,138 @@ LRESULT CPlayBoardView::DoDragSelectList(DragInfo& pdi) // Draw new drag image. pSLst->DrawTracker(pDC, trkMoving); } - ReleaseDC(&pDC); if (pdi.m_phase == PhaseDrag::Over) { - DragCheckAutoScroll(); - return (LRESULT)(LPVOID)pdi.m_hcsrSuggest; + event.SetCursor(pdi.m_hcsrSuggest); + return; } else if (pdi.m_phase == PhaseDrag::Drop) { - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); // Whoooopppp...Whoooopppp!!! Drop occurred here.... - DragKillAutoScroll(); std::vector> listObjs; pSLst->LoadTableWithObjectPtrs(listObjs, CSelList::otAll, FALSE); pSLst->PurgeList(FALSE); // Purge source list - pDoc->AssignNewMoveGroup(); - pDoc->PlaceObjectTableOnBoard(listObjs, rctObjs.TopLeft(), m_pPBoard.get()); + pDoc.AssignNewMoveGroup(); + pDoc.PlaceObjectTableOnBoard(listObjs, CB::Convert(rctObjs.GetTopLeft()), m_pPBoard.get()); m_selList.PurgeList(TRUE); // Purge former selections - if (!pDoc->HasPlayers() || !m_pPBoard->IsOwned() || + if (!pDoc.HasPlayers() || !m_pPBoard->IsOwned() || m_pPBoard->IsNonOwnerAccessAllowed() || - m_pPBoard->IsOwnedBy(pDoc->GetCurrentPlayerMask())) + m_pPBoard->IsOwnedBy(pDoc.GetCurrentPlayerMask())) { SelectAllObjectsInTable(listObjs); // Reselect on this board. } - CFrameWnd* pFrame = GetParentFrame(); - pFrame->SetActiveView(this); + CFrameWnd* pFrame = parent->GetParentFrame(); + pFrame->SetActiveView(&*parent); - pDoc->UpdateAllViews(this, HINT_UPDATESELECTLIST); + pDoc.UpdateAllViews(&*parent, HINT_UPDATESELECTLIST); NotifySelectListChange(); } - return 1; -} - -void CPlayBoardView::DragDoAutoScroll() -{ - CPoint ptBefore(0, 0); - ClientToWorkspace(ptBefore); - CDC *pDC = NULL; - - if (m_pDragSelList != NULL) - { - // Remove previous drag image. - pDC = GetDC(); - pDC->SaveDC(); - OnPrepareScaledDC(*pDC, TRUE); - m_pDragSelList->DrawTracker(*pDC, trkMoving); - pDC->RestoreDC(-1); - } - CPoint point; - GetCursorPos(&point); - ScreenToClient(&point); - BOOL bScrolled = ProcessAutoScroll(point); - if (m_pDragSelList != NULL && bScrolled) - { - CPoint ptAfter(0, 0); - ClientToWorkspace(ptAfter); - CSize sizeDelta = ptAfter - ptBefore; - if (sizeDelta.cx != 0 || sizeDelta.cy != 0) - { - // We still have to make sure the larger rect hasn't left the - // playing area. - CRect rctObjs = m_pDragSelList->GetEnclosingRect(); - rctObjs += (CPoint)sizeDelta; // Calc trial new position - BOOL bXOK, bYOK; - if (!IsRectFullyOnBoard(rctObjs, &bXOK, &bYOK)) - { - sizeDelta.cx = bXOK ? sizeDelta.cx : 0; - sizeDelta.cy = bYOK ? sizeDelta.cy : 0; - } - } - m_pDragSelList->Offset((CPoint)sizeDelta); - } - if (m_pDragSelList != NULL) - { - pDC->SaveDC(); - OnPrepareScaledDC(*pDC, TRUE); - // Restore drag image. - m_pDragSelList->DrawTracker(*pDC, trkMoving); - pDC->RestoreDC(-1); - } - if (pDC != NULL) - ReleaseDC(pDC); -} - -void CPlayBoardView::DragCheckAutoScroll() -{ - m_bInDrag = TRUE; - CPoint point; - GetCursorPos(&point); - ScreenToClient(&point); - if (CheckAutoScroll(point)) - { - if (m_nTimerID == uintptr_t(0)) - m_nTimerID = SetTimer(timerIDAutoScroll, timerAutoScroll, NULL); - } - else if (m_nTimerID != uintptr_t(0)) - { - if (m_nTimerID != uintptr_t(0)) - KillTimer(m_nTimerID); - m_nTimerID = uintptr_t(0); - } -} - -void CPlayBoardView::DragKillAutoScroll() -{ - m_bInDrag = FALSE; - m_pDragSelList = NULL; - if (m_nTimerID != uintptr_t(0)) - KillTimer(m_nTimerID); - m_nTimerID = uintptr_t(0); + event.SetResult(true); + return; } ///////////////////////////////////////////////////////////////////////////// -void CPlayBoardView::AddPiece(CPoint pnt, PieceID pid) +void CPlayBoardView::AddPiece(wxPoint pnt, PieceID pid) { - ASSERT(FALSE); //!!!!NO LONGER USED?!!!!! - GetDocument()->PlacePieceOnBoard(pnt, pid, m_pPBoard.get()); + wxASSERT(FALSE); //!!!!NO LONGER USED?!!!!! + GetDocument().PlacePieceOnBoard(CB::Convert(pnt), pid, m_pPBoard.get()); } ///////////////////////////////////////////////////////////////////////////// -void CPlayBoardView::OnPrepareScaledDC(CDC& pDC, BOOL bHonor180Flip) +void CPlayBoardView::OnPrepareScaledDC(wxDC& pDC, BOOL bHonor180Flip) { - OnPrepareDC(&pDC, NULL); + PrepareDC(pDC); PrepareScaledDC(pDC, NULL, bHonor180Flip); } -void CPlayBoardView::SetupDrawListDC(CDC& pDC, CRect& pRct) const +CPlayBoardView::DCSetupDrawListDC::DCSetupDrawListDC(const CPlayBoardView& rThis, wxDC& pDC, wxRect& pRct) { - if (m_nZoom == fullScale) + if (rThis.m_nZoom == fullScale) return; - pDC.SaveDC(); - PrepareScaledDC(pDC, &pRct); + double xScale, yScale; + pDC.GetUserScale(&xScale, &yScale); + scaleChanger = CB::DCUserScaleChanger(pDC, xScale, yScale); + logOrgChanger = CB::DCLogicalOriginChanger(pDC, pDC.GetLogicalOrigin()); + + rThis.PrepareScaledDC(pDC, &pRct); } -void CPlayBoardView::PrepareScaledDC(CDC& pDC, CRect* pRct, BOOL bHonor180Flip) const +void CPlayBoardView::PrepareScaledDC(wxDC& pDC, wxRect* pRct, BOOL bHonor180Flip) const { - CSize wsize, vsize; + wxSize wsize, vsize; m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(m_nZoom, wsize, vsize); - pDC.SetMapMode(MM_ANISOTROPIC); if (bHonor180Flip && m_pPBoard->IsBoardRotated180()) { - pDC.SetWindowExt(-wsize); - pDC.SetWindowOrg(wsize.cx, wsize.cy); + pDC.SetLogicalOrigin(wsize.x, wsize.y); + pDC.SetAxisOrientation(false, true); } - else - pDC.SetWindowExt(wsize); - pDC.SetViewportExt(vsize); + pDC.SetUserScale(double(vsize.x)/wsize.x, double(vsize.y)/wsize.y); if (pRct != NULL) ScaleRect(*pRct, wsize, vsize); } -void CPlayBoardView::RestoreDrawListDC(CDC& pDC) const -{ - if (m_nZoom != fullScale) - pDC.RestoreDC(-1); -} - ///////////////////////////////////////////////////////////////////////////// #ifdef _DEBUG -const CGamDoc* CPlayBoardView::GetDocument() const // non-debug version is inline +const CGamDoc& CPlayBoardView::GetDocument() const // non-debug version is inline { - const CGamDoc* retval = CB::ToCGamDoc(m_pDocument); - wxASSERT(retval); + const CGamDoc& retval = *document; return retval; } #endif //_DEBUG +CFrameWnd* CPlayBoardView::GetParentFrame() +{ + return parent->GetParentFrame(); +} + ///////////////////////////////////////////////////////////////////////////// // Right mouse button handler -void CPlayBoardView::OnContextMenu(CWnd* pWnd, CPoint point) +void CPlayBoardView::OnContextMenu(wxContextMenuEvent& event) { // Make sure window is active. GetParentFrame()->ActivateFrame(); - CMenu bar; - if (bar.LoadMenuW(IDR_MENU_PLAYER_POPUPS)) + std::unique_ptr bar(wxXmlResource::Get()->LoadMenuBar("IDR_MENU_PLAYER_POPUPS")); + if (bar) { - UINT nMenuNum; - if (GetDocument()->IsPlaying()) - nMenuNum = MENU_PV_PLAYMODE; - else if (GetDocument()->IsScenario()) - nMenuNum = MENU_PV_SCNMODE; + CB::string nMenuNum; + if (GetDocument().IsPlaying()) + nMenuNum = "1=PV_PLAYMODE"; + else if (GetDocument().IsScenario()) + nMenuNum = "2=PV_SCNMODE"; else - nMenuNum = MENU_PV_MOVEMODE; + nMenuNum = "0=PV_MOVEMODE"; - CMenu& popup = *bar.GetSubMenu(nMenuNum); - ASSERT(popup.m_hMenu != NULL); + int index = bar->FindMenu(nMenuNum); + wxASSERT(index != wxNOT_FOUND); + std::unique_ptr popup(bar->Remove(value_preserving_cast(index))); // Make sure we clean up even if exception is tossed. - TRY + try + { + PopupMenu(&*popup, ScreenToClient(event.GetPosition())); + } + catch (...) { - popup.TrackPopupMenu(TPM_RIGHTBUTTON, point.x, point.y, - AfxGetMainWnd()); // Route commands through main window - // Make sure command is dispatched BEFORE we clear m_bInRightMouse. - GetApp()->DispatchMessages(); + wxASSERT(!"exception"); } - END_TRY } } @@ -1041,62 +1174,80 @@ void CPlayBoardView::OnContextMenu(CWnd* pWnd, CPoint point) BOOL CPlayBoardView::IsBoardContentsAvailableToCurrentPlayer() const { if (m_pPBoard->IsNonOwnerAccessAllowed() || !m_pPBoard->IsOwned() || - GetDocument()->IsScenario()) + GetDocument().IsScenario()) return TRUE; - return m_pPBoard->IsOwnedBy(GetDocument()->GetCurrentPlayerMask()); + return m_pPBoard->IsOwnedBy(GetDocument().GetCurrentPlayerMask()); } -void CPlayBoardView::OnLButtonDown(UINT nFlags, CPoint point) +void CPlayBoardView::OnLButtonDown(wxMouseEvent& event) { if (!IsBoardContentsAvailableToCurrentPlayer()) { - CScrollView::OnLButtonDown(nFlags, point); + event.Skip(); return; } PToolType eToolType = MapToolType(m_nCurToolID); CPlayTool& pTool = CPlayTool::GetTool(eToolType); // Allow pieces to be selected even during playback - ClientToWorkspace(point); - pTool.OnLButtonDown(this, nFlags, point); + wxPoint point = ClientToWorkspace(event.GetPosition()); + pTool.OnLButtonDown(*this, event.GetModifiers(), point); } -void CPlayBoardView::OnMouseMove(UINT nFlags, CPoint point) +void CPlayBoardView::OnMouseMove(wxMouseEvent& event) { +#if 1 + int nMods = event.GetModifiers(); + wxPoint point = event.GetPosition(); if (!IsBoardContentsAvailableToCurrentPlayer()) { - CScrollView::OnMouseMove(nFlags, point); + event.Skip(); return; } DoToolTipHitProcessing(point); - if (!GetDocument()->IsPlaying()) + if (!GetDocument().IsPlaying()) { PToolType eToolType = MapToolType(m_nCurToolID); CPlayTool& pTool = CPlayTool::GetTool(eToolType); - ClientToWorkspace(point); - pTool.OnMouseMove(this, nFlags, point); + point = ClientToWorkspace(point); + pTool.OnMouseMove(*this, nMods, point); } else - CScrollView::OnMouseMove(nFlags, point); + event.Skip(); +#else + wxPoint client = event.GetPosition(); + wxPoint workspace = ClientToWorkspace(client); + CPP20_TRACE("client {}, wkspc {}\n", client, workspace); + wxOverlayDC dc(GetOverlay(), this); + OnPrepareScaledDC(dc, true); + dc.Clear(); + wxDCPenChanger setPen(dc, *wxBLACK_PEN); + wxDCBrushChanger setBrush(dc, *wxBLACK_BRUSH); + CB::DrawEllipse(dc, wxRect(wxPoint(workspace.x - 20, workspace.y - 20), + wxPoint(workspace.x + 20, workspace.y + 20))); + event.Skip(); +#endif } -void CPlayBoardView::OnLButtonUp(UINT nFlags, CPoint point) +void CPlayBoardView::OnLButtonUp(wxMouseEvent& event) { + int nMods = event.GetModifiers(); + wxPoint point = event.GetPosition(); if (!IsBoardContentsAvailableToCurrentPlayer()) { - CScrollView::OnLButtonUp(nFlags, point); + event.Skip(); return; } PToolType eToolType = MapToolType(m_nCurToolID); CPlayTool& pTool = CPlayTool::GetTool(eToolType); // Allow pieces to be selected even during playback - ClientToWorkspace(point); - bool rc = pTool.OnLButtonUp(this, nFlags, point); - ASSERT(rc || pTool.m_eToolType == ptypeSelect); + point = ClientToWorkspace(point); + bool rc = pTool.OnLButtonUp(*this, nMods, point); + wxASSERT(rc || pTool.m_eToolType == ptypeSelect); if (!rc && pTool.m_eToolType == ptypeSelect) { // failed drop messed up selection list, so rebuild it @@ -1107,111 +1258,131 @@ void CPlayBoardView::OnLButtonUp(UINT nFlags, CPoint point) } } -void CPlayBoardView::OnLButtonDblClk(UINT nFlags, CPoint point) +void CPlayBoardView::OnMouseCaptureLost(wxMouseCaptureLostEvent& event) +{ + PToolType eToolType = MapToolType(m_nCurToolID); + CPlayTool& pTool = CPlayTool::GetTool(eToolType); + pTool.OnMouseCaptureLost(*this); +} + +void CPlayBoardView::OnLButtonDblClk(wxMouseEvent& event) { + int nMods = event.GetModifiers(); + wxPoint point = event.GetPosition(); if (!IsBoardContentsAvailableToCurrentPlayer()) { - CScrollView::OnLButtonDblClk(nFlags, point); + event.Skip(); return; } - if (!GetDocument()->IsPlaying()) + if (!GetDocument().IsPlaying()) { PToolType eToolType = MapToolType(m_nCurToolID); CPlayTool& pTool = CPlayTool::GetTool(eToolType); - ClientToWorkspace(point); - pTool.OnLButtonDblClk(this, nFlags, point); + point = ClientToWorkspace(point); + pTool.OnLButtonDblClk(*this, nMods, point); } else - CScrollView::OnLButtonDblClk(nFlags, point); + event.Skip(); } -void CPlayBoardView::OnTimer(uintptr_t nIDEvent) +void CPlayBoardView::OnTimer(wxTimerEvent& event) { - if (m_nTimerID == nIDEvent) + if (!GetDocument().IsPlaying()) { - CPoint point; - GetCursorPos(&point); - ScreenToClient(&point); - if (!m_bInDrag || !CheckAutoScroll(point)) - { - KillTimer(m_nTimerID); - return; - } - DragDoAutoScroll(); - return; + PToolType eToolType = MapToolType(m_nCurToolID); + CPlayTool& pTool = CPlayTool::GetTool(eToolType); + pTool.OnTimer(*this, event.GetId()); } else { - if (!GetDocument()->IsPlaying()) - { - PToolType eToolType = MapToolType(m_nCurToolID); - CPlayTool& pTool = CPlayTool::GetTool(eToolType); - pTool.OnTimer(this, nIDEvent); - } - else - CScrollView::OnTimer(nIDEvent); + event.Skip(); } } -BOOL CPlayBoardView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) +void CPlayBoardView::OnSetCursor(wxSetCursorEvent& event) { - if (GetDocument()->IsPlaying()) - return CScrollView::OnSetCursor(pWnd, nHitTest, message); + if (GetDocument().IsPlaying()) + { + event.Skip(); + return; + } PToolType eToolType = MapToolType(m_nCurToolID); - if (pWnd == this && eToolType != ptypeUnknown) + if (event.GetEventObject() == this && eToolType != ptypeUnknown) { CPlayTool& pTool = CPlayTool::GetTool(eToolType); - if (pTool.OnSetCursor(this, nHitTest)) - return TRUE; + wxPoint point(event.GetX(), event.GetY()); + if (GetClientRect().Contains(point)) + { + point = ClientToWorkspace(point); + wxCursor rc = pTool.OnSetCursor(*this, point); + if (rc.IsOk()) + { + event.SetCursor(rc); + return; + } + } } - if (GetDocument()->IsRecordingCompoundMove()) + if (GetDocument().IsRecordingCompoundMove()) { - ::SetCursor(g_res.hcrCompMoveActive); - return TRUE; + event.SetCursor(g_res.hcrCompMoveActive); + return; } else - return CScrollView::OnSetCursor(pWnd, nHitTest, message); + { + event.Skip(); + return; + } } ////////////////////////////////////////////////////////////////////// -void CPlayBoardView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +void CPlayBoardView::OnChar(wxKeyEvent& event) { - CGamDoc* pDoc = GetDocument(); - if (!pDoc->IsPlaying()) + int nChar = event.GetKeyCode(); + CGamDoc& pDoc = GetDocument(); + if (!pDoc.IsPlaying()) { - if (nChar == VK_ESCAPE) + if (nChar == static_cast(WXK_ESCAPE)) { - if (pDoc->IsRecordingCompoundMove()) - pDoc->RecordCompoundMoveDiscard(); + if (pDoc.IsRecordingCompoundMove()) + pDoc.RecordCompoundMoveDiscard(); else if (m_pPBoard->GetPlotMoveMode()) OnActPlotDiscard(); else m_selList.PurgeList(TRUE); } - else if (nChar == VK_RETURN) + else if (nChar == static_cast(WXK_RETURN)) { - if (pDoc->IsRecordingCompoundMove()) - pDoc->RecordCompoundMoveEnd(); + if (pDoc.IsRecordingCompoundMove()) + pDoc.RecordCompoundMoveEnd(); else if (m_pPBoard->GetPlotMoveMode()) OnActPlotDone(); } } - CScrollView::OnChar(nChar, nRepCnt, nFlags); + event.Skip(); } -void CPlayBoardView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) +void CPlayBoardView::OnKeyDown(wxKeyEvent& event) { + int nChar = event.GetKeyCode(); if (!IsBoardContentsAvailableToCurrentPlayer()) return; - if (GetDocument()->IsPlaying()) + if (GetDocument().IsPlaying()) return; - if (nChar == VK_DELETE) + if (nChar == WXK_DELETE || + nChar == WXK_NUMPAD_DELETE) OnEditClear(); + + /* so other keys get to EVT_CHAR + (see https://docs.wxwidgets.org/stable/classwx_key_event.html) */ + else + { + event.Skip(); + } } ////////////////////////////////////////////////////////////////////// @@ -1221,127 +1392,121 @@ void CPlayBoardView::OnEditClear() if (!m_selList.HasMarkers()) return; // Nothing to do - ASSERT(!GetDocument()->IsPlaying() && m_selList.HasMarkers()); + wxASSERT(!GetDocument().IsPlaying() && m_selList.HasMarkers()); if (m_pPBoard->GetPlotMoveMode()) OnActPlotDiscard(); if (AfxMessageBox(IDS_WARN_DELETEMARKERS, MB_YESNO | MB_ICONQUESTION) != IDYES) return; - std::vector> listPtr; + std::vector> listPtr; m_selList.LoadTableWithObjectPtrs(listPtr, CSelList::otAll, FALSE); m_selList.PurgeList(TRUE); // Purge selections - GetDocument()->AssignNewMoveGroup(); - GetDocument()->DeleteObjectsInTable(listPtr); + GetDocument().AssignNewMoveGroup(); + GetDocument().DeleteObjectsInTable(listPtr); } -void CPlayBoardView::OnUpdateEditClear(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateEditClear(wxUpdateUIEvent& pCmdUI) { - pCmdUI->Enable(!GetDocument()->IsPlaying() && m_selList.HasMarkers()); + pCmdUI.Enable(!GetDocument().IsPlaying() && m_selList.HasMarkers()); } ////////////////////////////////////////////////////////////////////// -static PToolType tblTools[] = +PToolType CPlayBoardView::MapToolType(int nToolResID) const { - ptypeSelect, // ID_PTOOL_SELECT - ptypeLine, // ID_PTOOL_LINE - ptypeTextBox, // ID_PTOOL_TEXTBOX - ptypeMPlot, // ID_PTOOL_PLOTMOVE -}; - -PToolType CPlayBoardView::MapToolType(UINT nToolResID) const -{ - return tblTools[nToolResID - ID_PTOOL_SELECT]; + // wx doesn't guarantee XRCID() value order + static const std::unordered_map map { + { XRCID("ID_PTOOL_SELECT"), ptypeSelect }, + { XRCID("ID_PTOOL_LINE"), ptypeLine }, + { XRCID("ID_PTOOL_TEXTBOX"), ptypeTextBox }, + { XRCID("ID_PTOOL_PLOTMOVE"), ptypeMPlot }, + }; + return map.at(nToolResID); } ///////////////////////////////////////////////////////////////////////////// // CPlayBoardView message handlers -void CPlayBoardView::OnUpdateIndicatorCellNum(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateIndicatorCellNum(wxUpdateUIEvent& pCmdUI) { CBoardArray& pba = m_pPBoard->GetBoard()->GetBoardArray(); if (pba.GetCellNumTracking()) { - CPoint point; - GetCursorPos(&point); - ScreenToClient(&point); - CRect rct; - GetClientRect(&rct); - if (rct.PtInRect(point)) + wxPoint point = wxGetMouseState().GetPosition(); + point = ScreenToClient(point); + wxRect rct = GetClientRect(); + if (rct.Contains(point)) { - point += (CSize)GetDeviceScrollPosition(); - CB::string str = m_pPBoard->GetCellNumberStr(point, m_nZoom); - pCmdUI->Enable(); - pCmdUI->SetText(str); + point = CalcUnscrolledPosition(point); + CB::string str = m_pPBoard->GetCellNumberStr(CB::Convert(point), m_nZoom); + pCmdUI.Enable(true); + pCmdUI.SetText(str); } } } void CPlayBoardView::DoViewScaleBrd(TileScale nZoom) { - ASSERT(m_pPBoard != NULL); CBoard* pBoard = m_pPBoard->GetBoard(); - ASSERT(pBoard != NULL); + wxASSERT(pBoard != NULL); - CPoint pntMid; + wxPoint pntMid; if (m_selList.IsAnySelects()) { CRect rctSelection = m_selList.GetEnclosingRect(); - pntMid = rctSelection.CenterPoint(); + pntMid = CB::Convert(rctSelection.CenterPoint()); } else { - CRect rctClient; - GetClientRect(&rctClient); - pntMid = rctClient.CenterPoint(); - ClientToWorkspace(pntMid); + wxRect rctClient = GetClientRect(); + pntMid = GetMidRect(rctClient); + pntMid = ClientToWorkspace(pntMid); } m_nZoom = nZoom; SetOurScrollSizes(m_nZoom); - BeginWaitCursor(); - Invalidate(FALSE); + wxBusyCursor busyCursor; + Refresh(FALSE); CenterViewOnWorkspacePoint(pntMid); - UpdateWindow(); - EndWaitCursor(); + Update(); } -void CPlayBoardView::OnViewFullScaleBrd() +void CPlayBoardView::OnViewFullScaleBrd(wxCommandEvent& /*event*/) { DoViewScaleBrd(fullScale); } -void CPlayBoardView::OnUpdateViewFullScaleBrd(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateViewFullScaleBrd(wxUpdateUIEvent& pCmdUI) { - pCmdUI->SetCheck(m_nZoom == fullScale); + pCmdUI.Check(m_nZoom == fullScale); } -void CPlayBoardView::OnViewHalfScaleBrd() +void CPlayBoardView::OnViewHalfScaleBrd(wxCommandEvent& /*event*/) { DoViewScaleBrd(halfScale); } -void CPlayBoardView::OnUpdateViewHalfScaleBrd(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateViewHalfScaleBrd(wxUpdateUIEvent& pCmdUI) { - pCmdUI->SetCheck(m_nZoom == halfScale); + pCmdUI.Check(m_nZoom == halfScale); } -void CPlayBoardView::OnViewSmallScaleBoard() +void CPlayBoardView::OnViewSmallScaleBoard(wxCommandEvent& /*event*/) { DoViewScaleBrd(smallScale); } -void CPlayBoardView::OnUpdateViewSmallScaleBoard(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateViewSmallScaleBoard(wxUpdateUIEvent& pCmdUI) { - pCmdUI->SetCheck(m_nZoom == smallScale); + pCmdUI.Check(m_nZoom == smallScale); } -void CPlayBoardView::OnViewToggleScale() +void CPlayBoardView::OnViewToggleScale(wxCommandEvent& /*event*/) { - if (GetKeyState(VK_CONTROL) < 0) + if (wxGetKeyState(WXK_CONTROL)) { // Zoom out and around if (m_nZoom == fullScale) @@ -1363,47 +1528,51 @@ void CPlayBoardView::OnViewToggleScale() } } -void CPlayBoardView::OnUpdateViewToggleScale(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateViewToggleScale(wxUpdateUIEvent& pCmdUI) { - pCmdUI->Enable(TRUE); + pCmdUI.Enable(TRUE); } -void CPlayBoardView::OnViewBoardRotate180() +void CPlayBoardView::OnViewBoardRotate180(wxCommandEvent& /*event*/) { m_pPBoard->SetRotateBoard180(!m_pPBoard->IsBoardRotated180()); + if (m_nZoom == fullScale) + { + /* KLUDGE: without this, the wxDC soemtimes has the + wrong axis behavior */ + overlay = MakeOwner(); + } CGamDocHint hint; hint.GetArgs().m_pPBoard = m_pPBoard.get(); - GetDocument()->UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); + GetDocument().UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); } -void CPlayBoardView::OnUpdateViewBoardRotate180(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateViewBoardRotate180(wxUpdateUIEvent& pCmdUI) { - pCmdUI->SetCheck(m_pPBoard->IsBoardRotated180()); + pCmdUI.Check(m_pPBoard->IsBoardRotated180()); } -BOOL CPlayBoardView::OnPlayTool(UINT id) +void CPlayBoardView::OnPlayTool(wxCommandEvent& event) { - if (id !=ID_PTOOL_SELECT) + int id = event.GetId(); + if (id !=XRCID("ID_PTOOL_SELECT")) m_selList.PurgeList(TRUE); if (id != m_nCurToolID) { m_nCurToolID = id; } - return TRUE; } -void CPlayBoardView::OnUpdatePlayTool(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdatePlayTool(wxUpdateUIEvent& pCmdUI) { - // NOTE!!: The control ID's are assumed to be consecutive and - // in the same order as the tool codes defined in MAINFRM.C - if (GetDocument()->IsPlaying()) - pCmdUI->Enable(FALSE); + if (GetDocument().IsPlaying()) + pCmdUI.Enable(FALSE); else - pCmdUI->Enable(pCmdUI->m_nID == m_nCurToolID); - pCmdUI->SetCheck(pCmdUI->m_nID == m_nCurToolID); + pCmdUI.Enable(pCmdUI.GetId() == m_nCurToolID); + pCmdUI.Check(pCmdUI.GetId() == m_nCurToolID); } -void CPlayBoardView::OnActStack() +void CPlayBoardView::OnActStack(wxCommandEvent& /*event*/) { DoAutostackOfSelectedObjects(m_pPBoard->m_xStackStagger, m_pPBoard->m_yStackStagger); @@ -1411,97 +1580,97 @@ void CPlayBoardView::OnActStack() void CPlayBoardView::DoAutostackOfSelectedObjects(int xStagger, int yStagger) { - CRect rct = m_selList.GetPiecesEnclosingRect(); - if (rct.IsRectEmpty()) + wxRect rct = CB::Convert(m_selList.GetPiecesEnclosingRect()); + if (rct.IsEmpty()) return; - CPoint pntCenter(MidPnt(rct.left, rct.right), MidPnt(rct.top, rct.bottom)); + wxPoint pntCenter(MidPnt(rct.GetLeft(), rct.GetRight()), MidPnt(rct.GetTop(), rct.GetBottom())); std::vector> tblObjs; m_selList.LoadTableWithObjectPtrs(tblObjs, CSelList::otPiecesMarks, TRUE); m_selList.PurgeList(TRUE); // Purge former selections - GetDocument()->AssignNewMoveGroup(); - GetDocument()->PlaceObjectTableOnBoard(pntCenter, tblObjs, + GetDocument().AssignNewMoveGroup(); + GetDocument().PlaceObjectTableOnBoard(CB::Convert(pntCenter), tblObjs, xStagger, yStagger, m_pPBoard.get()); // Reselect the pieces. SelectAllObjectsInTable(tblObjs); // Reselect objects } -void CPlayBoardView::OnUpdateActStack(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActStack(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying()) - pCmdUI->Enable(FALSE); + if (GetDocument().IsPlaying()) + pCmdUI.Enable(FALSE); else - pCmdUI->Enable(m_selList.IsMultipleSelects()); + pCmdUI.Enable(m_selList.IsMultipleSelects()); } -void CPlayBoardView::OnActAutostackDeck() +void CPlayBoardView::OnActAutostackDeck(wxCommandEvent& /*event*/) { DoAutostackOfSelectedObjects(0, 0); } -void CPlayBoardView::OnUpdateActAutostackDeck(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActAutostackDeck(wxUpdateUIEvent& pCmdUI) { OnUpdateActStack(pCmdUI); } -void CPlayBoardView::OnActShuffleSelectedObjects() +void CPlayBoardView::OnActShuffleSelectedObjects(wxCommandEvent& /*event*/) { CRect rct = m_selList.GetPiecesEnclosingRect(); if (rct.IsRectEmpty()) return; - CGamDoc* pDoc = GetDocument(); // Shorthand pointer + CGamDoc& pDoc = GetDocument(); // Shorthand pointer CPoint pntCenter(MidPnt(rct.left, rct.right), MidPnt(rct.top, rct.bottom)); - std::vector> tblObjs; + std::vector> tblObjs; m_selList.LoadTableWithObjectPtrs(tblObjs, CSelList::otPiecesMarks, TRUE); m_selList.PurgeList(TRUE); // Purge former selections // Generate a shuffled index vector for the number of selected items - uint32_t nRandSeed = pDoc->GetRandomNumberSeed(); + uint32_t nRandSeed = pDoc.GetRandomNumberSeed(); size_t nNumIndices = tblObjs.size(); std::vector pnIndices = AllocateAndCalcRandomIndexVector(nNumIndices, nNumIndices, nRandSeed, &nRandSeed); - pDoc->SetRandomNumberSeed(nRandSeed); + pDoc.SetRandomNumberSeed(nRandSeed); // Create a shuffled table of objects... std::vector> tblRandObjs; tblRandObjs.reserve(tblObjs.size()); - for (int i = 0; i < value_preserving_cast(tblObjs.size()); i++) - tblRandObjs.push_back(tblObjs[value_preserving_cast(pnIndices[i])]); + for (size_t i = size_t(0); i < tblObjs.size(); i++) + tblRandObjs.emplace_back(&*tblObjs[value_preserving_cast(pnIndices[i])]); - pDoc->AssignNewMoveGroup(); + pDoc.AssignNewMoveGroup(); - if (pDoc->IsRecording()) + if (pDoc.IsRecording()) { // Insert a notification tip so there is some information // feedback during playback. CB::string strMsg = CB::string::Format(IDS_TIP_OBJS_SHUFFLED, tblRandObjs.size()); - pDoc->RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), + pDoc.RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), value_preserving_cast(pntCenter.x), value_preserving_cast(pntCenter.y)); } - pDoc->PlaceObjectTableOnBoard(tblRandObjs, m_pPBoard.get()); + pDoc.PlaceObjectTableOnBoard(tblRandObjs, m_pPBoard.get()); // Reselect the pieces. SelectAllObjectsInTable(tblRandObjs); // Reselect objects } -void CPlayBoardView::OnUpdateActShuffleSelectedObjects(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActShuffleSelectedObjects(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying()) - pCmdUI->Enable(FALSE); + if (GetDocument().IsPlaying()) + pCmdUI.Enable(FALSE); else - pCmdUI->Enable(m_selList.IsMultipleSelects()); + pCmdUI.Enable(m_selList.IsMultipleSelects()); } -void CPlayBoardView::OnActToFront() +void CPlayBoardView::OnActToFront(wxCommandEvent& /*event*/) { CRect rct = m_selList.GetEnclosingRect(); if (rct.IsRectEmpty()) @@ -1512,22 +1681,22 @@ void CPlayBoardView::OnActToFront() m_selList.PurgeList(TRUE); // Purge former selections - GetDocument()->AssignNewMoveGroup(); - GetDocument()->PlaceObjectTableOnBoard(listObjs, rct.TopLeft(), + GetDocument().AssignNewMoveGroup(); + GetDocument().PlaceObjectTableOnBoard(listObjs, rct.TopLeft(), m_pPBoard.get(), placeTop); SelectAllObjectsInTable(listObjs); // Reselect pieces } -void CPlayBoardView::OnUpdateActToFront(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActToFront(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying()) - pCmdUI->Enable(FALSE); + if (GetDocument().IsPlaying()) + pCmdUI.Enable(FALSE); else - pCmdUI->Enable(m_selList.IsAnySelects()); + pCmdUI.Enable(m_selList.IsAnySelects()); } -void CPlayBoardView::OnActToBack() +void CPlayBoardView::OnActToBack(wxCommandEvent& /*event*/) { CRect rct = m_selList.GetEnclosingRect(); if (rct.IsRectEmpty()) @@ -1538,104 +1707,107 @@ void CPlayBoardView::OnActToBack() m_selList.PurgeList(TRUE); // Purge former selections - GetDocument()->AssignNewMoveGroup(); - GetDocument()->PlaceObjectTableOnBoard(listObjs, rct.TopLeft(), + GetDocument().AssignNewMoveGroup(); + GetDocument().PlaceObjectTableOnBoard(listObjs, rct.TopLeft(), m_pPBoard.get(), placeBack); SelectAllObjectsInTable(listObjs); // Reselect pieces } -void CPlayBoardView::OnUpdateActToBack(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActToBack(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying()) - pCmdUI->Enable(FALSE); + if (GetDocument().IsPlaying()) + pCmdUI.Enable(FALSE); else - pCmdUI->Enable(m_selList.IsAnySelects()); + pCmdUI.Enable(m_selList.IsAnySelects()); } -BOOL CPlayBoardView::OnActTurnOver(UINT id) +void CPlayBoardView::OnActTurnOver(wxCommandEvent& event) { CPieceTable::Flip flip; - switch (id) + if (event.GetId() == XRCID("ID_ACT_TURNOVER")) { - case ID_ACT_TURNOVER: - flip = CPieceTable::fNext; - break; - case ID_ACT_TURNOVER_PREV: - flip = CPieceTable::fPrev; - break; - case ID_ACT_TURNOVER_RANDOM: - flip = CPieceTable::fRandom; - break; - default: - AfxThrowInvalidArgException(); + flip = CPieceTable::fNext; + } + else if (event.GetId() == XRCID("ID_ACT_TURNOVER_PREV")) + { + flip = CPieceTable::fPrev; + } + else if (event.GetId() == XRCID("ID_ACT_TURNOVER_RANDOM")) + { + flip = CPieceTable::fRandom; + } + else + { + throw std::invalid_argument("unknown command id"); } std::vector> listObjs; m_selList.LoadTableWithObjectPtrs(listObjs, CSelList::otAll, FALSE); - CPoint pntCenter; + wxPoint pntCenter; if (flip == CPieceTable::fRandom) { - CRect rct = m_selList.GetPiecesEnclosingRect(FALSE); - ASSERT(!rct.IsRectEmpty()); - pntCenter = CPoint(MidPnt(rct.left, rct.right), MidPnt(rct.top, rct.bottom)); + wxRect rct = CB::Convert(m_selList.GetPiecesEnclosingRect(FALSE)); + wxASSERT(!rct.IsEmpty()); + pntCenter = GetMidRect(rct); } m_selList.PurgeList(TRUE); // Purge former selections - CGamDoc* pDoc = GetDocument(); - pDoc->AssignNewMoveGroup(); + CGamDoc& pDoc = GetDocument(); + pDoc.AssignNewMoveGroup(); - if (pDoc->IsRecording() && flip == CPieceTable::fRandom) + if (pDoc.IsRecording() && flip == CPieceTable::fRandom) { // Insert a notification tip so there is some information // feedback during playback. CB::string strMsg = CB::string::LoadString(IDS_TIP_FLIP_RANDOM); - pDoc->RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), - value_preserving_cast(pntCenter.x), value_preserving_cast(pntCenter.y)); + pDoc.RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), + pntCenter.x, pntCenter.y); } - pDoc->InvertPlayingPieceTableOnBoard(listObjs, *m_pPBoard, flip); + pDoc.InvertPlayingPieceTableOnBoard(listObjs, *m_pPBoard, flip); SelectAllObjectsInTable(listObjs); // Reselect pieces - - return true; } -void CPlayBoardView::OnUpdateActTurnOver(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActTurnOver(wxUpdateUIEvent& pCmdUI) { bool bEnabled = false; - CGamDoc* pDoc = GetDocument(); - if (pDoc->IsPlaying() || !pDoc->IsScenario() && - m_selList.HasOwnedPiecesNotMatching(pDoc->GetCurrentPlayerMask())) + CGamDoc& pDoc = GetDocument(); + if (pDoc.IsPlaying() || !pDoc.IsScenario() && + m_selList.HasOwnedPiecesNotMatching(pDoc.GetCurrentPlayerMask())) bEnabled = false; else bEnabled = m_selList.HasFlippablePieces(); - pCmdUI->Enable(bEnabled); + pCmdUI.Enable(bEnabled); +#if 0 if (pCmdUI->m_pSubMenu != NULL) { // Need to handle menu that the submenu is connected to. pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex, MF_BYPOSITION | (bEnabled ? MF_ENABLED : (MF_DISABLED | MF_GRAYED))); } +#endif } -void CPlayBoardView::OnActPlotMove() +void CPlayBoardView::OnActPlotMove(wxCommandEvent& /*event*/) { // Do this call so we don't record the plot list in the // restoration record. - GetDocument()->CreateRecordListIfRequired(); + GetDocument().CreateRecordListIfRequired(); // Ok...finish plot setup m_pPBoard->SetPlotMoveMode(TRUE); m_pPBoard->InitPlotStartPoint(); - m_nCurToolID = ID_PTOOL_PLOTMOVE; + m_nCurToolID = XRCID("ID_PTOOL_PLOTMOVE"); } -void CPlayBoardView::OnUpdateActPlotMove(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActPlotMove(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying() || (!m_selList.HasPieces() && - !m_selList.HasMarkers()) || GetDocument()->IsScenario()) + if (GetDocument().IsPlaying() || (!m_selList.HasPieces() && + !m_selList.HasMarkers()) || GetDocument().IsScenario()) { +#if 0 if (pCmdUI->m_pSubMenu != NULL) { pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex, @@ -1643,103 +1815,109 @@ void CPlayBoardView::OnUpdateActPlotMove(CCmdUI* pCmdUI) } else pCmdUI->Enable(FALSE); +#else + pCmdUI.Enable(FALSE); +#endif return; } +#if 0 else if (pCmdUI->m_pSubMenu != NULL) { pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex, MF_BYPOSITION | MF_ENABLED); } +#endif - pCmdUI->Enable(!m_pPBoard->GetPlotMoveMode()); - pCmdUI->SetCheck(m_pPBoard->GetPlotMoveMode()); + pCmdUI.Enable(!m_pPBoard->GetPlotMoveMode()); + pCmdUI.Check(m_pPBoard->GetPlotMoveMode()); } void CPlayBoardView::OnActPlotDone() { if (m_pPBoard->GetPrevPlotPoint() != CPoint(-1, -1)) { - CRect rct = m_selList.GetPiecesEnclosingRect(); - CPoint ptPrev = m_pPBoard->GetPrevPlotPoint(); - ptPrev -= CSize(rct.Width() / 2, rct.Height() / 2); - AdjustPoint(ptPrev); + wxRect rct = CB::Convert(m_selList.GetPiecesEnclosingRect()); + wxPoint ptPrev = CB::Convert(m_pPBoard->GetPrevPlotPoint()); + ptPrev -= wxSize(rct.GetWidth() / 2, rct.GetHeight() / 2); + ptPrev = AdjustPoint(ptPrev); std::vector> listObjs; m_selList.LoadTableWithObjectPtrs(listObjs, CSelList::otAll, FALSE); m_selList.PurgeList(TRUE); - GetDocument()->AssignNewMoveGroup(); + GetDocument().AssignNewMoveGroup(); // Note that PlaceObjectListOnBoard() automatically detects the // plotted move case and records that fact. - GetDocument()->PlaceObjectTableOnBoard(listObjs, ptPrev, m_pPBoard.get()); + GetDocument().PlaceObjectTableOnBoard(listObjs, CB::Convert(ptPrev), m_pPBoard.get()); m_selList.PurgeList(TRUE); // Purge former selections SelectAllObjectsInTable(listObjs); // Select on this board. } m_pPBoard->SetPlotMoveMode(FALSE); - GetDocument()->UpdateAllBoardIndicators(*m_pPBoard); + GetDocument().UpdateAllBoardIndicators(*m_pPBoard); m_pPBoard->FlushAllIndicators(); - m_nCurToolID = ID_PTOOL_SELECT; + m_nCurToolID = XRCID("ID_PTOOL_SELECT"); } -void CPlayBoardView::OnUpdateActPlotDone(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActPlotDone(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying() || GetDocument()->IsScenario()) + if (GetDocument().IsPlaying() || GetDocument().IsScenario()) { - pCmdUI->Enable(FALSE); + pCmdUI.Enable(FALSE); return; } - pCmdUI->Enable(m_pPBoard->GetPlotMoveMode()); + pCmdUI.Enable(m_pPBoard->GetPlotMoveMode()); } void CPlayBoardView::OnActPlotDiscard() { m_pPBoard->SetPlotMoveMode(FALSE); - GetDocument()->UpdateAllBoardIndicators(*m_pPBoard); + GetDocument().UpdateAllBoardIndicators(*m_pPBoard); m_pPBoard->FlushAllIndicators(); - m_nCurToolID = ID_PTOOL_SELECT; + m_nCurToolID = XRCID("ID_PTOOL_SELECT"); } -void CPlayBoardView::OnUpdateActPlotDiscard(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActPlotDiscard(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying() || GetDocument()->IsScenario()) + if (GetDocument().IsPlaying() || GetDocument().IsScenario()) { - pCmdUI->Enable(FALSE); + pCmdUI.Enable(FALSE); return; } - pCmdUI->Enable(m_pPBoard->GetPlotMoveMode()); + pCmdUI.Enable(m_pPBoard->GetPlotMoveMode()); } -void CPlayBoardView::OnViewSnapGrid() +void CPlayBoardView::OnViewSnapGrid(wxCommandEvent& /*event*/) { m_pPBoard->m_bGridSnap = !m_pPBoard->m_bGridSnap; } -void CPlayBoardView::OnUpdateViewSnapGrid(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateViewSnapGrid(wxUpdateUIEvent& pCmdUI) { - pCmdUI->Enable(!GetDocument()->IsPlaying()); - pCmdUI->SetCheck(m_pPBoard->m_bGridSnap); + pCmdUI.Enable(!GetDocument().IsPlaying()); + pCmdUI.Check(m_pPBoard->m_bGridSnap); } -void CPlayBoardView::OnEditSelAllMarkers() +void CPlayBoardView::OnEditSelAllMarkers(wxCommandEvent& /*event*/) { SelectAllMarkers(); } -void CPlayBoardView::OnUpdateEditSelAllMarkers(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateEditSelAllMarkers(wxUpdateUIEvent& pCmdUI) { CDrawList* pDwg = m_pPBoard->GetPieceList(); - ASSERT(pDwg); - pCmdUI->Enable(!GetDocument()->IsPlaying() && pDwg->HasMarker()); + wxASSERT(pDwg); + pCmdUI.Enable(!GetDocument().IsPlaying() && pDwg->HasMarker()); } +#if 0 void CPlayBoardView::OnActRotate() // ** TEST CODE ** // { std::vector tbl; - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); m_selList.LoadTableWithPieceIDs(tbl); - TileID tid = pDoc->GetPieceTable().GetActiveTileID(tbl.front()); - CTile tile = pDoc->GetTileManager().GetTile(tid); + TileID tid = pDoc.GetPieceTable().GetActiveTileID(tbl.front()); + CTile tile = pDoc.GetTileManager().GetTile(tid); OwnerPtr bmap = tile.CreateBitmapOfTile(); wxASSERT(!"dead code"); #if 0 @@ -1752,13 +1930,14 @@ void CPlayBoardView::OnActRotate() // ** TEST CODE ** // void CPlayBoardView::OnUpdateActRotate(CCmdUI* pCmdUI) // ** TEST CODE ** // { - CGamDoc* pDoc = GetDocument(); - if (pDoc->IsPlaying() || m_pPBoard->GetPlotMoveMode() || !pDoc->IsScenario() && - m_selList.HasOwnedPiecesNotMatching(pDoc->GetCurrentPlayerMask())) + CGamDoc& pDoc = GetDocument(); + if (pDoc.IsPlaying() || m_pPBoard->GetPlotMoveMode() || !pDoc.IsScenario() && + m_selList.HasOwnedPiecesNotMatching(pDoc.GetCurrentPlayerMask())) pCmdUI->Enable(FALSE); else pCmdUI->Enable(m_selList.HasPieces()); } +#endif /////////////////////////////////////////////////////////////////////// // Handle rotation requests. The ID's for tile rotations @@ -1766,61 +1945,61 @@ void CPlayBoardView::OnUpdateActRotate(CCmdUI* pCmdUI) // ** TEST CODE ** // // five degree increments. For example: if ID_ACT_ROTATE_0 is 42000, then // ID_ACT_ROTATE_90 must be 42009. This makes the angle easy to compute. -void CPlayBoardView::OnRotatePiece(UINT nID) +void CPlayBoardView::OnRotatePiece(wxCommandEvent& event) { - uint16_t nFacing5DegCW = value_preserving_cast(nID - ID_ACT_ROTATE_0); + int nFacingDegCW = GetRotateMap().at(event.GetId()); std::vector> listObjs; m_selList.LoadTableWithObjectPtrs(listObjs, CSelList::otAll, FALSE); m_selList.PurgeList(TRUE); // Purge former selections - GetDocument()->AssignNewMoveGroup(); - GetDocument()->ChangePlayingPieceFacingTableOnBoard(listObjs, m_pPBoard.get(), - uint16_t(5) * nFacing5DegCW); // Convert to degrees + GetDocument().AssignNewMoveGroup(); + GetDocument().ChangePlayingPieceFacingTableOnBoard(listObjs, m_pPBoard.get(), + value_preserving_cast(nFacingDegCW)); SelectAllObjectsInTable(listObjs); // Reselect pieces } -void CPlayBoardView::OnUpdateRotatePiece(CCmdUI* pCmdUI, UINT nID) +void CPlayBoardView::OnUpdateRotatePiece(wxUpdateUIEvent& pCmdUI) { - CGamDoc* pDoc = GetDocument(); - BOOL bEnabled = (m_selList.HasPieces() || m_selList.HasMarkers()) && !pDoc->IsPlaying(); - if (bEnabled && !pDoc->IsScenario() && - m_selList.HasOwnedPiecesNotMatching(pDoc->GetCurrentPlayerMask())) + CGamDoc& pDoc = GetDocument(); + BOOL bEnabled = (m_selList.HasPieces() || m_selList.HasMarkers()) && !pDoc.IsPlaying(); + if (bEnabled && !pDoc.IsScenario() && + m_selList.HasOwnedPiecesNotMatching(pDoc.GetCurrentPlayerMask())) { bEnabled = FALSE; } +#if 0 if (pCmdUI->m_pSubMenu != NULL) { // Need to handle menu that the submenu is connected to. pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex, MF_BYPOSITION | (bEnabled ? MF_ENABLED : (MF_DISABLED | MF_GRAYED))); } - pCmdUI->Enable(bEnabled); +#endif + pCmdUI.Enable(bEnabled); } /////////////////////////////////////////////////////////////////////// // This method handles messages typically sent by the tiny map view. // WPARAM = POINT* -LRESULT CPlayBoardView::OnMessageCenterBoardOnPoint(WPARAM wParam, LPARAM lParam) +void CPlayBoardView::OnMessageCenterBoardOnPoint(CenterBoardOnPointEvent& event) { - CPoint pnt = *((POINT*)wParam); - CenterViewOnWorkspacePoint(pnt); - return (LRESULT)0; + CenterViewOnWorkspacePoint(event.GetPoint()); } /////////////////////////////////////////////////////////////////////// // This method handles notifications of changes of relative piece // rotation sent from the CRotatePieceDialog dialog. -LRESULT CPlayBoardView::OnMessageRotateRelative(WPARAM wParam, LPARAM lParam) +void CPlayBoardView::OnMessageRotateRelative(RotatePieceDeltaEvent& event) { - CGamDoc* pDoc = GetDocument(); - int nRelativeRotation = (int)wParam; - ASSERT(!m_tblCurPieces.empty()); - ASSERT(m_tblCurAngles.size() == m_tblCurPieces.size()); + CGamDoc& pDoc = GetDocument(); + int nRelativeRotation = event.GetDelta(); + wxASSERT(!m_tblCurPieces.empty()); + wxASSERT(m_tblCurAngles.size() == m_tblCurPieces.size()); for (size_t i = size_t(0) ; i < m_tblCurPieces.size() ; ++i) { @@ -1830,28 +2009,27 @@ LRESULT CPlayBoardView::OnMessageRotateRelative(WPARAM wParam, LPARAM lParam) CDrawObj& pDObj = *m_tblCurPieces[i]; if (pDObj.GetType() == CDrawObj::drawPieceObj) - pDoc->ChangePlayingPieceFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), value_preserving_cast(nAngle)); + pDoc.ChangePlayingPieceFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), value_preserving_cast(nAngle)); else if (pDObj.GetType() == CDrawObj::drawMarkObj) - pDoc->ChangeMarkerFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), value_preserving_cast(nAngle)); + pDoc.ChangeMarkerFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), value_preserving_cast(nAngle)); if (m_bWheelRotation && (pDObj.GetType() == CDrawObj::drawPieceObj || pDObj.GetType() == CDrawObj::drawMarkObj)) { // Calculate new rotated mid-point for object. - CPoint pntRotate = RotatePointAroundPoint(m_pntWheelMid, - CPoint(m_tblXMidPnt[value_preserving_cast(i)], m_tblYMidPnt[value_preserving_cast(i)]), nRelativeRotation); - CSize sizeDelta = pntRotate - GetMidRect(pDObj.GetEnclosingRect()); - pDoc->PlaceObjectOnBoard(m_pPBoard.get(), &pDObj, sizeDelta); + wxPoint pntRotate = RotatePointAroundPoint(m_pntWheelMid, + m_tblMidPnt[i], nRelativeRotation); + wxPoint sizeDelta = pntRotate - GetMidRect(CB::Convert(pDObj.GetEnclosingRect())); + pDoc.PlaceObjectOnBoard(m_pPBoard.get(), &pDObj, CB::Convert(sizeDelta)); } } - return (LRESULT)0; } -void CPlayBoardView::OnActRotateRelative() +void CPlayBoardView::OnActRotateRelative(wxCommandEvent& /*event*/) { DoRotateRelative(FALSE); } -void CPlayBoardView::OnActRotateGroupRelative() +void CPlayBoardView::OnActRotateGroupRelative(wxCommandEvent& /*event*/) { DoRotateRelative(TRUE); } @@ -1861,19 +2039,18 @@ void CPlayBoardView::DoRotateRelative(BOOL bWheelRotation) m_bWheelRotation = bWheelRotation; CRotatePieceDialog dlg(*this); - CGamDoc* pDoc = GetDocument(); - CPieceTable& pPTbl = pDoc->GetPieceTable(); + CGamDoc& pDoc = GetDocument(); + CPieceTable& pPTbl = pDoc.GetPieceTable(); // Get a list of the selected pieces and save their current // rotations. m_tblCurAngles.clear(); m_tblCurPieces.clear(); - m_tblXMidPnt.RemoveAll(); - m_tblYMidPnt.RemoveAll(); + m_tblMidPnt.clear(); m_selList.LoadTableWithObjectPtrs(m_tblCurPieces, CSelList::otAll, FALSE); - CRect rctGroupRect = m_selList.GetPiecesEnclosingRect(); + wxRect rctGroupRect = CB::Convert(m_selList.GetPiecesEnclosingRect()); m_pntWheelMid = GetMidRect(rctGroupRect); for (size_t i = size_t(0) ; i < m_tblCurPieces.size() ; ++i) @@ -1892,9 +2069,8 @@ void CPlayBoardView::DoRotateRelative(BOOL bWheelRotation) if (m_bWheelRotation && (pDObj.GetType() == CDrawObj::drawPieceObj || pDObj.GetType() == CDrawObj::drawMarkObj)) { - CPoint midPoint = GetMidRect(pDObj.GetEnclosingRect()); - m_tblXMidPnt.Add((UINT)midPoint.x); - m_tblYMidPnt.Add((UINT)midPoint.y); + wxPoint midPoint = GetMidRect(CB::Convert(pDObj.GetEnclosingRect())); + m_tblMidPnt.push_back(midPoint); } } // If we're recording moves right now, suspend it for the moment. @@ -1920,7 +2096,7 @@ void CPlayBoardView::DoRotateRelative(BOOL bWheelRotation) private: CGamDoc& doc; BOOL bRecording = doc.IsRecording(); - } suspendRecording(*pDoc); + } suspendRecording(pDoc); // Show the rotation dialog nDlgResult = dlg.ShowModal(); @@ -1931,21 +2107,21 @@ void CPlayBoardView::DoRotateRelative(BOOL bWheelRotation) CDrawObj& pDObj = *m_tblCurPieces[i]; if (pDObj.GetType() == CDrawObj::drawPieceObj) { - pDoc->ChangePlayingPieceFacingOnBoard(static_cast(pDObj), + pDoc.ChangePlayingPieceFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), m_tblCurAngles[i]); } else if (pDObj.GetType() == CDrawObj::drawMarkObj) { - pDoc->ChangeMarkerFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), + pDoc.ChangeMarkerFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), m_tblCurAngles[i]); } if (m_bWheelRotation && (pDObj.GetType() == CDrawObj::drawPieceObj || pDObj.GetType() == CDrawObj::drawMarkObj)) { // Restore original position - CSize sizeDelta = CPoint(m_tblXMidPnt[value_preserving_cast(i)], m_tblYMidPnt[value_preserving_cast(i)]) - - GetMidRect(pDObj.GetEnclosingRect()); - pDoc->PlaceObjectOnBoard(m_pPBoard.get(), &pDObj, sizeDelta); + wxPoint sizeDelta = m_tblMidPnt[i] - + GetMidRect(CB::Convert(pDObj.GetEnclosingRect())); + pDoc.PlaceObjectOnBoard(m_pPBoard.get(), &pDObj, CB::Convert(sizeDelta)); } } // Restore recording mode if it was active. @@ -1953,7 +2129,7 @@ void CPlayBoardView::DoRotateRelative(BOOL bWheelRotation) if (nDlgResult == wxID_OK) { // Rotation was accepted. Make the final changes. - pDoc->AssignNewMoveGroup(); + pDoc.AssignNewMoveGroup(); for (size_t i = size_t(0) ; i < m_tblCurPieces.size() ; ++i) { int nAngle = m_tblCurAngles[i] + dlg.m_nRelativeRotation; @@ -1964,242 +2140,247 @@ void CPlayBoardView::DoRotateRelative(BOOL bWheelRotation) if (pDObj.GetType() == CDrawObj::drawPieceObj) { - pDoc->ChangePlayingPieceFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), value_preserving_cast(nAngle)); + pDoc.ChangePlayingPieceFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), value_preserving_cast(nAngle)); } else if (pDObj.GetType() == CDrawObj::drawMarkObj) { - pDoc->ChangeMarkerFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), value_preserving_cast(nAngle)); + pDoc.ChangeMarkerFacingOnBoard(static_cast(pDObj), m_pPBoard.get(), value_preserving_cast(nAngle)); } if (m_bWheelRotation && (pDObj.GetType() == CDrawObj::drawPieceObj || pDObj.GetType() == CDrawObj::drawMarkObj)) { // Calculate new rotated mid-point for object. - CPoint pntRotate = RotatePointAroundPoint(m_pntWheelMid, - CPoint(m_tblXMidPnt[value_preserving_cast(i)], m_tblYMidPnt[value_preserving_cast(i)]), dlg.m_nRelativeRotation); - CSize sizeDelta = pntRotate - GetMidRect(pDObj.GetEnclosingRect()); - pDoc->PlaceObjectOnBoard(m_pPBoard.get(), &pDObj, sizeDelta); + wxPoint pntRotate = RotatePointAroundPoint(m_pntWheelMid, + m_tblMidPnt[i], dlg.m_nRelativeRotation); + wxPoint sizeDelta = pntRotate - GetMidRect(CB::Convert(pDObj.GetEnclosingRect())); + pDoc.PlaceObjectOnBoard(m_pPBoard.get(), &pDObj, CB::Convert(sizeDelta)); } } m_selList.UpdateObjects(TRUE, FALSE); // Make sure we erase old handles. - rctGroupRect.InflateRect(16, 16); - InvalidateRect(rctGroupRect, FALSE); + rctGroupRect.Inflate(16, 16); + RefreshRect(rctGroupRect, FALSE); } m_tblCurAngles.clear(); m_tblCurPieces.clear(); - m_tblXMidPnt.RemoveAll(); - m_tblYMidPnt.RemoveAll(); + m_tblMidPnt.clear(); } -void CPlayBoardView::OnUpdateActRotateRelative(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActRotateRelative(wxUpdateUIEvent& pCmdUI) { - CGamDoc* pDoc = GetDocument(); - if (pDoc->IsPlaying() || !pDoc->IsScenario() && - m_selList.HasOwnedPiecesNotMatching(pDoc->GetCurrentPlayerMask())) - pCmdUI->Enable(FALSE); + CGamDoc& pDoc = GetDocument(); + if (pDoc.IsPlaying() || !pDoc.IsScenario() && + m_selList.HasOwnedPiecesNotMatching(pDoc.GetCurrentPlayerMask())) + pCmdUI.Enable(FALSE); else - pCmdUI->Enable(m_selList.HasPieces() || m_selList.HasMarkers()); + pCmdUI.Enable(m_selList.HasPieces() || m_selList.HasMarkers()); } -void CPlayBoardView::OnUpdateActRotateGroupRelative(CCmdUI *pCmdUI) +void CPlayBoardView::OnUpdateActRotateGroupRelative(wxUpdateUIEvent& pCmdUI) { - CGamDoc* pDoc = GetDocument(); - if (pDoc->IsPlaying() || !pDoc->IsScenario() && - m_selList.HasOwnedPiecesNotMatching(pDoc->GetCurrentPlayerMask())) - pCmdUI->Enable(FALSE); + CGamDoc& pDoc = GetDocument(); + if (pDoc.IsPlaying() || !pDoc.IsScenario() && + m_selList.HasOwnedPiecesNotMatching(pDoc.GetCurrentPlayerMask())) + pCmdUI.Enable(FALSE); else { - pCmdUI->Enable(m_selList.IsMultipleSelects() && + pCmdUI.Enable(m_selList.IsMultipleSelects() && (m_selList.HasPieces() || m_selList.HasMarkers())); } } /////////////////////////////////////////////////////////////////////// -void CPlayBoardView::OnViewPieces() +void CPlayBoardView::OnViewPieces(wxCommandEvent& /*event*/) { - GetPlayBoard()->SetPiecesVisible(!GetPlayBoard()->GetPiecesVisible()); + GetPlayBoard().SetPiecesVisible(!GetPlayBoard().GetPiecesVisible()); CGamDocHint hint; hint.GetArgs().m_pPBoard = m_pPBoard.get(); - GetDocument()->UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); + GetDocument().UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); } -void CPlayBoardView::OnUpdateViewPieces(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateViewPieces(wxUpdateUIEvent& pCmdUI) { - pCmdUI->SetCheck(!GetPlayBoard()->GetPiecesVisible()); + pCmdUI.Check(!GetPlayBoard().GetPiecesVisible()); } /////////////////////////////////////////////////////////////////////// -void CPlayBoardView::OnEditCopy() +void CPlayBoardView::OnEditCopy(wxCommandEvent& /*event*/) { CBoard* pBoard = m_pPBoard->GetBoard(); - CWindowDC scrnDC(this); - CSize size = pBoard->GetSize(m_nZoom); + wxSize size = CB::Convert(pBoard->GetSize(m_nZoom)); - OwnerPtr bmap = CDib::CreateDIBSection(size.cx, size.cy); - CDC dcMem; - dcMem.CreateCompatibleDC(&scrnDC); - CBitmap* pPrvBMap = (CBitmap*)dcMem.SelectObject(&*bmap); + wxBitmap bmap(size.x, size.y); + { + wxMemoryDC dcMem; + dcMem.SelectObject(bmap); - CRect rct(0, 0, size.cx, size.cy); + wxRect rct(wxPoint(0, 0), size); // Draw base board image... pBoard->Draw(dcMem, rct, m_nZoom, m_pPBoard->m_bCellBorders); // Draw pieces etc..... - SetupDrawListDC(dcMem, rct); - m_pPBoard->Draw(dcMem, &rct, m_nZoom); - RestoreDrawListDC(dcMem); + DCSetupDrawListDC setupDrawListDC(*this, dcMem, rct); + m_pPBoard->Draw(dcMem, rct, m_nZoom); - GdiFlush(); - dcMem.SelectObject(pPrvBMap); + } LockWxClipboard lockClipbd(std::try_to_lock); if (lockClipbd) { wxBusyCursor busyCursor; - wxImage img = ToImage(*bmap); - wxBitmap wxbmp(img); - wxTheClipboard->SetData(new wxBitmapDataObject(wxbmp)); + wxTheClipboard->SetData(new wxBitmapDataObject(bmap)); } } -void CPlayBoardView::OnEditBoardToFile() +void CPlayBoardView::OnEditBoardToFile(wxCommandEvent& /*event*/) { CB::string strFilter = CB::string::LoadString(IDS_BMP_FILTER); CB::string strTitle = CB::string::LoadString(IDS_SEL_BITMAPFILE); - CFileDialog dlg(FALSE, "bmp"_cbstring, NULL, OFN_HIDEREADONLY | - OFN_OVERWRITEPROMPT, strFilter, NULL, 0); - dlg.m_ofn.lpstrTitle = strTitle; + wxFileDialog dlg(this, strTitle, + wxEmptyString, wxEmptyString, + strFilter, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT); - if (dlg.DoModal() != IDOK) + if (dlg.ShowModal() != wxID_OK) return; - BeginWaitCursor(); - TRY + wxBusyCursor busyCursor; + try { CBoard* pBoard = m_pPBoard->GetBoard(); - CWindowDC scrnDC(this); - CSize size = pBoard->GetSize(m_nZoom); + wxSize size = CB::Convert(pBoard->GetSize(m_nZoom)); - OwnerPtr bmap = CDib::CreateDIBSection( - size.cx, size.cy); - CDC dcMem; - dcMem.CreateCompatibleDC(&scrnDC); - CBitmap* pPrvBMap = (CBitmap*)dcMem.SelectObject(&*bmap); + wxBitmap bmap(size.x, size.y); + { + wxMemoryDC dcMem; + dcMem.SelectObject(bmap); - CRect rct(0, 0, size.cx, size.cy); + wxRect rct(wxPoint(0, 0), size); // Draw base board image... pBoard->Draw(dcMem, rct, m_nZoom, m_pPBoard->m_bCellBorders); // Draw pieces etc..... - SetupDrawListDC(dcMem, rct); + DCSetupDrawListDC setupDrawListDC(*this, dcMem, rct); m_pPBoard->Draw(dcMem, rct, m_nZoom); - RestoreDrawListDC(dcMem); - GdiFlush(); - dcMem.SelectObject(pPrvBMap); + } - wxImage img = ToImage(*bmap); + wxImage img = bmap.ConvertToImage(); - if (!img.SaveFile(CB::string(dlg.GetPathName()))) + if (!img.SaveFile(dlg.GetPath())) { - EndWaitCursor(); - AfxMessageBox(IDP_ERR_BMPCREATE, MB_ICONEXCLAMATION); - EndWaitCursor(); + wxMessageBox(CB::string::LoadString(IDP_ERR_BMPCREATE), + CB::GetAppName(), + wxICON_EXCLAMATION); return; } - - EndWaitCursor(); } - CATCH_ALL (e) + catch (...) { - EndWaitCursor(); - AfxMessageBox(IDP_ERR_BMPWRITE, MB_ICONEXCLAMATION); + wxMessageBox(CB::string::LoadString(IDP_ERR_BMPWRITE), + CB::GetAppName(), + wxICON_EXCLAMATION); } - END_CATCH_ALL } -void CPlayBoardView::OnEditBoardProperties() +void CPlayBoardView::OnEditBoardProperties(wxCommandEvent& /*event*/) { - GetDocument()->DoBoardProperties(CheckedDeref(GetPlayBoard())); + GetDocument().DoBoardProperties(GetPlayBoard()); } -void CPlayBoardView::OnSelectGroupMarkers(UINT nID) +void CPlayBoardView::OnSelectGroupMarkers(wxCommandEvent& event) { - SelectMarkersInGroup(nID - ID_MRKGROUP_FIRST); + SelectMarkersInGroup(value_preserving_cast(MarkerXrcidToIndex(event.GetId()))); } -void CPlayBoardView::OnUpdateSelectGroupMarkers(CCmdUI* pCmdUI, UINT nID) +void CPlayBoardView::OnMenuOpen(wxMenuEvent& event) { - if (pCmdUI->m_pSubMenu != NULL) + if (event.GetMenu()) { - CMarkManager& pMgr = GetDocument()->GetMarkManager(); - if (pMgr.IsEmpty()) - return; - std::vector tbl; - tbl.reserve(pMgr.GetNumMarkSets()); - for (size_t i = size_t(0) ; i < pMgr.GetNumMarkSets() ; ++i) + wxMenu* menu; + wxMenuItem* markers = event.GetMenu()->FindItem(XRCID("ID_MRKGROUP_FIRST_0"), &menu); + if (markers) { - tbl.push_back(pMgr.GetMarkSet(i).GetName()); + OnUpdateSelectGroupMarkers(CheckedDeref(menu)); + return; } - CMenu menu; - VERIFY(menu.CreatePopupMenu()); + } + event.Skip(); +} - CreateSequentialSubMenuIDs(menu, ID_MRKGROUP_FIRST, tbl); +void CPlayBoardView::OnUpdateSelectGroupMarkers(wxMenu& menu) +{ + CMarkManager& pMgr = GetDocument().GetMarkManager(); + if (pMgr.IsEmpty()) + return; + std::vector tbl; + tbl.reserve(pMgr.GetNumMarkSets()); + for (size_t i = size_t(0) ; i < pMgr.GetNumMarkSets() ; ++i) + { + tbl.push_back(pMgr.GetMarkSet(i).GetName()); + } + wxASSERT(menu.GetMenuItemCount() == 1); + menu.Delete(XRCID("ID_MRKGROUP_FIRST_0")); + wxASSERT(menu.GetMenuItemCount() == 0); - CB::string str = CB::string::GetMenuString(*pCmdUI->m_pMenu, pCmdUI->m_nIndex, - MF_BYPOSITION); - VERIFY(pCmdUI->m_pMenu->ModifyMenu(pCmdUI->m_nIndex, - MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING, - reinterpret_cast(menu.Detach()), str)); + for (size_t i = size_t(0) ; i < tbl.size() ; ++i) + { + int intI = value_preserving_cast(i); + int xrcid = MarkerIndexToXrcid(intI); + menu.Append(xrcid, tbl[i]); + if (intI >= m_bindEnd) + { + Bind(wxEVT_MENU, &CPlayBoardView::OnSelectGroupMarkers, this, xrcid); + ++m_bindEnd; + } } - else - pCmdUI->Enable(); } -void CPlayBoardView::OnViewDrawIndOnTop() +void CPlayBoardView::OnViewDrawIndOnTop(wxCommandEvent& /*event*/) { - GetPlayBoard()->SetIndicatorsOnTop(!GetPlayBoard()->GetIndicatorsOnTop()); + GetPlayBoard().SetIndicatorsOnTop(!GetPlayBoard().GetIndicatorsOnTop()); CGamDocHint hint; hint.GetArgs().m_pPBoard = m_pPBoard.get(); - GetDocument()->UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); + GetDocument().UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); } -void CPlayBoardView::OnUpdateViewDrawIndOnTop(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateViewDrawIndOnTop(wxUpdateUIEvent& pCmdUI) { - pCmdUI->SetCheck(GetPlayBoard()->GetIndicatorsOnTop()); + pCmdUI.Enable(true); + pCmdUI.Check(GetPlayBoard().GetIndicatorsOnTop()); } -void CPlayBoardView::OnEditElementText() +void CPlayBoardView::OnEditElementText(wxCommandEvent& /*event*/) { ASSERT(m_selList.IsSingleSelect() && (m_selList.HasMarkers() || m_selList.HasPieces())); CDrawObj& pDObj = *m_selList.front()->m_pObj; - GetDocument()->DoEditObjectText(pDObj); + GetDocument().DoEditObjectText(pDObj); NotifySelectListChange(); // Make sure indicators are updated } -void CPlayBoardView::OnUpdateEditElementText(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateEditElementText(wxUpdateUIEvent& pCmdUI) { - CGamDoc* pDoc = GetDocument(); - if (pDoc->IsPlaying() || !pDoc->IsScenario() && - m_selList.HasOwnedPiecesNotMatching(pDoc->GetCurrentPlayerMask())) - pCmdUI->Enable(FALSE); + CGamDoc& pDoc = GetDocument(); + if (pDoc.IsPlaying() || !pDoc.IsScenario() && + m_selList.HasOwnedPiecesNotMatching(pDoc.GetCurrentPlayerMask())) + pCmdUI.Enable(FALSE); else { - pCmdUI->Enable(m_selList.IsSingleSelect() && + pCmdUI.Enable(m_selList.IsSingleSelect() && (m_selList.HasMarkers() || m_selList.HasPieces())); } } -void CPlayBoardView::OnActLockObject() +void CPlayBoardView::OnActLockObject(wxCommandEvent& /*event*/) { int nSet; int nClear; @@ -2212,18 +2393,18 @@ void CPlayBoardView::OnActLockObject() std::vector> listObjs; m_selList.LoadTableWithObjectPtrs(listObjs, CSelList::otAll, FALSE); - GetDocument()->AssignNewMoveGroup(); - GetDocument()->SetObjectLockdownTable(listObjs, bLockState); + GetDocument().AssignNewMoveGroup(); + GetDocument().SetObjectLockdownTable(listObjs, bLockState); if (m_pPBoard->GetLocksEnforced() && bLockState) m_selList.PurgeList(TRUE); // Purge former selections } -void CPlayBoardView::OnUpdateActLockObject(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActLockObject(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying()) + if (GetDocument().IsPlaying()) { - pCmdUI->Enable(FALSE); + pCmdUI.Enable(FALSE); return; } @@ -2233,15 +2414,15 @@ void CPlayBoardView::OnUpdateActLockObject(CCmdUI* pCmdUI) m_selList.CountDObjFlags(dobjFlgLockDown, nSet, nClear); if (nSet != 0 && nClear != 0) - pCmdUI->SetCheck(2); + pCmdUI.Set3StateValue(wxCHK_UNDETERMINED); else if (nSet != 0 && nClear == 0) - pCmdUI->SetCheck(1); + pCmdUI.Set3StateValue(wxCHK_CHECKED); else - pCmdUI->SetCheck(0); - pCmdUI->Enable(!m_selList.empty()); + pCmdUI.Set3StateValue(wxCHK_UNCHECKED); + pCmdUI.Enable(!m_selList.empty()); } -void CPlayBoardView::OnActLockSuspend() +void CPlayBoardView::OnActLockSuspend(wxCommandEvent& /*event*/) { m_pPBoard->SetLocksEnforced(!m_pPBoard->GetLocksEnforced()); // If enforcement is on and objects are locked, deselect them @@ -2249,19 +2430,19 @@ void CPlayBoardView::OnActLockSuspend() m_selList.DeselectIfDObjFlagsSet(dobjFlgLockDown); } -void CPlayBoardView::OnUpdateActLockSuspend(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActLockSuspend(wxUpdateUIEvent& pCmdUI) { - if (GetDocument()->IsPlaying()) - pCmdUI->Enable(FALSE); + if (GetDocument().IsPlaying()) + pCmdUI.Enable(FALSE); else { - pCmdUI->Enable(TRUE); - pCmdUI->SetCheck(!m_pPBoard->GetLocksEnforced()); + pCmdUI.Enable(TRUE); + pCmdUI.Check(!m_pPBoard->GetLocksEnforced()); } } -void CPlayBoardView::OnActTakeOwnership() +void CPlayBoardView::OnActTakeOwnership(wxCommandEvent& /*event*/) { CRect rct = m_selList.GetPiecesEnclosingRect(FALSE); if (rct.IsRectEmpty()) @@ -2269,48 +2450,48 @@ void CPlayBoardView::OnActTakeOwnership() CPoint pntCenter(MidPnt(rct.left, rct.right), MidPnt(rct.top, rct.bottom)); - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); std::vector tblPieces; m_selList.LoadTableWithOwnerStatePieceIDs(tblPieces, m_selList.LF_NOTOWNED); - pDoc->AssignNewMoveGroup(); + pDoc.AssignNewMoveGroup(); - if (pDoc->IsRecording()) + if (pDoc.IsRecording()) { // Insert a notification tip so there is some information // feedback during playback. CB::string strMsg = CB::string::LoadString(IDS_TIP_OWNER_ACQUIRED); - pDoc->RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), + pDoc.RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), value_preserving_cast(pntCenter.x), value_preserving_cast(pntCenter.y)); } - pDoc->SetPieceOwnershipTable(tblPieces, pDoc->GetCurrentPlayerMask()); + pDoc.SetPieceOwnershipTable(tblPieces, pDoc.GetCurrentPlayerMask()); CGamDocHint hint; hint.GetArgs().m_pPBoard = m_pPBoard.get(); - pDoc->UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); + pDoc.UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); NotifySelectListChange(); } -void CPlayBoardView::OnUpdateActTakeOwnership(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActTakeOwnership(wxUpdateUIEvent& pCmdUI) { - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); // Can't take ownership while residing on an owned board. - if (pDoc->IsPlaying() || m_pPBoard->IsOwned()) - pCmdUI->Enable(FALSE); - else if (pDoc->IsCurrentPlayerReferee()) - pCmdUI->Enable(FALSE); // No owner to acquire. He's the Referee! + if (pDoc.IsPlaying() || m_pPBoard->IsOwned()) + pCmdUI.Enable(FALSE); + else if (pDoc.IsCurrentPlayerReferee()) + pCmdUI.Enable(FALSE); // No owner to acquire. He's the Referee! else { - pCmdUI->Enable(pDoc->HasPlayers() && m_selList.HasNonOwnedPieces() && - pDoc->GetCurrentPlayerMask() != OWNER_MASK_SPECTATOR); + pCmdUI.Enable(pDoc.HasPlayers() && m_selList.HasNonOwnedPieces() && + pDoc.GetCurrentPlayerMask() != OWNER_MASK_SPECTATOR); } } -void CPlayBoardView::OnActReleaseOwnership() +void CPlayBoardView::OnActReleaseOwnership(wxCommandEvent& /*event*/) { CRect rct = m_selList.GetPiecesEnclosingRect(FALSE); if (rct.IsRectEmpty()) @@ -2318,57 +2499,57 @@ void CPlayBoardView::OnActReleaseOwnership() CPoint pntCenter(MidPnt(rct.left, rct.right), MidPnt(rct.top, rct.bottom)); - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); std::vector tblPieces; m_selList.LoadTableWithOwnerStatePieceIDs(tblPieces, m_selList.LF_OWNED); - pDoc->AssignNewMoveGroup(); + pDoc.AssignNewMoveGroup(); - if (pDoc->IsRecording()) + if (pDoc.IsRecording()) { // Insert a notification tip so there is some information // feedback during playback. CB::string strMsg = CB::string::LoadString(IDS_TIP_OWNER_RELEASED); - pDoc->RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), + pDoc.RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), value_preserving_cast(pntCenter.x), value_preserving_cast(pntCenter.y)); } - pDoc->SetPieceOwnershipTable(tblPieces, OWNER_MASK_SPECTATOR); + pDoc.SetPieceOwnershipTable(tblPieces, OWNER_MASK_SPECTATOR); CGamDocHint hint; hint.GetArgs().m_pPBoard = m_pPBoard.get(); - pDoc->UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); + pDoc.UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); NotifySelectListChange(); } -void CPlayBoardView::OnUpdateActReleaseOwnership(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActReleaseOwnership(wxUpdateUIEvent& pCmdUI) { - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); // Can't release ownership while residing on an owned board. - if (pDoc->IsPlaying() || m_pPBoard->IsOwned()) - pCmdUI->Enable(FALSE); - else if (pDoc->IsCurrentPlayerReferee() && m_selList.HasPieces()) - pCmdUI->Enable(TRUE); + if (pDoc.IsPlaying() || m_pPBoard->IsOwned()) + pCmdUI.Enable(FALSE); + else if (pDoc.IsCurrentPlayerReferee() && m_selList.HasPieces()) + pCmdUI.Enable(TRUE); else { - pCmdUI->Enable(pDoc->HasPlayers() && m_selList.HasOwnedPieces() && - pDoc->GetCurrentPlayerMask() != OWNER_MASK_SPECTATOR); + pCmdUI.Enable(pDoc.HasPlayers() && m_selList.HasOwnedPieces() && + pDoc.GetCurrentPlayerMask() != OWNER_MASK_SPECTATOR); } } -void CPlayBoardView::OnActSetOwner() +void CPlayBoardView::OnActSetOwner(wxCommandEvent& /*event*/) { - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); CRect rct = m_selList.GetPiecesEnclosingRect(FALSE); if (rct.IsRectEmpty()) return; - CSelectNewOwnerDialog dlg(CheckedDeref(pDoc->GetPlayerManager())); - if (!pDoc->IsCurrentPlayerReferee()) - dlg.m_nPlayer = CPlayerManager::GetPlayerNumFromMask(pDoc->GetCurrentPlayerMask()); + CSelectNewOwnerDialog dlg(CheckedDeref(pDoc.GetPlayerManager())); + if (!pDoc.IsCurrentPlayerReferee()) + dlg.m_nPlayer = CPlayerManager::GetPlayerNumFromMask(pDoc.GetCurrentPlayerMask()); if (dlg.ShowModal() != wxID_OK) return; @@ -2380,41 +2561,42 @@ void CPlayBoardView::OnActSetOwner() std::vector tblPieces; m_selList.LoadTableWithOwnerStatePieceIDs(tblPieces, m_selList.LF_BOTH); - pDoc->AssignNewMoveGroup(); + pDoc.AssignNewMoveGroup(); - if (pDoc->IsRecording()) + if (pDoc.IsRecording()) { // Insert a notification tip so there is some information // feedback during playback. CB::string strMsg = CB::string::LoadString(IDS_TIP_OWNER_ACQUIRED); - pDoc->RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), + pDoc.RecordEventMessage(strMsg, m_pPBoard->GetSerialNumber(), value_preserving_cast(pntCenter.x), value_preserving_cast(pntCenter.y)); } - pDoc->SetPieceOwnershipTable(tblPieces, dwNewOwnerMask); + pDoc.SetPieceOwnershipTable(tblPieces, dwNewOwnerMask); CGamDocHint hint; hint.GetArgs().m_pPBoard = m_pPBoard.get(); - pDoc->UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); + pDoc.UpdateAllViews(NULL, HINT_UPDATEBOARD, &hint); NotifySelectListChange(); } -void CPlayBoardView::OnUpdateActSetOwner(CCmdUI* pCmdUI) +void CPlayBoardView::OnUpdateActSetOwner(wxUpdateUIEvent& pCmdUI) { - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); // Can't take ownership while residing on an owned board. - if (pDoc->IsPlaying() || m_pPBoard->IsOwned()) - pCmdUI->Enable(FALSE); - else if (pDoc->IsCurrentPlayerReferee() && m_selList.HasPieces()) - pCmdUI->Enable(TRUE); + if (pDoc.IsPlaying() || m_pPBoard->IsOwned()) + pCmdUI.Enable(FALSE); + else if (pDoc.IsCurrentPlayerReferee() && m_selList.HasPieces()) + pCmdUI.Enable(TRUE); else { - pCmdUI->Enable(pDoc->HasPlayers() && - (m_selList.HasPieces() && pDoc->GetCurrentPlayerMask() != OWNER_MASK_SPECTATOR)); + pCmdUI.Enable(pDoc.HasPlayers() && + (m_selList.HasPieces() && pDoc.GetCurrentPlayerMask() != OWNER_MASK_SPECTATOR)); } } +#if 0 ///////////////////////////////////////////////////////////////////////////// // Fix MFC problems with mouse wheel handling in Win98 and WinME systems @@ -2564,3 +2746,65 @@ BOOL CPlayBoardView::DoMouseWheelFix(UINT fFlags, short zDelta, CPoint point) return bResult; } } +#endif + +void CPlayBoardView::OnUpdateEnable(wxUpdateUIEvent& pCmdUI) +{ + pCmdUI.Enable(true); +} + +void CPlayBoardViewContainer::OnDraw(CDC* pDC) +{ + // do nothing because child covers entire client rect +} + +void CPlayBoardViewContainer::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) +{ + child->OnUpdate(pSender, lHint, pHint); + + BASE::OnUpdate(pSender, lHint, pHint); +} + +void CPlayBoardViewContainer::OnActivateView(BOOL bActivate, CView* pActivateView, + CView* pDeactiveView) +{ + BASE::OnActivateView(bActivate, pActivateView, pDeactiveView); + child->OnActivateView(bActivate, pActivateView, pDeactiveView); +} + +CPlayBoardViewContainer::CPlayBoardViewContainer() : + CB::wxNativeContainerWindowMixin(static_cast(*this)) +{ +} + +int CPlayBoardViewContainer::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (BASE::OnCreate(lpCreateStruct) == -1) + { + return -1; + } + + child = new CPlayBoardView(*this); + + return 0; +} + +// MFC puts the focus here, so move it to the useful window +void CPlayBoardViewContainer::OnSetFocus(CWnd* pOldWnd) +{ + BASE::OnSetFocus(pOldWnd); + child->SetFocus(); +} + +void CPlayBoardViewContainer::OnSize(UINT nType, int cx, int cy) +{ + child->SetSize(0, 0, cx, cy); + return BASE::OnSize(nType, cx, cy); +} + +LRESULT CPlayBoardViewContainer::OnMessageWindowState(WPARAM wParam, LPARAM lParam) +{ + WinStateEvent event(*reinterpret_cast(wParam), bool(lParam)); + child->ProcessWindowEvent(event); + return (LRESULT)1; +} diff --git a/GP/VwPbrd.h b/GP/VwPbrd.h index 51d17c82..ac5cfb42 100644 --- a/GP/VwPbrd.h +++ b/GP/VwPbrd.h @@ -1,6 +1,6 @@ // VwPbrd.h : interface of the CPlayBoardView class // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -41,250 +41,338 @@ class CPlayBoard; enum TileScale; -class CPlayBoardView : public CScrollView +class CPlayBoardView : public CB::ProcessEventOverride { +private: friend class CPlayBoardFrame; - -protected: // create from serialization only - CPlayBoardView(); - DECLARE_DYNCREATE(CPlayBoardView) + friend class CPlayBoardViewContainer; + typedef CB::ProcessEventOverride BASE; + CPlayBoardView(CPlayBoardViewContainer& parent); // Attributes public: - const CGamDoc* GetDocument() const; - CGamDoc* GetDocument() { return const_cast(std::as_const(*this).GetDocument()); } - const CPlayBoard* GetPlayBoard() const { return m_pPBoard.get(); } - CPlayBoard* GetPlayBoard() { return const_cast(std::as_const(*this).GetPlayBoard()); } + const CGamDoc& GetDocument() const; + CGamDoc& GetDocument() { return const_cast(std::as_const(*this).GetDocument()); } + const CPlayBoard& GetPlayBoard() const { return *m_pPBoard; } + CPlayBoard& GetPlayBoard() { return const_cast(std::as_const(*this).GetPlayBoard()); } + wxOverlay& GetOverlay() { return *overlay; } + CFrameWnd* GetParentFrame(); // Operations public: // Implementation public: - virtual ~CPlayBoardView(); - virtual void OnDraw(CDC* pDC) override; // Overridden to draw this view + ~CPlayBoardView() override; + void OnDraw(wxDC& pDC) override; // Overridden to draw this view // Tools and selection support public: CSelList m_selList; // List of selected objects. void NotifySelectListChange(); - const CSelList* GetSelectList() const { return &m_selList; } - CSelList* GetSelectList() { return const_cast(std::as_const(*this).GetSelectList()); } - CPoint GetWorkspaceDim() const; + const CSelList& GetSelectList() const { return m_selList; } + CSelList& GetSelectList() { return const_cast(std::as_const(*this).GetSelectList()); } + wxPoint GetWorkspaceDim() const; void AddDrawObject(CDrawObj::OwnerPtr pObj); void MoveObjsInSelectList(BOOL bToFront, BOOL bInvalidate = TRUE); - void PrepareScaledDC(CDC& pDC, CRect* pRct = NULL, BOOL bHonor180Flip = FALSE) const; - void OnPrepareScaledDC(CDC& pDC, BOOL bHonor180Flip = FALSE); + void PrepareScaledDC(wxDC& pDC, wxRect* pRct = NULL, BOOL bHonor180Flip = FALSE) const; + void OnPrepareScaledDC(wxDC& pDC, BOOL bHonor180Flip = FALSE); - void AdjustPoint(CPoint& pnt) const; // Limit and grid processing - void AdjustRect(CRect& rct) const; + [[nodiscard]] wxPoint AdjustPoint(wxPoint pnt) const; // Limit and grid processing + [[nodiscard]] wxRect AdjustRect(wxRect rct) const; - void SelectWithinRect(CRect rctNet, BOOL bInclIntersects = FALSE); - void SelectAllUnderPoint(CPoint point); - CDrawObj* ObjectHitTest(CPoint point); + void SelectWithinRect(wxRect rctNet, BOOL bInclIntersects = FALSE); + void SelectAllUnderPoint(wxPoint point); + CDrawObj* ObjectHitTest(wxPoint point); void SelectAllObjectsInList(const std::vector>& pLst); void SelectAllObjectsInTable(const std::vector>& pTbl); void SelectMarkersInGroup(size_t nGroup); void SelectAllMarkers(); // TEMP FOR NOW! - COLORREF GetTextColor() const { return RGB(255, 0, 0); } - COLORREF GetLineColor() const { return RGB(0, 255, 0); } + wxColour GetTextColor() const { return wxColour(255, 0, 0); } + wxColour GetLineColor() const { return wxColour(0, 255, 0); } UINT GetLineWidth() const { return 3; } // Coordinate scaling... public: - void WorkspaceToClient(CPoint& point) const; - void WorkspaceToClient(CRect& rect) const; - void ClientToWorkspace(CPoint& point) const; - void ClientToWorkspace(CRect& rect) const; - void InvalidateWorkspaceRect(const CRect& pRect, BOOL bErase = FALSE); + [[nodiscard]] wxPoint WorkspaceToClient(wxPoint point) const; + [[nodiscard]] wxRect WorkspaceToClient(wxRect rect) const; + [[nodiscard]] wxPoint ClientToWorkspace(wxPoint point) const; + [[nodiscard]] wxRect ClientToWorkspace(wxRect rect) const; + void InvalidateWorkspaceRect(const wxRect& pRect, BOOL bErase = FALSE); // View support public: - void ScrollWorkspacePointIntoView(CPoint point); - void CenterViewOnWorkspacePoint(CPoint point); - BOOL CheckAutoScroll(CPoint point); - BOOL ProcessAutoScroll(CPoint point); + void ScrollWorkspacePointIntoView(wxPoint point); + void CenterViewOnWorkspacePoint(wxPoint point); + BOOL CheckAutoScroll(wxPoint point); + BOOL ProcessAutoScroll(wxPoint point); + // this method can be overridden in a derived class to forbid sending the + // auto scroll events - note that unlike StopAutoScrolling() it doesn't + // stop the timer, so it will be called repeatedly and will typically + // return different values depending on the current mouse position + bool SendAutoScrollEvents(wxScrollWinEvent& event) const override; void SetOurScrollSizes(TileScale nZoom); void DoViewScaleBrd(TileScale nZoom); // Tooltip Support public: - void SetNotificationTip(CPoint pointClient, UINT nResID); - void SetNotificationTip(CPoint pointClient, const CB::string* pszTip); +#if 0 + void SetNotificationTip(wxPoint pointClient, UINT nResID); +#endif + void SetNotificationTip(wxPoint pointClient, const CB::string& pszTip); void ClearNotificationTip(); void ClearToolTip(); - static void CALLBACK NotificationTipTimeoutHandler(HWND hwnd, UINT uMsg, - UINT_PTR idEvent, DWORD dwTime); - void DoToolTipHitProcessing(CPoint pointClient); + void NotificationTipTimeoutHandler(wxTimerEvent& event); + void DoToolTipHitProcessing(wxPoint pointClient); // Grid and limiting support protected: BOOL IsGridizeActive() const; #ifdef WIN32 - void GridizeX(long& xPos) const; - void GridizeY(long& yPos) const; + [[nodiscard]] long GridizeX(long xPos) const; + [[nodiscard]] long GridizeY(long yPos) const; #else void GridizeX(int& xPos) const; void GridizeY(int& yPos) const; #endif - void LimitPoint(POINT& pPnt) const; - void LimitRect(RECT& pRct) const; - BOOL IsRectFullyOnBoard(const RECT& pRct, BOOL* pbXOK = NULL, BOOL* pbYOK = NULL) const; + [[nodiscard]] wxPoint LimitPoint(wxPoint pPnt) const; + [[nodiscard]] wxRect LimitRect(wxRect pRct) const; + BOOL IsRectFullyOnBoard(const wxRect& pRct, BOOL* pbXOK = NULL, BOOL* pbYOK = NULL) const; // Implementation +private: + // member declaration order determines construction order + RefPtr parent; + RefPtr document; protected: - CB::propagate_const m_pPBoard; // Board that contains selections etc... + RefPtr m_pPBoard; // Board that contains selections etc... TileScale m_nZoom; // Current zoom level of view // -------- // BOOL m_bInDrag; // Currently being dragged over CB::propagate_const m_pDragSelList; // Pointer the select list being dragged - uintptr_t m_nTimerID; // Used to control autoscrolls +public: + void SetTimer(int id, unsigned milliseconds); + void KillTimer(int id); +private: + OwnerOrNullPtr timer; +protected: // -------- // - UINT m_nCurToolID; // Current tool ID + int m_nCurToolID; // Current tool ID // -------- // - CToolTipCtrl m_toolMsgTip; // Tooltip for notifications - CToolTipCtrl m_toolHitTip; // Tooltip hit support for view + CB::ToolTip m_toolMsgTip; // Tooltip for notifications + wxTimer m_toolMsgTipTimer; + CB::ToolTip m_toolHitTip; // Tooltip hit support for view + wxRect m_toolHitTipRect = wxRect(); CB::propagate_const m_pCurTipObj; // Currently hit tip object // Tables used to process relative piece rotations. DON'T Serialize! BOOL m_bWheelRotation; // Indicates the type of rotation being done - CPoint m_pntWheelMid; // The wheel rotation point + wxPoint m_pntWheelMid; // The wheel rotation point std::vector m_tblCurAngles; // Original angles of pieces - std::vector> m_tblCurPieces; // Pieces being rotated - CUIntArray m_tblXMidPnt; // X coord of piece midpoint - CUIntArray m_tblYMidPnt; // Y coord of piece midpoint + std::vector> m_tblCurPieces; // Pieces being rotated + std::vector m_tblMidPnt; // X coord of piece midpoint // Implementation protected: BOOL IsBoardContentsAvailableToCurrentPlayer() const; - void AddPiece(CPoint pnt, PieceID pid); - - PToolType MapToolType(UINT nToolResID) const; + void AddPiece(wxPoint pnt, PieceID pid); - void SetupDrawListDC(CDC& pDC, CRect& pRct) const; - void RestoreDrawListDC(CDC& pDC) const; + PToolType MapToolType(int nToolResID) const; - LRESULT DoDragPiece(DragInfo& pdi); - LRESULT DoDragMarker(DragInfo& pdi); - LRESULT DoDragPieceList(DragInfo& pdi); - LRESULT DoDragSelectList(DragInfo& pdi); + class DCSetupDrawListDC + { + public: + DCSetupDrawListDC(const CPlayBoardView& rThis, wxDC& dc, wxRect& pRct); + private: + CB::DCUserScaleChanger scaleChanger; + CB::DCLogicalOriginChanger logOrgChanger; + }; - void DragDoAutoScroll(); - void DragCheckAutoScroll(); - void DragKillAutoScroll(); + void DoDragPiece(const DragInfoWx& pdi); + void DoDragMarker(DragDropEvent& event); + void DoDragPieceList(DragDropEvent& event); + void DoDragSelectList(DragDropEvent& event); void DoAutostackOfSelectedObjects(int xStagger, int yStagger); void DoRotateRelative(BOOL bWheelRotation); +#if 0 BOOL DoMouseWheelFix(UINT fFlags, short zDelta, CPoint point); +#endif protected: - virtual void OnInitialUpdate(); - virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - virtual BOOL PreTranslateMessage(MSG* pMsg); - virtual void OnActivateView(BOOL bActivate, CView* pActivateView, + void OnInitialUpdate(); + void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); +#if 0 + BOOL PreCreateWindow(CREATESTRUCT& cs) override; + BOOL PreTranslateMessage(MSG* pMsg) override; +#endif + void OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView); -// Generated message map functions protected: - //{{AFX_MSG(CPlayBoardView) - afx_msg void OnViewFullScaleBrd(); - afx_msg void OnUpdateViewFullScaleBrd(CCmdUI* pCmdUI); - afx_msg void OnViewHalfScaleBrd(); - afx_msg void OnUpdateViewHalfScaleBrd(CCmdUI* pCmdUI); - afx_msg LRESULT OnDragItem(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnMessageRotateRelative(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnMessageCenterBoardOnPoint(WPARAM wParam, LPARAM lParam); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnTimer(uintptr_t nIDEvent); - afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); - afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message); - afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); - afx_msg BOOL OnPlayTool(UINT id); - afx_msg void OnUpdatePlayTool(CCmdUI* pCmdUI); - afx_msg void OnActStack(); - afx_msg void OnUpdateActStack(CCmdUI* pCmdUI); - afx_msg void OnActToBack(); - afx_msg void OnUpdateActToBack(CCmdUI* pCmdUI); - afx_msg void OnActToFront(); - afx_msg void OnUpdateActToFront(CCmdUI* pCmdUI); - afx_msg BOOL OnActTurnOver(UINT id); - afx_msg void OnUpdateActTurnOver(CCmdUI* pCmdUI); - afx_msg void OnActPlotMove(); - afx_msg void OnUpdateActPlotMove(CCmdUI* pCmdUI); - afx_msg void OnActPlotDone(); - afx_msg void OnUpdateActPlotDone(CCmdUI* pCmdUI); - afx_msg void OnActPlotDiscard(); - afx_msg void OnUpdateActPlotDiscard(CCmdUI* pCmdUI); - afx_msg void OnUpdateIndicatorCellNum(CCmdUI* pCmdUI); - afx_msg void OnViewSnapGrid(); - afx_msg void OnUpdateViewSnapGrid(CCmdUI* pCmdUI); - afx_msg void OnEditSelAllMarkers(); - afx_msg void OnUpdateEditSelAllMarkers(CCmdUI* pCmdUI); + void OnViewFullScaleBrd(wxCommandEvent& event); + void OnUpdateViewFullScaleBrd(wxUpdateUIEvent& pCmdUI); + void OnViewHalfScaleBrd(wxCommandEvent& event); + void OnUpdateViewHalfScaleBrd(wxUpdateUIEvent& pCmdUI); + void OnDragItem(DragDropEvent& event); + void OnMessageRotateRelative(RotatePieceDeltaEvent& event); + void OnMessageCenterBoardOnPoint(CenterBoardOnPointEvent& event); + void OnLButtonDown(wxMouseEvent& event); + void OnMouseMove(wxMouseEvent& event); + void OnLButtonUp(wxMouseEvent& event); + void OnMouseCaptureLost(wxMouseCaptureLostEvent& event); + void OnTimer(wxTimerEvent& event); + void OnLButtonDblClk(wxMouseEvent& event); + void OnSetCursor(wxSetCursorEvent& event); + void OnKeyDown(wxKeyEvent& event); + void OnChar(wxKeyEvent& event); + void OnPlayTool(wxCommandEvent& event); + void OnUpdatePlayTool(wxUpdateUIEvent& pCmdUI); + void OnActStack(wxCommandEvent& event); + void OnUpdateActStack(wxUpdateUIEvent& pCmdUI); + void OnActToBack(wxCommandEvent& event); + void OnUpdateActToBack(wxUpdateUIEvent& pCmdUI); + void OnActToFront(wxCommandEvent& event); + void OnUpdateActToFront(wxUpdateUIEvent& pCmdUI); + void OnActTurnOver(wxCommandEvent& event); + void OnUpdateActTurnOver(wxUpdateUIEvent& pCmdUI); + void OnActPlotMove(wxCommandEvent& event); + void OnUpdateActPlotMove(wxUpdateUIEvent& pCmdUI); + void OnActPlotDone(); + void OnActPlotDone(wxCommandEvent& /*event*/) { OnActPlotDone(); } + void OnUpdateActPlotDone(wxUpdateUIEvent& pCmdUI); + void OnActPlotDiscard(); + void OnActPlotDiscard(wxCommandEvent& /*event*/) { OnActPlotDiscard(); } + void OnUpdateActPlotDiscard(wxUpdateUIEvent& pCmdUI); + void OnUpdateIndicatorCellNum(wxUpdateUIEvent& pCmdUI); + void OnViewSnapGrid(wxCommandEvent& event); + void OnUpdateViewSnapGrid(wxUpdateUIEvent& pCmdUI); + void OnEditSelAllMarkers(wxCommandEvent& event); + void OnUpdateEditSelAllMarkers(wxUpdateUIEvent& pCmdUI); +#if 0 afx_msg void OnActRotate(); afx_msg void OnUpdateActRotate(CCmdUI* pCmdUI); - afx_msg void OnViewToggleScale(); - afx_msg void OnUpdateViewToggleScale(CCmdUI* pCmdUI); - afx_msg void OnViewPieces(); - afx_msg void OnUpdateViewPieces(CCmdUI* pCmdUI); - afx_msg void OnEditCopy(); - afx_msg void OnEditBoardToFile(); - afx_msg void OnEditBoardProperties(); - afx_msg void OnActRotateRelative(); - afx_msg void OnUpdateActRotateRelative(CCmdUI* pCmdUI); - afx_msg void OnEditClear(); - afx_msg void OnUpdateEditClear(CCmdUI* pCmdUI); - afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); - afx_msg void OnViewDrawIndOnTop(); - afx_msg void OnUpdateViewDrawIndOnTop(CCmdUI* pCmdUI); - afx_msg void OnEditElementText(); - afx_msg void OnUpdateEditElementText(CCmdUI* pCmdUI); - afx_msg void OnActLockObject(); - afx_msg void OnUpdateActLockObject(CCmdUI* pCmdUI); - afx_msg void OnActLockSuspend(); - afx_msg void OnUpdateActLockSuspend(CCmdUI* pCmdUI); - afx_msg void OnActShuffleSelectedObjects(); - afx_msg void OnUpdateActShuffleSelectedObjects(CCmdUI* pCmdUI); - afx_msg void OnActAutostackDeck(); - afx_msg void OnUpdateActAutostackDeck(CCmdUI* pCmdUI); - afx_msg void OnActTakeOwnership(); - afx_msg void OnUpdateActTakeOwnership(CCmdUI* pCmdUI); - afx_msg void OnActReleaseOwnership(); - afx_msg void OnUpdateActReleaseOwnership(CCmdUI* pCmdUI); - afx_msg void OnActSetOwner(); - afx_msg void OnUpdateActSetOwner(CCmdUI* pCmdUI); - afx_msg void OnViewSmallScaleBoard(); - afx_msg void OnUpdateViewSmallScaleBoard(CCmdUI* pCmdUI); - afx_msg void OnViewBoardRotate180(); - afx_msg void OnUpdateViewBoardRotate180(CCmdUI* pCmdUI); +#endif + void OnViewToggleScale(wxCommandEvent& event); + void OnUpdateViewToggleScale(wxUpdateUIEvent& pCmdUI); + void OnViewPieces(wxCommandEvent& event); + void OnUpdateViewPieces(wxUpdateUIEvent& pCmdUI); + void OnEditCopy(wxCommandEvent& event); + void OnEditBoardToFile(wxCommandEvent& event); + void OnEditBoardProperties(wxCommandEvent& event); + void OnActRotateRelative(wxCommandEvent& event); + void OnUpdateActRotateRelative(wxUpdateUIEvent& pCmdUI); + void OnEditClear(); + void OnEditClear(wxCommandEvent& /*event*/) { OnEditClear(); } + void OnUpdateEditClear(wxUpdateUIEvent& pCmdUI); + void OnContextMenu(wxContextMenuEvent& event); + void OnViewDrawIndOnTop(wxCommandEvent& event); + void OnUpdateViewDrawIndOnTop(wxUpdateUIEvent& pCmdUI); + void OnEditElementText(wxCommandEvent& event); + void OnUpdateEditElementText(wxUpdateUIEvent& pCmdUI); + void OnActLockObject(wxCommandEvent& event); + void OnUpdateActLockObject(wxUpdateUIEvent& pCmdUI); + void OnActLockSuspend(wxCommandEvent& event); + void OnUpdateActLockSuspend(wxUpdateUIEvent& pCmdUI); + void OnActShuffleSelectedObjects(wxCommandEvent& event); + void OnUpdateActShuffleSelectedObjects(wxUpdateUIEvent& pCmdUI); + void OnActAutostackDeck(wxCommandEvent& event); + void OnUpdateActAutostackDeck(wxUpdateUIEvent& pCmdUI); + void OnActTakeOwnership(wxCommandEvent& event); + void OnUpdateActTakeOwnership(wxUpdateUIEvent& pCmdUI); + void OnActReleaseOwnership(wxCommandEvent& event); + void OnUpdateActReleaseOwnership(wxUpdateUIEvent& pCmdUI); + void OnActSetOwner(wxCommandEvent& event); + void OnUpdateActSetOwner(wxUpdateUIEvent& pCmdUI); + void OnViewSmallScaleBoard(wxCommandEvent& event); + void OnUpdateViewSmallScaleBoard(wxUpdateUIEvent& pCmdUI); + void OnViewBoardRotate180(wxCommandEvent& event); + void OnUpdateViewBoardRotate180(wxUpdateUIEvent& pCmdUI); +#if 0 afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); - //}}AFX_MSG - afx_msg void OnSelectGroupMarkers(UINT nID); - afx_msg void OnUpdateSelectGroupMarkers(CCmdUI* pCmdUI, UINT nID); - afx_msg void OnRotatePiece(UINT nID); - afx_msg void OnUpdateRotatePiece(CCmdUI* pCmdUI, UINT nID); - afx_msg LRESULT OnMessageWindowState(WPARAM wParam, LPARAM lParam); - afx_msg LRESULT OnMessageSelectBoardObjectList(WPARAM wParam, LPARAM lParam); - DECLARE_MESSAGE_MAP() +#endif + void OnSelectGroupMarkers(wxCommandEvent& event); + void OnMenuOpen(wxMenuEvent& event); + void OnUpdateSelectGroupMarkers(wxMenu& menu); + void OnRotatePiece(wxCommandEvent& event); + void OnUpdateRotatePiece(wxUpdateUIEvent& pCmdUI); + void OnMessageWindowState(WinStateEvent& event); + void OnMessageSelectBoardObjectList(SelectBoardObjListEvent& event); + void OnScrollWinLine(wxScrollWinEvent& event); + wxDECLARE_EVENT_TABLE(); public: - afx_msg void OnActRotateGroupRelative(); - afx_msg void OnUpdateActRotateGroupRelative(CCmdUI *pCmdUI); + void OnActRotateGroupRelative(wxCommandEvent& event); + void OnUpdateActRotateGroupRelative(wxUpdateUIEvent& pCmdUI); +private: + void OnUpdateEnable(wxUpdateUIEvent& pCmdUI); + +private: + // IGetCmdTarget + CCmdTarget& Get() override; + + /* This view should support scrolling by individual pixels, + but don't make the line-up and line-down scrolling that + slow. */ + int m_xScrollPixelsPerLine; + int m_yScrollPixelsPerLine; + + OwnerPtr overlay = MakeOwner(); + int m_bindEnd = 0; }; #ifndef _DEBUG // debug version in vwmbrd.cpp -inline const CGamDoc* CPlayBoardView::GetDocument() const - { return CB::ToCGamDoc(m_pDocument); } +inline const CGamDoc& CPlayBoardView::GetDocument() const + { return *document; } #endif +class CPlayBoardViewContainer : public CB::OnCmdMsgOverride, + public CB::wxNativeContainerWindowMixin +{ +public: + void OnDraw(CDC* pDC) override; + operator const CPlayBoardView&() const { return *child; } + operator CPlayBoardView&() + { + return const_cast(static_cast(std::as_const(*this))); + } + + void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) override; + void OnActivateView(BOOL bActivate, CView* pActivateView, + CView* pDeactiveView) override; + +private: + CPlayBoardViewContainer(); // used by dynamic creation + DECLARE_DYNCREATE(CPlayBoardViewContainer) + + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg LRESULT OnMessageWindowState(WPARAM wParam, LPARAM lParam); + DECLARE_MESSAGE_MAP() + + // IGetEvtHandler + wxEvtHandler& Get() override + { + return CheckedDeref(CheckedDeref(child).GetEventHandler()); + } + + // owned by wx + CB::propagate_const child = nullptr; + + typedef CB::OnCmdMsgOverride BASE; +}; + +inline CCmdTarget& CPlayBoardView::Get() +{ + return *parent; +} + ///////////////////////////////////////////////////////////////////////////// diff --git a/GP/VwPbrd1.cpp b/GP/VwPbrd1.cpp index a76fc701..1194fa00 100644 --- a/GP/VwPbrd1.cpp +++ b/GP/VwPbrd1.cpp @@ -1,6 +1,6 @@ // VwPbrd1.cpp : implementation of the CPlayBoardView class // -// Copyright (c) 1994-2023 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -50,30 +50,34 @@ const int scrollZone = 16; ////////////////////////////////////////////////////////////////////// -void CPlayBoardView::DoToolTipHitProcessing(CPoint pointClient) +void CPlayBoardView::DoToolTipHitProcessing(wxPoint pointClient) { - CGamDoc* pDoc = GetDocument(); - if (!pDoc->IsShowingObjectTips() && pDoc->IsOwnerTipsDisabled()) + CGamDoc& pDoc = GetDocument(); + if (!pDoc.IsShowingObjectTips() && pDoc.IsOwnerTipsDisabled()) { // Delete previous tool definition - m_toolHitTip.DelTool(this, ID_TIP_PLAYBOARD_HIT); + if (!m_toolHitTipRect.IsEmpty()) + { + m_toolHitTip.Delete(*this, m_toolHitTipRect); + m_toolHitTipRect = wxRect(); + } m_pCurTipObj = NULL; return; } - CPoint pnt(pointClient); - ClientToWorkspace(pnt); + wxPoint pnt(pointClient); + pnt = ClientToWorkspace(pnt); CDrawObj* pDObj = ObjectHitTest(pnt); - if (pDoc->IsOwnerTipsDisabled() && pDoc->HasPlayers()) + if (pDoc.IsOwnerTipsDisabled() && pDoc.HasPlayers()) { if (pDObj != NULL && pDObj->GetType() == CDrawObj::drawPieceObj) { CPieceObj* pPObj = (CPieceObj*)pDObj; if (pPObj->IsOwned() && - !pDoc->GetPieceTable().IsPieceInvisible(pPObj->m_pid)) + !pDoc.GetPieceTable().IsPieceInvisible(pPObj->m_pid)) { - CB::string strOwner = pDoc->GetPieceOwnerName(pPObj->m_pid); + CB::string strOwner = pDoc.GetPieceOwnerName(pPObj->m_pid); CB::string strOwnedBy = CB::string::Format(IDS_TIP_OWNED_BY_UC, strOwner); GetMainFrame()->GetStatusBar()->SetWindowText(strOwnedBy); } @@ -87,39 +91,42 @@ void CPlayBoardView::DoToolTipHitProcessing(CPoint pointClient) if (pDObj != m_pCurTipObj) { // Object changed so delete previous tool definition - m_toolHitTip.DelTool(this, ID_TIP_PLAYBOARD_HIT); + if (!m_toolHitTipRect.IsEmpty()) + { + m_toolHitTip.Delete(*this, m_toolHitTipRect); + m_toolHitTipRect = wxRect(); + } m_pCurTipObj = pDObj; if (pDObj != NULL) { // New object found so create a new tip - CRect rct = pDObj->GetRect(); - WorkspaceToClient(rct); + wxRect rct = CB::Convert(pDObj->GetRect()); + rct = WorkspaceToClient(rct); CB::string strTip; - CB::string strTitle; - if (pDoc->IsShowingObjectTips()) - pDoc->GetTipTextForObject(*pDObj, strTip, &strTitle); + if (pDoc.IsShowingObjectTips()) + pDoc.GetTipTextForObject(*pDObj, strTip); // All this stuff is used to annotate tips with owner names // when player accounts are active. - if (pDoc->HasPlayers() && pDObj->GetType() == CDrawObj::drawPieceObj) + if (pDoc.HasPlayers() && pDObj->GetType() == CDrawObj::drawPieceObj) { CPieceObj* pPObj = (CPieceObj*)pDObj; if (pPObj->IsOwned() && - !pDoc->GetPieceTable().IsPieceInvisible(pPObj->m_pid)) + !pDoc.GetPieceTable().IsPieceInvisible(pPObj->m_pid)) { - CB::string strOwner = pDoc->GetPieceOwnerName(pPObj->m_pid); + CB::string strOwner = pDoc.GetPieceOwnerName(pPObj->m_pid); CB::string strOwnedBy = CB::string::Format(IDS_TIP_OWNED_BY_UC, strOwner); - if (!pDoc->IsScenario() && !pPObj->IsOwnedBy(pDoc->GetCurrentPlayerMask())) + if (!pDoc.IsScenario() && !pPObj->IsOwnedBy(pDoc.GetCurrentPlayerMask())) { strTip.clear(); // Current player isn't allowed to see text. - if (!pDoc->IsOwnerTipsDisabled() && !strOwner.empty())// Replace tip with special "Owned by" tip + if (!pDoc.IsOwnerTipsDisabled() && !strOwner.empty())// Replace tip with special "Owned by" tip strTip = strOwnedBy; } else { - if (!pDoc->IsOwnerTipsDisabled()) + if (!pDoc.IsOwnerTipsDisabled()) { // Append actual tip to owner string. if (strTip.empty()) @@ -135,96 +142,84 @@ void CPlayBoardView::DoToolTipHitProcessing(CPoint pointClient) } if (!strTip.empty()) { - m_toolHitTip.AddTool(this, strTip, rct, ID_TIP_PLAYBOARD_HIT); - - if (!strTitle.empty()) - m_toolHitTip.SendMessage(TTM_SETTITLE, 0, reinterpret_cast(strTitle.v_str())); + m_toolHitTip.Add(*this, rct, strTip); + m_toolHitTipRect = rct; - m_toolHitTip.Activate(TRUE); + m_toolHitTip.Enable(TRUE); } else { // Delete previous tool definition - m_toolHitTip.DelTool(this, ID_TIP_PLAYBOARD_HIT); + if (!m_toolHitTipRect.IsEmpty()) + { + m_toolHitTip.Delete(*this, m_toolHitTipRect); + m_toolHitTipRect = wxRect(); + } m_pCurTipObj = NULL; return; } } else - m_toolHitTip.Activate(FALSE); + m_toolHitTip.Enable(FALSE); } } void CPlayBoardView::ClearToolTip() { // Object changed so delete previous tool definition - m_toolHitTip.DelTool(this, ID_TIP_PLAYBOARD_HIT); + if (!m_toolHitTipRect.IsEmpty()) + { + m_toolHitTip.Delete(*this, m_toolHitTipRect); + m_toolHitTipRect = wxRect(); + } m_pCurTipObj = NULL; - m_toolHitTip.Activate(FALSE); + m_toolHitTip.Enable(FALSE); } ////////////////////////////////////////////////////////////////////// -void CPlayBoardView::SetNotificationTip(CPoint pointClient, UINT nResID) -{ - CB::string str = CB::string::LoadString(nResID); - SetNotificationTip(pointClient, &str); -} - -void CPlayBoardView::SetNotificationTip(CPoint pointClient, const CB::string* pszTip) +void CPlayBoardView::SetNotificationTip(wxPoint pointClient, const CB::string& pszTip) { ClearNotificationTip(); - TOOLINFO ti; - m_toolMsgTip.FillInToolInfo(ti, this, ID_TIP_PLAYBOARD_MSG); - ti.uFlags |= TTF_TRACK; - ti.lpszText = pszTip ? const_cast(pszTip->v_str()) : nullptr; + m_toolMsgTip.Add(*this, pszTip, CB::ToolTip::TRACK); - m_toolMsgTip.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti); + wxPoint pointScreen = ClientToScreen(pointClient); - CPoint pointScreen(pointClient); - ClientToScreen(&pointScreen); + m_toolMsgTip.Enable(true); + m_toolMsgTip.TrackActivate(*this, true); + m_toolMsgTip.TrackPosition(pointScreen); - m_toolMsgTip.Activate(TRUE); - m_toolMsgTip.SendMessage(TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&ti); - m_toolMsgTip.SendMessage(TTM_TRACKPOSITION, 0, - (LPARAM)MAKELONG(static_cast(pointScreen.x), static_cast(pointScreen.y))); - - SetTimer(ID_TIP_MSG_TIMER, MAX_TIP_MSG_TIME, NotificationTipTimeoutHandler); + m_toolMsgTipTimer.Start(MAX_TIP_MSG_TIME, wxTIMER_ONE_SHOT); } void CPlayBoardView::ClearNotificationTip() { - KillTimer(ID_TIP_MSG_TIMER); // Kill it in case it's still running + m_toolMsgTipTimer.Stop(); - CToolInfo ti; - m_toolMsgTip.GetToolInfo(ti, this, ID_TIP_PLAYBOARD_MSG); - m_toolMsgTip.SendMessage(TTM_TRACKACTIVATE, (WPARAM)FALSE, (LPARAM)&ti); - m_toolMsgTip.DelTool(this, ID_TIP_PLAYBOARD_MSG); - m_toolMsgTip.Activate(FALSE); + m_toolMsgTip.TrackActivate(*this, false); + m_toolMsgTip.Delete(*this); + m_toolMsgTip.Enable(false); } -void CALLBACK CPlayBoardView::NotificationTipTimeoutHandler(HWND hwnd, - UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +void CPlayBoardView::NotificationTipTimeoutHandler(wxTimerEvent& /*event*/) { - CPlayBoardView* pView = (CPlayBoardView*)CWnd::FromHandle(hwnd); - ASSERT(pView != NULL); - pView->ClearNotificationTip(); + ClearNotificationTip(); } ////////////////////////////////////////////////////////////////////// -CDrawObj* CPlayBoardView::ObjectHitTest(CPoint point) +CDrawObj* CPlayBoardView::ObjectHitTest(wxPoint point) { CDrawList& pDwg = CheckedDeref(m_pPBoard->GetPieceList()); - return pDwg.HitTest(point); + return pDwg.HitTest(CB::Convert(point)); } ////////////////////////////////////////////////////////////////////// -void CPlayBoardView::SelectWithinRect(CRect rctNet, BOOL bInclIntersects) +void CPlayBoardView::SelectWithinRect(wxRect rctNet, BOOL bInclIntersects) { - CGamDoc* pDoc = GetDocument(); + CGamDoc& pDoc = GetDocument(); CDrawList& pDwg = CheckedDeref(m_pPBoard->GetPieceList()); BOOL bPieceSelected = FALSE; @@ -234,15 +229,15 @@ void CPlayBoardView::SelectWithinRect(CRect rctNet, BOOL bInclIntersects) if (!m_selList.IsObjectSelected(pObj)) { if ((!bInclIntersects && - ((pObj.GetEnclosingRect() | rctNet) == rctNet)) || + ((CB::Convert(pObj.GetEnclosingRect()).Union(rctNet)) == rctNet)) || (bInclIntersects && - (!(pObj.GetEnclosingRect() & rctNet).IsRectEmpty()))) + (!(CB::Convert(pObj.GetEnclosingRect()).Intersect(rctNet)).IsEmpty()))) { BOOL bOwnedByCurrentPlayer = TRUE; if (pObj.GetType() == CDrawObj::drawPieceObj) { CPieceObj& pPObj = static_cast(pObj); - PlayerMask dwCurrentPlayer = pDoc->GetCurrentPlayerMask(); + PlayerMask dwCurrentPlayer = pDoc.GetCurrentPlayerMask(); bOwnedByCurrentPlayer = !pPObj.IsOwned() || pPObj.IsOwnedBy(dwCurrentPlayer) || m_pPBoard->IsNonOwnerAccessAllowed(); @@ -261,7 +256,7 @@ void CPlayBoardView::SelectWithinRect(CRect rctNet, BOOL bInclIntersects) // - Owned by the current player OR // - Owned but non-owner access is allowed. // (the last three conditions were checked above.) - if (pDoc->IsScenario() || bOwnedByCurrentPlayer) + if (pDoc.IsScenario() || bOwnedByCurrentPlayer) { m_selList.AddObject(pObj, TRUE); bPieceSelected |= pObj.GetType() == CDrawObj::drawPieceObj || @@ -274,15 +269,15 @@ void CPlayBoardView::SelectWithinRect(CRect rctNet, BOOL bInclIntersects) NotifySelectListChange(); } -void CPlayBoardView::SelectAllUnderPoint(CPoint point) +void CPlayBoardView::SelectAllUnderPoint(wxPoint point) { CDrawList* pDwg = m_pPBoard->GetPieceList(); - ASSERT(pDwg); + wxASSERT(pDwg); BOOL bPieceSelected = FALSE; std::vector> selLst; - pDwg->DrillDownHitTest(point, selLst); + pDwg->DrillDownHitTest(CB::Convert(point), selLst); for (size_t i = size_t(0) ; i < selLst.size() ; ++i) { @@ -293,7 +288,7 @@ void CPlayBoardView::SelectAllUnderPoint(CPoint point) if (pObj.GetType() == CDrawObj::drawPieceObj) { CPieceObj& pPObj = static_cast(pObj); - PlayerMask dwCurrentPlayer = GetDocument()->GetCurrentPlayerMask(); + PlayerMask dwCurrentPlayer = GetDocument().GetCurrentPlayerMask(); bOwnedByCurrentPlayer = !pPObj.IsOwned() || pPObj.IsOwnedBy(dwCurrentPlayer); } @@ -377,7 +372,7 @@ void CPlayBoardView::SelectAllMarkers() void CPlayBoardView::SelectMarkersInGroup(size_t nGroup) { CDrawList& pDwg = CheckedDeref(m_pPBoard->GetPieceList()); - CMarkManager& pMgr = GetDocument()->GetMarkManager(); + CMarkManager& pMgr = GetDocument().GetMarkManager(); m_selList.PurgeList(); @@ -408,7 +403,7 @@ void CPlayBoardView::AddDrawObject(CDrawObj::OwnerPtr pObj) if (pDwg != NULL) { pDwg->AddToFront(std::move(pObj)); - GetDocument()->SetModifiedFlag(); + GetDocument().SetModifiedFlag(); } } @@ -445,86 +440,87 @@ void CPlayBoardView::MoveObjsInSelectList(BOOL bToFront, BOOL bInvalidate) } if (bInvalidate) m_selList.InvalidateList(); - GetDocument()->SetModifiedFlag(); + GetDocument().SetModifiedFlag(); } ///////////////////////////////////////////////////////////////////////////// -CPoint CPlayBoardView::GetWorkspaceDim() const +wxPoint CPlayBoardView::GetWorkspaceDim() const { // First get MM_TEXT size of board for this scaling mode. - CPoint pnt = (CPoint)m_pPBoard->GetBoard()->GetSize(m_nZoom); + wxSize size = CB::Convert(m_pPBoard->GetBoard()->GetSize(m_nZoom)); + wxPoint pnt(size.x, size.y); // Translate to current scaling mode. - pnt -= (CSize)GetDeviceScrollPosition(); - ClientToWorkspace(pnt); + pnt = CalcScrolledPosition(pnt); + pnt = ClientToWorkspace(pnt); return pnt; } ///////////////////////////////////////////////////////////////////////////// -void CPlayBoardView::WorkspaceToClient(CPoint& point) const +wxPoint CPlayBoardView::WorkspaceToClient(wxPoint point) const { - CPoint dpnt = GetDeviceScrollPosition(); - CSize wsize, vsize; + wxSize wsize, vsize; m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(m_nZoom, wsize, vsize); if (m_pPBoard->IsBoardRotated180()) - point = CPoint(wsize.cx - point.x, wsize.cy - point.y); + point = wxPoint(wsize.x - point.x, wsize.y - point.y); ScalePoint(point, vsize, wsize); - point -= (CSize)dpnt; + point = CalcScrolledPosition(point); + return point; } -void CPlayBoardView::WorkspaceToClient(CRect& rect) const +wxRect CPlayBoardView::WorkspaceToClient(wxRect rect) const { - CPoint dpnt = GetDeviceScrollPosition(); - CSize wsize, vsize; + wxSize wsize, vsize; m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(m_nZoom, wsize, vsize); if (m_pPBoard->IsBoardRotated180()) { - rect = CRect(wsize.cx - rect.left, wsize.cy - rect.top, - wsize.cx - rect.right, wsize.cy - rect.bottom); - rect.NormalizeRect(); + rect = wxRect(wxPoint(wsize.x - rect.GetLeft(), wsize.y - rect.GetTop()), + wxSize(-rect.GetWidth(), -rect.GetHeight())); + CB::Normalize(rect); } ScaleRect(rect, vsize, wsize); - rect -= dpnt; + rect.SetLeftTop(CalcScrolledPosition(rect.GetTopLeft())); + return rect; } -void CPlayBoardView::InvalidateWorkspaceRect(const CRect& pRect, BOOL bErase) +void CPlayBoardView::InvalidateWorkspaceRect(const wxRect& pRect, BOOL bErase) { - CRect rct(pRect); - WorkspaceToClient(rct); - rct.InflateRect(1, 1); - InvalidateRect(&rct, bErase); + wxRect rct(pRect); + rct = WorkspaceToClient(rct); + rct.Inflate(1, 1); + RefreshRect(rct, bErase); } -void CPlayBoardView::ClientToWorkspace(CPoint& point) const +wxPoint CPlayBoardView::ClientToWorkspace(wxPoint point) const { - CPoint dpnt = GetDeviceScrollPosition(); - point += (CSize)dpnt; - CSize wsize, vsize; + point = CalcUnscrolledPosition(point); + wxSize wsize, vsize; m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(m_nZoom, wsize, vsize); ScalePoint(point, wsize, vsize); if (m_pPBoard->IsBoardRotated180()) - point = CPoint(wsize.cx - point.x, wsize.cy - point.y); + point = wxPoint(wsize.x - point.x, wsize.y - point.y); + return point; } -void CPlayBoardView::ClientToWorkspace(CRect& rect) const +wxRect CPlayBoardView::ClientToWorkspace(wxRect rect) const { - CPoint dpnt = GetDeviceScrollPosition(); - rect += dpnt; - CSize wsize, vsize; + rect.SetLeftTop(CalcUnscrolledPosition(rect.GetLeftTop())); + wxSize wsize, vsize; m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(m_nZoom, wsize, vsize); ScaleRect(rect, wsize, vsize); if (m_pPBoard->IsBoardRotated180()) { - rect = CRect(wsize.cx - rect.left, wsize.cy - rect.top, - wsize.cx - rect.right, wsize.cy - rect.bottom); - rect.NormalizeRect(); + rect = wxRect(wxPoint(wsize.x - rect.GetLeft(), wsize.y - rect.GetTop()), + wxSize(-rect.GetWidth(), -rect.GetHeight())); + CB::Normalize(rect); } + return rect; } ////////////////////////////////////////////////////////////////////// @@ -536,25 +532,27 @@ BOOL CPlayBoardView::IsGridizeActive() const return !(bControl && bGridSnap || !bControl && !bGridSnap); } -void CPlayBoardView::GridizeX(long& xPos) const +long CPlayBoardView::GridizeX(long xPos) const { if (IsGridizeActive()) { xPos = GridizeClosest1000(value_preserving_cast(xPos), value_preserving_cast(m_pPBoard->m_xGridSnap), value_preserving_cast(m_pPBoard->m_xGridSnapOff)); } + return xPos; } -void CPlayBoardView::GridizeY(long& yPos) const +long CPlayBoardView::GridizeY(long yPos) const { if (IsGridizeActive()) { yPos = GridizeClosest1000(value_preserving_cast(yPos), value_preserving_cast(m_pPBoard->m_yGridSnap), value_preserving_cast(m_pPBoard->m_yGridSnapOff)); } + return yPos; } -void CPlayBoardView::LimitPoint(POINT& pPnt) const +wxPoint CPlayBoardView::LimitPoint(wxPoint pPnt) const { const CBoard* pBoard = m_pPBoard->GetBoard(); if (pPnt.x < 0) pPnt.x = 0; @@ -563,38 +561,38 @@ void CPlayBoardView::LimitPoint(POINT& pPnt) const if (pPnt.y < 0) pPnt.y = 0; if (pPnt.y > pBoard->GetHeight(fullScale)) pPnt.y = pBoard->GetHeight(fullScale); + return pPnt; } -void CPlayBoardView::LimitRect(RECT& pRct) const +wxRect CPlayBoardView::LimitRect(wxRect rct) const { - CRect rct(pRct); const CBoard* pBoard = m_pPBoard->GetBoard(); - if (rct.left < 0) - rct.OffsetRect(-rct.left, 0); - if (rct.top < 0) - rct.OffsetRect(0, -rct.top); - if (rct.right > pBoard->GetWidth(fullScale)) - rct.OffsetRect(pBoard->GetWidth(fullScale) - rct.right, 0); - if (rct.bottom > pBoard->GetHeight(fullScale)) - rct.OffsetRect(0, pBoard->GetHeight(fullScale) - rct.bottom); - pRct = rct; + if (rct.GetLeft() < 0) + rct.Offset(-rct.GetLeft(), 0); + if (rct.GetTop() < 0) + rct.Offset(0, -rct.GetTop()); + if (rct.GetRight() > pBoard->GetWidth(fullScale)) + rct.Offset(pBoard->GetWidth(fullScale) - rct.GetRight(), 0); + if (rct.GetBottom() > pBoard->GetHeight(fullScale)) + rct.Offset(0, pBoard->GetHeight(fullScale) - rct.GetBottom()); + return rct; } -BOOL CPlayBoardView::IsRectFullyOnBoard(const RECT& pRct, BOOL* pbXOK, BOOL* pbYOK) const +BOOL CPlayBoardView::IsRectFullyOnBoard(const wxRect& pRct, BOOL* pbXOK, BOOL* pbYOK) const { - CRect rct(pRct); + wxRect rct(pRct); const CBoard* pBoard = m_pPBoard->GetBoard(); BOOL bXOK = TRUE; BOOL bYOK = TRUE; BOOL bOK = TRUE; - if (rct.left < 0 || rct.right > pBoard->GetWidth(fullScale)) + if (rct.GetLeft() < 0 || rct.GetRight() > pBoard->GetWidth(fullScale)) { bXOK = FALSE; bOK = FALSE; } - if (rct.top < 0 || rct.bottom > pBoard->GetHeight(fullScale)) + if (rct.GetTop() < 0 || rct.GetBottom() > pBoard->GetHeight(fullScale)) { bYOK = FALSE; bOK = FALSE; @@ -604,129 +602,107 @@ BOOL CPlayBoardView::IsRectFullyOnBoard(const RECT& pRct, BOOL* pbXOK, BOOL* pbY return bOK; } -void CPlayBoardView::AdjustPoint(CPoint& pnt) const +void CPlayBoardView::SetTimer(int id, unsigned milliseconds) +{ + wxASSERT(!timer); + timer = MakeOwner(this, id); + CB_VERIFY(timer->Start(value_preserving_cast(milliseconds))); +} + +void CPlayBoardView::KillTimer(int id) { - GridizeX(pnt.x); - GridizeY(pnt.y); - LimitPoint(pnt); + wxASSERT(timer && timer->GetId() == id); + timer = nullptr; } -void CPlayBoardView::AdjustRect(CRect& rct) const +wxPoint CPlayBoardView::AdjustPoint(wxPoint pnt) const { - CPoint pnt; + pnt.x = GridizeX(pnt.x); + pnt.y = GridizeY(pnt.y); + pnt = LimitPoint(pnt); + return pnt; +} + +wxRect CPlayBoardView::AdjustRect(wxRect rct) const +{ + wxPoint pnt; if (m_pPBoard->m_bGridRectCenters) pnt = GetMidRect(rct); else - pnt = rct.TopLeft(); + pnt = rct.GetLeftTop(); - GridizeX(pnt.x); - GridizeY(pnt.y); - LimitPoint(pnt); + pnt.x = GridizeX(pnt.x); + pnt.y = GridizeY(pnt.y); + pnt = LimitPoint(pnt); if (m_pPBoard->m_bGridRectCenters) { if (pnt != GetMidRect(rct)) - rct.OffsetRect(pnt - GetMidRect(rct)); + rct.Offset(pnt - GetMidRect(rct)); } else { - if (pnt != rct.TopLeft()) - rct.OffsetRect(pnt - rct.TopLeft()); + if (pnt != rct.GetLeftTop()) + rct.Offset(pnt - rct.GetLeftTop()); } - LimitRect(rct); + rct = LimitRect(rct); + return rct; } ////////////////////////////////////////////////////////////////////// -void CPlayBoardView::ScrollWorkspacePointIntoView(CPoint point) +void CPlayBoardView::ScrollWorkspacePointIntoView(wxPoint point) { - CRect rct; - GetClientRect(&rct); - if ((rct.Height() < 2 * viewZone) || (rct.Width() < 2 * viewZone)) + wxRect rct = GetClientRect(); + if ((rct.GetHeight() < 2 * viewZone) || (rct.GetWidth() < 2 * viewZone)) { // Attempt to center point. CenterViewOnWorkspacePoint(point); return; } - rct.InflateRect(-viewZone, -viewZone); - ClientToWorkspace(rct); - if (rct.PtInRect(point)) + rct.Inflate(-viewZone, -viewZone); + rct = ClientToWorkspace(rct); + if (rct.Contains(point)) return; // Everthing is ok CenterViewOnWorkspacePoint(point); } -void CPlayBoardView::CenterViewOnWorkspacePoint(CPoint point) +void CPlayBoardView::CenterViewOnWorkspacePoint(wxPoint point) { - WorkspaceToClient(point); - CRect rct; - GetClientRect(&rct); - CPoint pt = GetMidRect(rct); - CSize size = point - pt; - CPoint newUpLeft = GetDeviceScrollPosition() + size; + point = WorkspaceToClient(point); + wxRect rct = GetClientRect(); + wxPoint pt = GetMidRect(rct); + wxPoint size = point - pt; + wxPoint newUpLeft = CalcUnscrolledPosition(size); // If the axis being scrolled is entirely visible then set // that scroll position to zero. - CSize sizeTotal = GetTotalSize(); // Logical is in device units for us - if (rct.Width() >= sizeTotal.cx) + wxSize sizeTotal = GetVirtualSize(); // Logical is in device units for us + if (rct.GetWidth() >= sizeTotal.x) newUpLeft.x = 0; - if (rct.Height() >= sizeTotal.cy) + if (rct.GetHeight() >= sizeTotal.y) newUpLeft.y = 0; - ScrollToPosition(newUpLeft); - UpdateWindow(); + Scroll(newUpLeft); + Update(); } -////////////////////////////////////////////////////////////////////////// -// point is in client coords - -BOOL CPlayBoardView::CheckAutoScroll(CPoint point) +// this method can be overridden in a derived class to forbid sending the +// auto scroll events - note that unlike StopAutoScrolling() it doesn't +// stop the timer, so it will be called repeatedly and will typically +// return different values depending on the current mouse position +bool CPlayBoardView::SendAutoScrollEvents(wxScrollWinEvent& event) const { - CRect rctClient; - CRect rct; - - GetClientRect(&rctClient); - rct = rctClient; - rct.InflateRect(-scrollZone, -scrollZone); - rct.NormalizeRect(); - - return rctClient.PtInRect(point) && !rct.PtInRect(point); -} - -// Returns TRUE if scroll happened -BOOL CPlayBoardView::ProcessAutoScroll(CPoint point) -{ - CRect rectClient; - CRect rect; - - GetClientRect(&rectClient); - rect = rectClient; - rect.InflateRect(-scrollZone, -scrollZone); - rect.NormalizeRect(); - - UINT nScrollID = MAKEWORD(-1, -1); - if (rectClient.PtInRect(point) && !rect.PtInRect(point)) + // scroll if this is the capturing window (net select) + // or this is drag destination + wxASSERT(event.GetEventObject() == this); + if (HasCapture() || GetAutoscrollWithoutCapture()) { - // Mouse is in the scroll zone.... - // Determine which way to scroll along both X & Y axis - if (point.x < rect.left) - nScrollID = MAKEWORD(SB_LINEUP, HIBYTE(nScrollID)); - else if (point.x >= rect.right) - nScrollID = MAKEWORD(SB_LINEDOWN, HIBYTE(nScrollID)); - if (point.y < rect.top) - nScrollID = MAKEWORD(LOBYTE(nScrollID), SB_LINEUP); - else if (point.y >= rect.bottom) - nScrollID = MAKEWORD(LOBYTE(nScrollID), SB_LINEDOWN); - ASSERT(nScrollID != MAKEWORD(-1, -1)); - // First check if scroll can happen. - BOOL bValidScroll = OnScroll(nScrollID, 0, FALSE); - if (bValidScroll) - { - OnScroll(nScrollID, 0, TRUE); - UpdateWindow(); // Redraw image content. - return TRUE; - } + return true; } - return FALSE; -} - + // scroll if drag-move + CPlayTool& tool = CPlayTool::GetTool(ptypeSelect); + CPSelectTool& select = dynamic_cast(tool); + return select.m_eSelMode == CPSelectTool::smodeMove; +} diff --git a/GP/VwPrjga1.cpp b/GP/VwPrjga1.cpp index 6ba3dcc9..cf881eef 100644 --- a/GP/VwPrjga1.cpp +++ b/GP/VwPrjga1.cpp @@ -31,6 +31,7 @@ #include "Trays.h" #include "MoveHist.h" +#include "VwPbrd.h" #include "VwPrjgam.h" #ifdef _DEBUG @@ -105,7 +106,7 @@ void CGamProjView::DoBoardView() AfxMessageBox(IDS_ERR_PRIVATE_BOARD_PERM, MB_OK | MB_ICONEXCLAMATION); return; } - CView* pView = pDoc->FindPBoardView(pPBoard); + CPlayBoardView* pView = pDoc->FindPBoardView(pPBoard); if (pView != NULL) { // This board already has an editor. Activate that view. diff --git a/GP/VwPrjgs1.cpp b/GP/VwPrjgs1.cpp index 5edadb3f..b83e8d56 100644 --- a/GP/VwPrjgs1.cpp +++ b/GP/VwPrjgs1.cpp @@ -32,6 +32,7 @@ #include "Trays.h" #include "Player.h" +#include "VwPbrd.h" #include "VwPrjgsn.h" #include "DlgScnp.h" @@ -96,7 +97,7 @@ void CGsnProjView::DoBoardView() size_t nBrd = m_listProj->GetItemSourceCode(value_preserving_cast(nSel)); CPlayBoard& pPBoard = pDoc.GetPBoardManager().GetPBoard(nBrd); - CView* pView = pDoc.FindPBoardView(pPBoard); + CPlayBoardView* pView = pDoc.FindPBoardView(pPBoard); if (pView != NULL) { // This board already has an editor. Activate that view. diff --git a/GP/VwPrjgsn.cpp b/GP/VwPrjgsn.cpp index 6e8f279b..9be23f59 100644 --- a/GP/VwPrjgsn.cpp +++ b/GP/VwPrjgsn.cpp @@ -499,7 +499,7 @@ void CGsnProjView::DoUpdateProjectList(BOOL bUpdateItem /* = TRUE */) m_listProj->ScrollToRow(nTopIdx); if (nCurSel != wxNOT_FOUND) { - if (nCurSel >= m_listProj->GetItemCount()) + if (nCurSel >= value_preserving_cast(m_listProj->GetItemCount())) nCurSel = value_preserving_cast(m_listProj->GetItemCount() - size_t(1)); m_listProj->SetSelection(nCurSel); } diff --git a/GP/VwPrjgsn.h b/GP/VwPrjgsn.h index 943d6537..dcb76f8e 100644 --- a/GP/VwPrjgsn.h +++ b/GP/VwPrjgsn.h @@ -68,7 +68,8 @@ class CProjListBoxGsn : public CProjListBoxWx, private CB::Impl::CGsnProjViewBase { -public: + friend class CGsnProjViewContainer; +private: CGsnProjView(CGsnProjViewContainer& p); // Attributes @@ -181,8 +182,6 @@ class CGsnProjView : public CB::ProcessEventOverride, private CB::Impl: RefPtr parent; RefPtr document; - - friend class CGsnProjViewContainer; }; class CGsnProjViewContainer : public CB::OnCmdMsgOverride, diff --git a/GP/VwSelpce.cpp b/GP/VwSelpce.cpp index edc71c7c..c2fa39ff 100644 --- a/GP/VwSelpce.cpp +++ b/GP/VwSelpce.cpp @@ -1,6 +1,6 @@ // VwSelpce.cpp : Selected Piece List View // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -36,7 +36,8 @@ static char THIS_FILE[] = __FILE__; #endif -IMPLEMENT_DYNCREATE(CSelectedPieceView, CView) +// KLUDGE: compile fails for base CSelectedPieceViewContainer::BASE +IMPLEMENT_DYNCREATE(CSelectedPieceViewContainer, CView) #ifdef _DEBUG #define new DEBUG_NEW @@ -44,23 +45,50 @@ IMPLEMENT_DYNCREATE(CSelectedPieceView, CView) ///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CSelectedPieceView, CView) - //{{AFX_MSG_MAP(CSelectedPieceView) +wxBEGIN_EVENT_TABLE(CSelectedPieceView, CSelectedPieceView::BASE) +#if 0 ON_WM_CREATE() - ON_WM_SIZE() - ON_WM_ERASEBKGND() +#endif + EVT_SIZE(OnSize) +#if 0 ON_WM_MOUSEACTIVATE() +#endif + /* see ctor ON_WM_VKEYTOITEM() - //}}AFX_MSG_MAP + */ + EVT_WINSTATE(OnMessageWindowState) +wxEND_EVENT_TABLE() + +BEGIN_MESSAGE_MAP(CSelectedPieceViewContainer, CSelectedPieceViewContainer::BASE) + ON_WM_CREATE() + ON_WM_SIZE() + ON_WM_MOUSEACTIVATE() ON_MESSAGE(WM_WINSTATE, OnMessageWindowState) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CSelectedPieceView -CSelectedPieceView::CSelectedPieceView() +CSelectedPieceView::CSelectedPieceView(CSelectedPieceViewContainer& p) : + parent(&p), + document(dynamic_cast(parent->GetDocument())), + m_pPBoard(static_cast(document->GetNewViewParameter())), + m_listSel(new CSelectListBox) { - m_pPBoard = NULL; + BASE::Create(*parent, 0); + m_listSel->Create(this, wxID_ANY, + wxDefaultPosition, wxDefaultSize, + wxLB_MULTIPLE); + /* wx doesn't support WM_VKEYTOITEM, + and wxEVT_CHAR doesn't propagate to parent */ + m_listSel->Bind(wxEVT_CHAR, &CSelectedPieceView::OnVKeyToItem, this); + + CB::string str = CB::string::LoadString(IDS_TIP_SELLIST_HELP); + m_toolTip.Add(*m_listSel, str, CB::ToolTip::CENTER); + + m_toolTip.Enable(TRUE); + + OnInitialUpdate(); } CSelectedPieceView::~CSelectedPieceView() @@ -69,6 +97,7 @@ CSelectedPieceView::~CSelectedPieceView() ///////////////////////////////////////////////////////////////////////////// +#if 0 int CSelectedPieceView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) @@ -97,33 +126,21 @@ int CSelectedPieceView::OnCreate(LPCREATESTRUCT lpCreateStruct) return 0; } +#endif -void CSelectedPieceView::OnSize(UINT nType, int cx, int cy) -{ - CView::OnSize(nType, cx, cy); - m_listSel.MoveWindow(-1, -1, cx + 1, cy + 1, TRUE); - m_toolTip.SetMaxTipWidth(4 * cx); -} - -///////////////////////////////////////////////////////////////////////////// - -BOOL CSelectedPieceView::PreTranslateMessage(MSG* pMsg) +void CSelectedPieceView::OnSize(wxSizeEvent& event) { - // RelayEvent is required for CToolTipCtrl objects - - // it passes mouse messages on to the tool tip control - // so it can decide when to show the tool tip - m_toolTip.RelayEvent(pMsg); - - return CView::PreTranslateMessage(pMsg); + event.Skip(); + m_listSel->SetSize(0, 0, event.GetSize().x, event.GetSize().y); + m_toolTip.SetMaxWidth(4 * event.GetSize().x); } ///////////////////////////////////////////////////////////////////////////// void CSelectedPieceView::OnInitialUpdate() { - m_pPBoard = (CPlayBoard*)GetDocument()->GetNewViewParameter(); - CView::OnInitialUpdate(); - m_listSel.SetDocument(GetDocument()); + parent->OnInitialUpdate(); + m_listSel->SetDocument(GetDocument()); } void CSelectedPieceView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) @@ -131,28 +148,28 @@ void CSelectedPieceView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) CGamDocHint* ph = (CGamDocHint*)pHint; if (lHint == HINT_UPDATESELECT && ph->GetArgs().m_pPBoard == m_pPBoard) { - ASSERT(ph->GetArgs().m_pSelList != NULL); + wxASSERT(ph->GetArgs().m_pSelList != NULL); CSelList* pSLst = ph->GetArgs().m_pSelList; if (!pSLst->HasPieces() && !pSLst->HasMarkers()) { - m_listSel.SetItemMap(NULL); + m_listSel->SetItemMap(NULL); m_tblSel.clear(); return; } pSLst->LoadTableWithObjectPtrs(m_tblSel, CSelList::otPiecesMarks, TRUE); - m_listSel.SetItemMap(&m_tblSel); + m_listSel->SetItemMap(&m_tblSel); } else if (lHint == HINT_GAMESTATEUSED) { - m_listSel.SetItemMap(NULL); + m_listSel->SetItemMap(NULL); m_tblSel.clear(); return; } else if (lHint == HINT_UPDATEOBJECT && ph->GetArgs().m_pPBoard == m_pPBoard) { - Invalidate(); + Refresh(); } } @@ -160,97 +177,131 @@ void CSelectedPieceView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) // This message is sent when a document is being saved. // WPARAM = CArchive*, LPARAM = 0 if save, 1 if restore -LRESULT CSelectedPieceView::OnMessageWindowState(WPARAM wParam, LPARAM lParam) +void CSelectedPieceView::OnMessageWindowState(WinStateEvent& /*event*/) { - return (LRESULT)0; } ///////////////////////////////////////////////////////////////////////////// // CSelectedPieceView drawing -void CSelectedPieceView::OnDraw(CDC* pDC) -{ - // Eat this since view is filled with a list box. -} - -BOOL CSelectedPieceView::OnEraseBkgnd(CDC* pDC) -{ - // Eat this since view is filled with a list box. - return TRUE; -} - ///////////////////////////////////////////////////////////////////////////// #ifdef _DEBUG -CGamDoc* CSelectedPieceView::GetDocument() // non-debug version is inline +CGamDoc& CSelectedPieceView::GetDocument() // non-debug version is inline { - CGamDoc* retval = CB::ToCGamDoc(m_pDocument); - wxASSERT(retval); - return retval; + return *document; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CSelectedPieceView message handlers +#if 0 int CSelectedPieceView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) { // We don't want the frame to ever consider this view to be the // "active" view. return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message); } +#endif -int CSelectedPieceView::OnVKeyToItem(UINT nKey, CListBox* pListBox, UINT nIndex) +void CSelectedPieceView::OnVKeyToItem(wxKeyEvent& event) { - if (nKey == VK_DELETE) + int nKey = event.GetKeyCode(); + if (nKey == WXK_DELETE) { ModifySelectionsBasedOnListItems(TRUE); - return -2; } - else if (nKey == VK_INSERT) + else if (nKey == WXK_INSERT) { ModifySelectionsBasedOnListItems(FALSE); - return -2; } else - return CView::OnVKeyToItem(nKey, pListBox, nIndex); + { + event.Skip(); + } } // Either removes or keeps items selected in listbox. void CSelectedPieceView::ModifySelectionsBasedOnListItems(BOOL bRemoveSelectedItems) { // Get the indexes of all the selected items. - int nCount = m_listSel.GetSelCount(); - CArray tblListBoxSel; - - tblListBoxSel.SetSize(nCount); - m_listSel.GetSelItems(nCount, tblListBoxSel.GetData()); + std::vector tblListBoxSel = m_listSel->GetSelections(); // Create a list containing all items that are *not* selected. // Rather than try to be real clever I'll just brute force the search. std::vector> listDObj; - for (int nItem = 0; nItem < m_listSel.GetCount(); nItem++) + for (size_t nItem = size_t(0) ; nItem < m_listSel->GetItemCount() ; ++nItem) { // Loop and see if item is in selected list. - int nSelItem; - for (nSelItem = 0; nSelItem < tblListBoxSel.GetSize(); nSelItem++) + size_t nSelItem; + for (nSelItem = size_t(0) ; nSelItem < tblListBoxSel.size() ; ++nSelItem) { - if (tblListBoxSel.GetAt(nSelItem) == nItem) + if (tblListBoxSel.at(nSelItem) == nItem) break; } - if (bRemoveSelectedItems && nSelItem == tblListBoxSel.GetSize()) + if (bRemoveSelectedItems && nSelItem == tblListBoxSel.size()) { // Not a listbox selection so add it to new select list. - listDObj.push_back(&m_listSel.MapIndexToItem(value_preserving_cast(nItem))); + listDObj.push_back(&m_listSel->MapIndexToItem(nItem)); } - else if (!bRemoveSelectedItems && nSelItem < tblListBoxSel.GetSize()) + else if (!bRemoveSelectedItems && nSelItem < tblListBoxSel.size()) { // It is a listbox selection so add it to new select list. - listDObj.push_back(&m_listSel.MapIndexToItem(value_preserving_cast(nItem))); + listDObj.push_back(&m_listSel->MapIndexToItem(nItem)); } } - CPlayBoardFrame* pFrame = (CPlayBoardFrame*)GetParentFrame(); - pFrame->SendMessageToActiveBoardPane(WM_SELECT_BOARD_OBJLIST, (WPARAM)m_pPBoard, + CPlayBoardFrame* pFrame = static_cast(parent->GetParentFrame()); + pFrame->SendMessageToActiveBoardPane(WM_SELECT_BOARD_OBJLIST, (WPARAM)&*m_pPBoard, (LPARAM)&listDObj); } +void CSelectedPieceViewContainer::OnDraw(CDC* pDC) +{ + // do nothing because child covers entire client rect +} + +void CSelectedPieceViewContainer::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) +{ + child->OnUpdate(pSender, lHint, pHint); + + BASE::OnUpdate(pSender, lHint, pHint); +} + +CSelectedPieceViewContainer::CSelectedPieceViewContainer() : + CB::wxNativeContainerWindowMixin(static_cast(*this)) +{ +} + +int CSelectedPieceViewContainer::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (BASE::OnCreate(lpCreateStruct) == -1) + { + return -1; + } + + child = new CSelectedPieceView(*this); + + return 0; +} + +void CSelectedPieceViewContainer::OnSize(UINT nType, int cx, int cy) +{ + child->SetSize(0, 0, cx, cy); + return BASE::OnSize(nType, cx, cy); +} + +int CSelectedPieceViewContainer::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) +{ + // We don't want the frame to ever consider this view to be the + // "active" view. + return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message); +} + +LRESULT CSelectedPieceViewContainer::OnMessageWindowState(WPARAM wParam, LPARAM lParam) +{ + WinStateEvent event(*reinterpret_cast(wParam), bool(lParam)); + child->ProcessWindowEvent(event); + return (LRESULT)1; +} + diff --git a/GP/VwSelpce.h b/GP/VwSelpce.h index e4bc7425..d2730057 100644 --- a/GP/VwSelpce.h +++ b/GP/VwSelpce.h @@ -1,6 +1,6 @@ // VwSelpce.h : header file // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -31,52 +31,93 @@ class CPlayBoard; ///////////////////////////////////////////////////////////////////////////// // CSelectedPieceView view -class CSelectedPieceView : public CView +class CSelectedPieceView : public CB::ProcessEventOverride { - DECLARE_DYNCREATE(CSelectedPieceView) -protected: - CSelectedPieceView(); // protected constructor used by dynamic creation +private: + friend class CSelectedPieceViewContainer; + typedef CB::ProcessEventOverride BASE; + CSelectedPieceView(CSelectedPieceViewContainer& parent); // Attributes -public: - CGamDoc* GetDocument(); +private: + CGamDoc& GetDocument(); // Operations public: // Implementation +private: + RefPtr parent; + RefPtr document; protected: - CPlayBoard* m_pPBoard; // Board that contains selections + RefPtr m_pPBoard; // Board that contains selections - CSelectListBox m_listSel; - std::vector> m_tblSel; - CToolTipCtrl m_toolTip; + // owned by wx + RefPtr m_listSel; + std::vector> m_tblSel; + CB::ToolTip m_toolTip; // Implementation protected: void ModifySelectionsBasedOnListItems(BOOL bRemoveSelectedItems); - virtual ~CSelectedPieceView(); - virtual void OnDraw(CDC* pDC); // overridden to draw this view - virtual void OnInitialUpdate(); - virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); - virtual BOOL PreTranslateMessage(MSG* pMsg); + ~CSelectedPieceView() override; + void OnInitialUpdate(); // first time after construct + void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); -// Generated message map functions protected: - //{{AFX_MSG(CSelectedPieceView) +#if 0 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnSize(UINT nType, int cx, int cy); - afx_msg BOOL OnEraseBkgnd(CDC* pDC); +#endif + void OnSize(wxSizeEvent& event); +#if 0 afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message); - afx_msg int OnVKeyToItem(UINT nKey, CListBox* pListBox, UINT nIndex); - //}}AFX_MSG - afx_msg LRESULT OnMessageWindowState(WPARAM wParam, LPARAM lParam); - DECLARE_MESSAGE_MAP() +#endif + void OnVKeyToItem(wxKeyEvent& event); + void OnMessageWindowState(WinStateEvent& event); + wxDECLARE_EVENT_TABLE(); + +private: + // IGetCmdTarget + CCmdTarget& Get() override; }; #ifndef _DEBUG // debug version in vwselpce.cpp -inline CGamDoc* CSelectedPieceView::GetDocument() - { return CB::ToCGamDoc(m_pDocument); } +inline CGamDoc& CSelectedPieceView::GetDocument() + { return *document; } #endif +class CSelectedPieceViewContainer : public CB::OnCmdMsgOverride, + public CB::wxNativeContainerWindowMixin +{ +public: + void OnDraw(CDC* pDC) override; + + void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) override; + +private: + CSelectedPieceViewContainer(); // used by dynamic creation + DECLARE_DYNCREATE(CSelectedPieceViewContainer) + + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message); + afx_msg LRESULT OnMessageWindowState(WPARAM wParam, LPARAM lParam); + DECLARE_MESSAGE_MAP() + + // IGetEvtHandler + wxEvtHandler& Get() override + { + return CheckedDeref(CheckedDeref(child).GetEventHandler()); + } + + // owned by wx + CB::propagate_const child = nullptr; + + typedef CB::OnCmdMsgOverride BASE; +}; + +inline CCmdTarget& CSelectedPieceView::Get() +{ + return *parent; +} diff --git a/GP/VwTbrd.cpp b/GP/VwTbrd.cpp index 4cab291b..b74f20d1 100644 --- a/GP/VwTbrd.cpp +++ b/GP/VwTbrd.cpp @@ -1,6 +1,6 @@ // VwTbrd.cpp : Small scale playing board view. // -// Copyright (c) 1994-2023 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -37,7 +37,7 @@ static char THIS_FILE[] = __FILE__; #endif -IMPLEMENT_DYNCREATE(CTinyBoardView, CScrollView) +IMPLEMENT_DYNCREATE(CTinyBoardViewContainer, CView) #ifdef _DEBUG #define new DEBUG_NEW @@ -45,23 +45,41 @@ IMPLEMENT_DYNCREATE(CTinyBoardView, CScrollView) ///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CTinyBoardView, CScrollView) - //{{AFX_MSG_MAP(CTinyBoardView) - ON_WM_LBUTTONDOWN() - ON_WM_RBUTTONDOWN() +wxBEGIN_EVENT_TABLE(CTinyBoardView, CB::ProcessEventOverride) + EVT_LEFT_DOWN(OnLButtonDown) + EVT_RIGHT_DOWN(OnRButtonDown) +#if 0 + ON_WM_MOUSEACTIVATE() +#endif + EVT_WINSTATE(OnMessageWindowState) +wxEND_EVENT_TABLE() + +BEGIN_MESSAGE_MAP(CTinyBoardViewContainer, CTinyBoardViewContainer::BASE) + ON_WM_CREATE() +#if 0 + ON_WM_SIZE() +#endif ON_WM_MOUSEACTIVATE() - //}}AFX_MSG_MAP ON_MESSAGE(WM_WINSTATE, OnMessageWindowState) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTinyBoardView -CTinyBoardView::CTinyBoardView() +CTinyBoardView::CTinyBoardView(CTinyBoardViewContainer& p) : + parent(&p), + document(dynamic_cast(parent->GetDocument())), + m_pPBoard(static_cast(document->GetNewViewParameter())) { - m_pPBoard = NULL; + // use sizers for scrolling + wxSizer* sizer = new wxBoxSizer(wxVERTICAL); + SetSizer(sizer); + sizer->Add(0, 0); + BASE::Create(*parent, 0); + OnInitialUpdate(); } +#if 0 BOOL CTinyBoardView::PreCreateWindow(CREATESTRUCT& cs) { if (!CScrollView::PreCreateWindow(cs)) @@ -73,16 +91,13 @@ BOOL CTinyBoardView::PreCreateWindow(CREATESTRUCT& cs) return TRUE; } +#endif ///////////////////////////////////////////////////////////////////////////// void CTinyBoardView::OnInitialUpdate() { - CScrollView::OnInitialUpdate(); - - m_pPBoard = (CPlayBoard*)GetDocument()->GetNewViewParameter(); - CBoard* pBoard = m_pPBoard->GetBoard(); - SetScrollSizes(MM_TEXT, pBoard->GetSize(smallScale)); + RecalcScrollLimits(); } void CTinyBoardView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) @@ -90,265 +105,311 @@ void CTinyBoardView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) CGamDocHint* ph = (CGamDocHint*)pHint; if (lHint == HINT_UPDATEOBJECT && ph->GetArgs().m_pPBoard == m_pPBoard) { - CRect rct; - rct = ph->GetArgs().m_pDrawObj->GetEnclosingRect(); // In board coords. - InvalidateWorkspaceRect(&rct); + wxRect rct; + rct = CB::Convert(ph->GetArgs().m_pDrawObj->GetEnclosingRect()); // In board coords. + InvalidateWorkspaceRect(rct); } else if (lHint == HINT_UPDATEOBJLIST && ph->GetArgs().m_pPBoard == m_pPBoard) { - const std::vector>& pPtrList = *ph->GetArgs().m_pPtrList; + wxASSERT(!"untested code"); + const std::vector>& pPtrList = *ph->GetArgs().m_pPtrList; for (size_t i = size_t(0); i < pPtrList.size(); ++i) { - CDrawObj& pDObj = *pPtrList[i]; - CRect rct = pDObj.GetEnclosingRect(); // In board coords. - InvalidateWorkspaceRect(&rct); + const CDrawObj& pDObj = *pPtrList[i]; + wxRect rct = CB::Convert(pDObj.GetEnclosingRect()); // In board coords. + InvalidateWorkspaceRect(rct); } } else if (lHint == HINT_UPDATEBOARD && ph->GetArgs().m_pPBoard == m_pPBoard) { - m_pBMap = nullptr; - Invalidate(); + m_pBMap = wxBitmap(); + Refresh(); } else if (lHint == HINT_ALWAYSUPDATE || lHint == HINT_GAMESTATEUSED) - CScrollView::OnUpdate(pSender, lHint, pHint); + { + parent->CTinyBoardViewContainer::BASE::OnUpdate(pSender, lHint, pHint); + } } /////////////////////////////////////////////////////////////////////// // This message is sent when a document is being saved. -// WPARAM = CArchive*, LPARAM = 0 if save, 1 if restore -LRESULT CTinyBoardView::OnMessageWindowState(WPARAM wParam, LPARAM lParam) +void CTinyBoardView::OnMessageWindowState(WinStateEvent& event) { - ASSERT(wParam != NULL); - CArchive& ar = *((CArchive*)wParam); + CArchive& ar = event.GetArchive(); if (ar.IsStoring()) { - CPoint pnt = GetScrollPosition(); - ar << (DWORD)pnt.x; - ar << (DWORD)pnt.y; + wxPoint pnt = GetViewStart(); + ar << value_preserving_cast(pnt.x); + ar << value_preserving_cast(pnt.y); } else { - CPoint pnt; - DWORD dwTmp; - ar >> dwTmp; pnt.x = (LONG)dwTmp; - ar >> dwTmp; pnt.y = (LONG)dwTmp; - ScrollToPosition(pnt); + wxPoint pnt; + uint32_t dwTmp; + ar >> dwTmp; pnt.x = value_preserving_cast(dwTmp); + ar >> dwTmp; pnt.y = value_preserving_cast(dwTmp); + Scroll(pnt); } - return (LRESULT)1; } ///////////////////////////////////////////////////////////////////////////// // CTinyBoardView drawing -void CTinyBoardView::OnDraw(CDC* pDC) +void CTinyBoardView::OnDraw(wxDC& pDC) { - if (!m_pBMap) + if (!m_pBMap.IsOk()) RegenCachedMap(pDC); - ASSERT(m_pBMap); + wxASSERT(m_pBMap.IsOk()); - CDC dcMem; - CRect oRct; - CRect oRctSave; - CBitmap* pPrvBMap; + wxMemoryDC dcMem; + wxRect oRct; + wxRect oRctSave; - pDC->GetClipBox(&oRct); - if (oRct.IsRectEmpty()) + pDC.GetClippingBox(oRct); + if (oRct.IsEmpty()) return; // Nothing to do - OwnerPtr bmMem = CreateRGBDIBSection(oRct.Width(), oRct.Height()); - dcMem.CreateCompatibleDC(pDC); - pPrvBMap = dcMem.SelectObject(&*bmMem); - dcMem.PatBlt(0, 0, oRct.Width(), oRct.Height(), WHITENESS); + wxBitmap bmMem(oRct.GetWidth(), oRct.GetHeight(), pDC); + dcMem.SelectObject(bmMem); + { + wxDCBrushChanger setBrush(dcMem, *wxWHITE_BRUSH); + wxDCPenChanger setPen(dcMem, *wxTRANSPARENT_PEN); + dcMem.DrawRectangle(0, 0, oRct.GetWidth(), oRct.GetHeight()); + } if (m_pPBoard->IsBoardRotated180()) { oRctSave = oRct; - CSize sizeBrd = m_pPBoard->GetBoard()->GetSize(smallScale); - oRct = CRect(CPoint(sizeBrd.cx - oRct.left - oRct.Width(), - sizeBrd.cy - oRct.top - oRct.Height()), oRct.Size()); + wxSize sizeBrd = CB::Convert(m_pPBoard->GetBoard()->GetSize(smallScale)); + oRct = wxRect(wxPoint(sizeBrd.x - oRct.GetLeft() - oRct.GetWidth(), + sizeBrd.y - oRct.GetTop() - oRct.GetHeight()), oRct.GetSize()); } - dcMem.SetViewportOrg(-oRct.left, -oRct.top); + dcMem.SetDeviceOrigin(-oRct.GetLeft(), -oRct.GetTop()); // Draw updated part of board image - BitmapBlt(dcMem, CPoint(0, 0), *m_pBMap); + dcMem.DrawBitmap(m_pBMap, 0, 0); // Draw pieces etc. (Need to rescale the DC and the update rect) - CRect rct(&oRct); - SetupDrawListDC(&dcMem, rct); + wxRect rct(oRct); + { + DCSetupDrawListDC setupDrawListDC(*this, dcMem, rct); - m_pPBoard->Draw(dcMem, &rct, smallScale); + m_pPBoard->Draw(dcMem, rct, smallScale); - RestoreDrawListDC(&dcMem); + } if (m_pPBoard->IsBoardRotated180()) { // Xfer to output - dcMem.SetViewportOrg(0, 0); - pDC->StretchBlt(oRctSave.left, oRctSave.top, oRctSave.Width(), oRctSave.Height(), - &dcMem, oRctSave.Width() - 1, oRctSave.Height() - 1, - -oRctSave.Width(), -oRctSave.Height(), SRCCOPY); + dcMem.SetDeviceOrigin(0, 0); + pDC.StretchBlit(oRctSave.GetLeft(), oRctSave.GetTop(), oRctSave.GetWidth(), oRctSave.GetHeight(), + &dcMem, oRctSave.GetWidth() - 1, oRctSave.GetHeight() - 1, + -oRctSave.GetWidth(), -oRctSave.GetHeight()); } else { // Copy to output area - pDC->BitBlt(oRct.left, oRct.top, oRct.Width(), oRct.Height(), - &dcMem, oRct.left, oRct.top, SRCCOPY); + pDC.Blit(oRct.GetLeft(), oRct.GetTop(), oRct.GetWidth(), oRct.GetHeight(), + &dcMem, oRct.GetLeft(), oRct.GetTop(), wxCOPY); } - - dcMem.SelectObject(pPrvBMap); } -void CTinyBoardView::DrawFullMap(CDC* pDC, CBitmap& bmap) +wxBitmap CTinyBoardView::DrawFullMap() { - CDC dcMem; + wxBitmap bmap; + wxMemoryDC dcMem; - CSize size = m_pPBoard->GetBoard()->GetSize(smallScale); + wxSize size = CB::Convert(m_pPBoard->GetBoard()->GetSize(smallScale)); - bmap.Attach(CreateRGBDIBSection(size.cx, size.cy)->Detach()); - dcMem.CreateCompatibleDC(pDC); - CBitmap* pPrvBMap = dcMem.SelectObject(&bmap); + bmap = wxBitmap(size.x, size.y); + dcMem.SelectObject(bmap); // Draw updated part of board image - BitmapBlt(dcMem, CPoint(0, 0), *m_pBMap); + dcMem.DrawBitmap(m_pBMap, 0, 0); // Draw pieces etc. (Need to rescale the DC and the update rect) - CRect rct(CPoint(0,0), size); - SetupDrawListDC(&dcMem, rct); + wxRect rct(wxPoint(0,0), size); + { + DCSetupDrawListDC setupDrawList(*this, dcMem, rct); + + m_pPBoard->Draw(dcMem, rct, smallScale); - m_pPBoard->Draw(dcMem, &rct, smallScale); + } - RestoreDrawListDC(&dcMem); - dcMem.SelectObject(pPrvBMap); + return bmap; } -void CTinyBoardView::RegenCachedMap(CDC* pDC) +void CTinyBoardView::RegenCachedMap(wxDC& pDC) { - BeginWaitCursor(); + wxBusyCursor waitCursor; CBoard* pBoard = m_pPBoard->GetBoard(); - CSize size = pBoard->GetSize(smallScale); // Get pixel size of board - m_pBMap = CreateRGBDIBSection(size.cx, size.cy); + wxSize size = CB::Convert(pBoard->GetSize(smallScale)); // Get pixel size of board + m_pBMap = wxBitmap(size.x, size.y, pDC); - CDC dcMem; - dcMem.CreateCompatibleDC(pDC); - CBitmap* pPrvBMap = dcMem.SelectObject(&*m_pBMap); + wxMemoryDC dcMem; + dcMem.SelectObject(m_pBMap); - CRect rct(CPoint(0, 0), size); + wxRect rct(wxPoint(0, 0), size); pBoard->SetMaxDrawLayer(); // Make sure all layers are drawn pBoard->Draw(dcMem, rct, smallScale, m_pPBoard->m_bSmallCellBorders); - - dcMem.SelectObject(pPrvBMap); - EndWaitCursor(); } ///////////////////////////////////////////////////////////////////////////// -void CTinyBoardView::SetupDrawListDC(CDC* pDC, CRect& rct) +CTinyBoardView::DCSetupDrawListDC::DCSetupDrawListDC(const CTinyBoardView& rThis, wxDC& pDC, wxRect& rct) { - CSize wsize, vsize; - m_pPBoard->GetBoard()->GetBoardArray(). + wxSize wsize, vsize; + rThis.m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(smallScale, wsize, vsize); - pDC->SaveDC(); - pDC->SetMapMode(MM_ANISOTROPIC); - pDC->SetWindowExt(wsize); - pDC->SetViewportExt(vsize); + scaleChanger = CB::DCUserScaleChanger(pDC, double(vsize.x)/wsize.x, double(vsize.y)/wsize.y); ScaleRect(rct, wsize, vsize); } -void CTinyBoardView::RestoreDrawListDC(CDC *pDC) -{ - pDC->RestoreDC(-1); -} - ///////////////////////////////////////////////////////////////////////////// -void CTinyBoardView::WorkspaceToClient(CRect& rect) +void CTinyBoardView::WorkspaceToClient(wxRect& rect) const { - CPoint dpnt = GetDeviceScrollPosition(); - CSize wsize, vsize; + wxSize wsize, vsize; m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(smallScale, wsize, vsize); if (m_pPBoard->IsBoardRotated180()) { - rect = CRect(wsize.cx - rect.left, wsize.cy - rect.top, - wsize.cx - rect.right, wsize.cy - rect.bottom); - rect.NormalizeRect(); + rect = wxRect(wxPoint(wsize.x - rect.GetLeft(), wsize.y - rect.GetTop()), + wxPoint(wsize.x - rect.GetRight(), wsize.y - rect.GetBottom())); + CB::Normalize(rect); } ScaleRect(rect, vsize, wsize); - rect -= dpnt; + rect.SetLeftTop(CalcScrolledPosition(rect.GetTopLeft())); } -void CTinyBoardView::InvalidateWorkspaceRect(const CRect* pRect, BOOL bErase) +void CTinyBoardView::InvalidateWorkspaceRect(const wxRect& pRect, BOOL bErase) { - CRect rct(pRect); + wxRect rct(pRect); WorkspaceToClient(rct); - InvalidateRect(&rct, bErase); + RefreshRect(rct, bErase); } -void CTinyBoardView::ClientToWorkspace(CPoint& pnt) +void CTinyBoardView::ClientToWorkspace(wxPoint& pnt) const { - pnt += GetDeviceScrollPosition(); - CSize wsize, vsize; + pnt = CalcUnscrolledPosition(pnt); + wxSize wsize, vsize; m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(smallScale, wsize, vsize); ScalePoint(pnt, wsize, vsize); if (m_pPBoard->IsBoardRotated180()) - pnt = CPoint(wsize.cx - pnt.x, wsize.cy - pnt.y); + pnt = wxPoint(wsize.x - pnt.x, wsize.y - pnt.y); } -///////////////////////////////////////////////////////////////////////////// - -#ifdef _DEBUG -CGamDoc* CTinyBoardView::GetDocument() // non-debug version is inline -{ - CGamDoc* retval = CB::ToCGamDoc(m_pDocument); - wxASSERT(retval); - return retval; -} -#endif //_DEBUG - ///////////////////////////////////////////////////////////////////////////// // CTinyBoardView message handlers -void CTinyBoardView::OnLButtonDown(UINT nFlags, CPoint point) +void CTinyBoardView::OnLButtonDown(wxMouseEvent& event) { + wxPoint point = event.GetPosition(); ClientToWorkspace(point); - CFrameWnd* pFrame = GetParentFrame(); - pFrame->SendMessage(WM_CENTERBOARDONPOINT, (WPARAM)&point); + // TODO: convert to wx when frame handles wxEvent + CFrameWnd* pFrame = parent->GetParentFrame(); + CPoint cpoint = CB::Convert(point); + pFrame->SendMessage(WM_CENTERBOARDONPOINT, reinterpret_cast(&cpoint)); } -void CTinyBoardView::OnRButtonDown(UINT nFlags, CPoint point) +void CTinyBoardView::OnRButtonDown(wxMouseEvent& event) { - if (!m_pBMap) + if (!m_pBMap.IsOk()) return; - CTinyBoardPopup* pTBrd = new CTinyBoardPopup; + // owned by MFC + RefPtr pTBrd(new CTinyBoardPopup(CheckedDeref(parent->GetParentFrame()))); - { - CWindowDC dcRef(NULL); - DrawFullMap(&dcRef, pTBrd->m_bmap); - } + pTBrd->m_bmap = DrawFullMap(); - pTBrd->m_pWnd = GetParentFrame(); m_pPBoard->GetBoard()->GetBoardArray(). GetBoardScaling(smallScale, pTBrd->m_wsize, pTBrd->m_vsize); pTBrd->m_bRotate180 = m_pPBoard->IsBoardRotated180(); - CRect rct; - GetWindowRect(&rct); - pTBrd->Create(GetMainFrame(), rct.CenterPoint()); + wxRect rct = GetScreenRect(); + pTBrd->Create(CheckedDeref(GetMainFrame()), GetMidRect(rct)); - CScrollView::OnRButtonDown(nFlags, point); + event.Skip(); } +#if 0 int CTinyBoardView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) { // We don't want the frame to ever consider this view to be the // "active" view. return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message); } +#endif + +void CTinyBoardView::RecalcScrollLimits() +{ + wxSizer& sizer = CheckedDeref(GetSizer()); + wxSizerItemList& items = sizer.GetChildren(); + wxASSERT(items.size() == 1); + wxSizerItem& item = CheckedDeref(items[0]); + wxASSERT(item.IsSpacer()); + + CBoard* pBoard = m_pPBoard->GetBoard(); + wxSize size = CB::Convert(pBoard->GetSize(smallScale)); + item.AssignSpacer(size); + SetScrollRate(size.x/100, size.y/100); + sizer.FitInside(this); +} + +void CTinyBoardViewContainer::OnDraw(CDC* pDC) +{ + // do nothing because child covers entire client rect +} + +void CTinyBoardViewContainer::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) +{ + child->OnUpdate(pSender, lHint, pHint); + + BASE::OnUpdate(pSender, lHint, pHint); +} + +CTinyBoardViewContainer::CTinyBoardViewContainer() : + CB::wxNativeContainerWindowMixin(static_cast(*this)) +{ +} + +int CTinyBoardViewContainer::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + if (BASE::OnCreate(lpCreateStruct) == -1) + { + return -1; + } + + child = new CTinyBoardView(*this); + + return 0; +} + +#if 0 +void CTinyBoardViewContainer::OnSize(UINT nType, int cx, int cy) +{ + child->MoveWindow(0, 0, cx, cy); + return CView::OnSize(nType, cx, cy); +} +#endif + +int CTinyBoardViewContainer::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) +{ + // We don't want the frame to ever consider this view to be the + // "active" view. + return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message); +} + +LRESULT CTinyBoardViewContainer::OnMessageWindowState(WPARAM wParam, LPARAM lParam) +{ + WinStateEvent event(*reinterpret_cast(wParam), bool(lParam)); + child->ProcessWindowEvent(event); + return (LRESULT)1; +} diff --git a/GP/VwTbrd.h b/GP/VwTbrd.h index 22ac9a8e..dc84f1b3 100644 --- a/GP/VwTbrd.h +++ b/GP/VwTbrd.h @@ -1,6 +1,6 @@ // VwTbrd.h : header file // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,59 +25,107 @@ ///////////////////////////////////////////////////////////////////////////// // CTinyBoardView view -class CTinyBoardView : public CScrollView +class CTinyBoardView : public CB::ProcessEventOverride { - DECLARE_DYNCREATE(CTinyBoardView) -protected: - CTinyBoardView(); // protected constructor used by dynamic creation +private: + friend class CTinyBoardViewContainer; + typedef CB::ProcessEventOverride BASE; + CTinyBoardView(CTinyBoardViewContainer& parent); // Attributes -public: - CGamDoc* GetDocument(); // Operations public: // Implementation +private: + // member declaration order determines construction order + RefPtr parent; + RefPtr document; protected: - CPlayBoard* m_pPBoard; // The playing board we are viewing - OwnerOrNullPtr m_pBMap; // Cached predrawn board bitmap + RefPtr m_pPBoard; // The playing board we are viewing + wxBitmap m_pBMap; // Cached predrawn board bitmap TileScale m_nZoom; - void RegenCachedMap(CDC* pDC); - void DrawFullMap(CDC* pDC, CBitmap& bmap); + void RegenCachedMap(wxDC& pDC); + wxBitmap DrawFullMap(); // Implementation protected: - void SetupDrawListDC(CDC* pDC, CRect& rct); - void RestoreDrawListDC(CDC *pDC); + class DCSetupDrawListDC + { + public: + DCSetupDrawListDC(const CTinyBoardView& rThis, wxDC& pDC, wxRect& rct); + private: + CB::DCUserScaleChanger scaleChanger; + }; // -------- // - void WorkspaceToClient(CRect& rect); - void ClientToWorkspace(CPoint& pnt); - void InvalidateWorkspaceRect(const CRect* pRect, BOOL bErase = FALSE); + void WorkspaceToClient(wxRect& rect) const; + void ClientToWorkspace(wxPoint& pnt) const; + void InvalidateWorkspaceRect(const wxRect& pRect, BOOL bErase = FALSE); // Implementation protected: - virtual ~CTinyBoardView() = default; - virtual BOOL PreCreateWindow(CREATESTRUCT& cs); - virtual void OnInitialUpdate(); // first time after construct - virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); - virtual void OnDraw(CDC* pDC); // overridden to draw this view - - // Generated message map functions - //{{AFX_MSG(CTinyBoardView) - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + ~CTinyBoardView() override = default; +#if 0 + BOOL PreCreateWindow(CREATESTRUCT& cs) override; +#endif + void OnInitialUpdate(); // first time after construct + void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint); + void OnDraw(wxDC& pDC) override; // overridden to draw this view + + void OnLButtonDown(wxMouseEvent& event); + void OnRButtonDown(wxMouseEvent& event); +#if 0 + afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message); +#endif + void OnMessageWindowState(WinStateEvent& event); + wxDECLARE_EVENT_TABLE(); + +private: + // IGetCmdTarget + CCmdTarget& Get() override; + + void RecalcScrollLimits(); +}; + +class CTinyBoardViewContainer : public CB::OnCmdMsgOverride, + public CB::wxNativeContainerWindowMixin +{ +public: + void OnDraw(CDC* pDC) override; + + void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) override; + +private: + CTinyBoardViewContainer(); // used by dynamic creation + DECLARE_DYNCREATE(CTinyBoardViewContainer) + + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); +#if 0 + afx_msg void OnSize(UINT nType, int cx, int cy); +#endif afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message); - //}}AFX_MSG afx_msg LRESULT OnMessageWindowState(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() + + // IGetEvtHandler + wxEvtHandler& Get() override + { + return CheckedDeref(CheckedDeref(child).GetEventHandler()); + } + + // owned by wx + CB::propagate_const child = nullptr; + + typedef CB::OnCmdMsgOverride BASE; + friend CTinyBoardView; }; -#ifndef _DEBUG // debug version in vwmbrd.cpp -inline CGamDoc* CTinyBoardView::GetDocument() - { return CB::ToCGamDoc(m_pDocument); } -#endif +inline CCmdTarget& CTinyBoardView::Get() +{ + return *parent; +} diff --git a/GP/WStateGp.cpp b/GP/WStateGp.cpp index ea376447..56fae8a0 100644 --- a/GP/WStateGp.cpp +++ b/GP/WStateGp.cpp @@ -29,6 +29,7 @@ #include "FrmProj.h" #include "Board.h" #include "PBoard.h" +#include "VwPbrd.h" #include "WStateGp.h" enum { gpFrmProject = 0, gpFrmPlayBoard = 1 }; @@ -48,7 +49,7 @@ CWnd* CGpWinStateMgr::OnGetFrameForWinStateElement(const CWinStateElement& pWse) { // The second user code is the board's serial number. CPlayBoard& pPBoard = CheckedDeref(pDoc->GetPBoardManager().GetPBoardBySerial(pWse.m_boardID)); - CView* pView = pDoc->FindPBoardView(pPBoard); + CPlayBoardView* pView = pDoc->FindPBoardView(pPBoard); if (pView == NULL) { // No frame open for board. Create it. diff --git a/GP/WinPoptb.cpp b/GP/WinPoptb.cpp index 8036c0d3..7c140635 100644 --- a/GP/WinPoptb.cpp +++ b/GP/WinPoptb.cpp @@ -1,6 +1,6 @@ // WinPoptb.cpp : implementation file // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -28,6 +28,7 @@ #include "Gmisc.h" #include "GdiTools.h" #include "WinPoptb.h" +#include "CDib.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -35,22 +36,24 @@ static char THIS_FILE[] = __FILE__; #endif -BEGIN_MESSAGE_MAP(CTinyBoardPopup, CWnd) - //{{AFX_MSG_MAP(CTinyBoardPopup) - ON_WM_RBUTTONDOWN() - ON_WM_LBUTTONDOWN() +wxBEGIN_EVENT_TABLE(CTinyBoardPopup, wxPopupTransientWindow) + EVT_RIGHT_DOWN(OnRButtonDown) +#if 1 + EVT_LEFT_DOWN(OnLButtonDown) +#endif +#if 0 ON_WM_CREATE() - ON_WM_PAINT() - ON_WM_CHAR() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() +#endif + EVT_PAINT(OnPaint) + EVT_CHAR(OnChar) +wxEND_EVENT_TABLE() ///////////////////////////////////////////////////////////////////////////// // CTinyBoardPopup -CTinyBoardPopup::CTinyBoardPopup() +CTinyBoardPopup::CTinyBoardPopup(CWnd& pWnd) : + m_pWnd(&pWnd) { - m_pWnd = NULL; m_bRotate180 = FALSE; } @@ -60,39 +63,23 @@ CTinyBoardPopup::~CTinyBoardPopup() ///////////////////////////////////////////////////////////////////////////// -BOOL CTinyBoardPopup::Create(CWnd* pParent, CPoint ptCenter) +BOOL CTinyBoardPopup::Create(wxWindow& pParent, wxPoint ptCenter) { - CRect rct(CPoint(0,0), m_vsize); - DWORD dwStyle = WS_BORDER | WS_POPUP | WS_VISIBLE; - DWORD dwExStyle = WS_EX_CLIENTEDGE; - - AdjustWindowRectEx(&rct, dwStyle, FALSE, dwExStyle); - rct.OffsetRect(ptCenter.x - rct.Width()/2, ptCenter.y - rct.Height()/2); - - // Make sure on screen... - CRect rctWrk; - SystemParametersInfo(SPI_GETWORKAREA, 0, &rctWrk, 0); - if (rct.right > rctWrk.right) - rct.OffsetRect(rctWrk.right - rct.right, 0); - if (rct.bottom > rctWrk.bottom) - rct.OffsetRect(0, rctWrk.bottom - rct.bottom); - - if (rct.Width() > rctWrk.Width()) + // wxPU_CONTAINS_CONTROLS required to enable having focus + BOOL retval = wxPopupTransientWindow::Create(&pParent, + wxPU_CONTAINS_CONTROLS | wxBORDER_SUNKEN); + if (retval) { - rct.left = rctWrk.left; - rct.right = rctWrk.right; + SetClientSize(m_vsize); + wxRect rct(wxPoint(0, 0), GetSize()); + rct.Offset(ptCenter.x - rct.GetWidth()/2, ptCenter.y - rct.GetHeight()/2); + Position(rct.GetLeftTop(), wxDefaultSize); + Popup(); } - if (rct.Height() > rctWrk.Height()) - { - rct.top = rctWrk.top; - rct.bottom = rctWrk.bottom; - } - - return CWnd::CreateEx(dwExStyle, - AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW), - (HBRUSH)(COLOR_BTNFACE + 1)), ""_cbstring, dwStyle, rct, pParent, NULL, NULL); + return retval; } +#if 0 int CTinyBoardPopup::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) @@ -107,73 +94,136 @@ int CTinyBoardPopup::OnCreate(LPCREATESTRUCT lpCreateStruct) return 0; } +#endif ///////////////////////////////////////////////////////////////////////////// // CTinyBoardPopup message handlers -void CTinyBoardPopup::PostNcDestroy() +void CTinyBoardPopup::OnPaint(wxPaintEvent& event) { - delete this; -} + wxPaintDC dc(this); // device context for painting -void CTinyBoardPopup::OnPaint() -{ - CPaintDC dc(this); // device context for painting + wxMemoryDC dcMem; + wxRect oRct; - CDC dcMem; - CRect oRct; + dcMem.SelectObject(m_bmap); - dcMem.CreateCompatibleDC(&dc); - CBitmap* pPrvBMap = dcMem.SelectObject(&m_bmap); - - CRect rctClient; - GetClientRect(rctClient); + wxRect rctClient = GetClientRect(); if (m_bRotate180) { - dc.StretchBlt(0, 0, rctClient.right, rctClient.bottom, &dcMem, - m_vsize.cx - 1,m_vsize.cy - 1, -m_vsize.cx, -m_vsize.cy, SRCCOPY); + dc.StretchBlit(0, 0, rctClient.GetRight(), rctClient.GetBottom(), &dcMem, + m_vsize.x - 1,m_vsize.y - 1, -m_vsize.x, -m_vsize.y); } else { - dc.StretchBlt(0, 0, rctClient.right, rctClient.bottom, &dcMem, 0, 0, - m_vsize.cx, m_vsize.cy, SRCCOPY); + dc.StretchBlit(0, 0, rctClient.GetRight(), rctClient.GetBottom(), &dcMem, 0, 0, + m_vsize.x, m_vsize.y); } - - dcMem.SelectObject(pPrvBMap); } -void CTinyBoardPopup::ProcessBoardHit(UINT nFlags, CPoint point) +void CTinyBoardPopup::ProcessBoardHit(wxMouseEvent& event) { - ReleaseCapture(); + wxPoint point = event.GetPosition(); - CRect rctClient; - GetClientRect(&rctClient); - if (rctClient.PtInRect(point)) + wxRect rctClient = GetClientRect(); + if (rctClient.Contains(point)) { - ScalePoint(point, m_wsize, rctClient.Size()); + ScalePoint(point, m_wsize, rctClient.GetSize()); if (m_bRotate180) - point = CPoint(m_wsize.cx - point.x, m_wsize.cy - point.y); - m_pWnd->SendMessage(WM_CENTERBOARDONPOINT, (WPARAM)&point); + point = wxPoint(m_wsize.x - point.x, m_wsize.y - point.y); + CPoint cpoint = CB::Convert(point); + m_pWnd->SendMessage(WM_CENTERBOARDONPOINT, (WPARAM)&cpoint); } - DestroyWindow(); + Dismiss(); } -void CTinyBoardPopup::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) +void CTinyBoardPopup::OnChar(wxKeyEvent& event) { - if (nChar == VK_ESCAPE) + if (event.GetUnicodeKey() == WXK_ESCAPE) { - ReleaseCapture(); - DestroyWindow(); + Dismiss(); } } -void CTinyBoardPopup::OnRButtonDown(UINT nFlags, CPoint point) +void CTinyBoardPopup::OnRButtonDown(wxMouseEvent& event) { - ProcessBoardHit(nFlags, point); + ProcessBoardHit(event); } -void CTinyBoardPopup::OnLButtonDown(UINT nFlags, CPoint point) +#if 1 +void CTinyBoardPopup::OnLButtonDown(wxMouseEvent& event) +#else +bool CTinyBoardPopup::ProcessLeftDown(wxMouseEvent& event) +#endif +{ + ProcessBoardHit(event); +#if 1 +#else + return false; +#endif +} + +/* default position policy wants no overlap between arg rect + and this, but we want as close to leftTop as screen + permits */ +void CTinyBoardPopup::Position(const wxPoint& ptOrigin, + const wxSize& sizePopup) { - ProcessBoardHit(nFlags, point); + // based on wxPopupWindowBase::Position() + // determine the position and size of the screen we clamp the popup to + wxPoint posScreen; + wxSize sizeScreen; + + const int displayNum = wxDisplay::GetFromPoint(ptOrigin); + if ( displayNum != wxNOT_FOUND ) + { + const wxRect rectScreen = wxDisplay(displayNum).GetGeometry(); + posScreen = rectScreen.GetPosition(); + sizeScreen = rectScreen.GetSize(); + } + else // outside of any display? + { + // just use the primary one then + posScreen = wxPoint(0, 0); + sizeScreen = wxGetDisplaySize(); + } + + + const wxSize sizeSelf = GetSize(); + + wxCoord y = ptOrigin.y; + if ( y + sizeSelf.y > posScreen.y + sizeScreen.y ) + { + y = posScreen.y + sizeScreen.y - sizeSelf.y; + } + + // now check left/right too + wxCoord x = ptOrigin.x; + + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + { + wxASSERT(!"untested code"); + // shift the window to the left instead of the right. + x -= sizeSelf.x; // also shift it by window width. + } + + + if ( x + sizeSelf.x > posScreen.x + sizeScreen.x ) + { + x = posScreen.x + sizeScreen.x - sizeSelf.x; + } + + Move(x, y, wxSIZE_NO_ADJUSTMENTS); +} + +void CTinyBoardPopup::Dismiss() +{ + /* KLUDGE: sometimes getting multiple dismisses, but should + not destroy multiple times */ + if (IsShown()) + { + wxPopupTransientWindow::Dismiss(); + Destroy(); + } } diff --git a/GP/WinPoptb.h b/GP/WinPoptb.h index ae6d4fe2..b66541dd 100644 --- a/GP/WinPoptb.h +++ b/GP/WinPoptb.h @@ -1,6 +1,6 @@ // WinPoptb.h : header file // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -32,48 +32,58 @@ ///////////////////////////////////////////////////////////////////////////// // CTinyBoardPopup window -class CTinyBoardPopup : public CWnd +class CTinyBoardPopup : public wxPopupTransientWindow { // Construction public: - CTinyBoardPopup(); + CTinyBoardPopup(CWnd& pWnd); // Attributes +private: + RefPtr m_pWnd; public: - CWnd* m_pWnd; - CBitmap m_bmap; - CSize m_wsize; - CSize m_vsize; + wxBitmap m_bmap; + wxSize m_wsize; + wxSize m_vsize; BOOL m_bRotate180; // Board is rotated by 180 degrees // Operations public: - BOOL Create(CWnd* pParent, CPoint ptCenter); + BOOL Create(wxWindow& pParent, wxPoint ptCenter); // Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CTinyBoardPopup) public: protected: - virtual void PostNcDestroy(); - //}}AFX_VIRTUAL // Implementation public: - virtual ~CTinyBoardPopup(); + ~CTinyBoardPopup() override; - void ProcessBoardHit(UINT nFlags, CPoint point); +private: + void ProcessBoardHit(wxMouseEvent& event); - // Generated message map functions -protected: - //{{AFX_MSG(CTinyBoardPopup) - afx_msg void OnRButtonDown(UINT nFlags, CPoint point); - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + void OnRButtonDown(wxMouseEvent& event); + /* N.B.: OnLButtonDown() instead of ProcessLeftDown() + see https://groups.google.com/g/wx-dev/c/506M_PpcsZk/m/FODigxNUAQAJ + */ +#if 1 + void OnLButtonDown(wxMouseEvent& event); +#else + bool ProcessLeftDown(wxMouseEvent& event) override; +#endif +#if 0 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg void OnPaint(); - afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() +#endif + void OnPaint(wxPaintEvent& event); + void OnChar(wxKeyEvent& event); + wxDECLARE_EVENT_TABLE(); + + /* default position policy wants no overlap between arg rect + and this, but we want as close to leftTop as screen + permits */ + void Position(const wxPoint& leftTop, + const wxSize&) override; + void Dismiss() override; }; ///////////////////////////////////////////////////////////////////////////// diff --git a/GShr/CalcLib.cpp b/GShr/CalcLib.cpp index af71a937..91c96143 100644 --- a/GShr/CalcLib.cpp +++ b/GShr/CalcLib.cpp @@ -250,14 +250,14 @@ CPoint GetMidRect(const CRect& rct) /////////////////////////////////////////////////////////////////////// // Rotate point around specified origin point. -CPoint RotatePointAroundPoint(CPoint pntOrigin, CPoint pntXlate, int nAngleDeg) +wxPoint RotatePointAroundPoint(wxPoint pntOrigin, wxPoint pntXlate, int nAngleDeg) { - CPoint pntRelative = pntXlate - pntOrigin; + wxPoint pntRelative = pntXlate - pntOrigin; int nCosA = Cos10K(nAngleDeg); int nSinA = Sin10K(nAngleDeg); int xRotated = (pntRelative.x * nCosA - pntRelative.y * nSinA) / 10000; int yRotated = (pntRelative.x * nSinA + pntRelative.y * nCosA) / 10000; - CPoint pntFinal = CPoint(xRotated, yRotated) + pntOrigin; + wxPoint pntFinal = wxPoint(xRotated, yRotated) + pntOrigin; return pntFinal; } diff --git a/GShr/CyberBoard.h b/GShr/CyberBoard.h index 83bcf539..1e761ff2 100644 --- a/GShr/CyberBoard.h +++ b/GShr/CyberBoard.h @@ -1,6 +1,6 @@ // CyberBoard.h // -// Copyright (c) 2020-2025 By William Su, All Rights Reserved. +// Copyright (c) 2020-2026 By William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -2242,7 +2242,7 @@ namespace CB { public: // flags may be or'ed together - enum Flags { NONE = 0, CENTER = 1, TRACK = 2 }; + enum Flags { NONE = 0, CENTER = 1, TRACK = 2, /*TRACK_ON = 4*/ }; ToolTip() = default; ~ToolTip(); @@ -2262,6 +2262,15 @@ namespace CB void SetReshow(long milliseconds); // set maximum width for the new tooltips: -1 disables wrapping void SetMaxWidth(int width); + /* WARNING: balloon mode is ignored: + wxTipWindow doesn't have a balloon shape, + but wxRichToolTip doesn't support setting + tip position, and demands title. If we + really want the balloon shape, we will have + to implement the paint ourselves. */ + void SetBalloonMode(bool b) { balloon = b; } + void TrackActivate(wxWindow& wnd, bool b); + void TrackPosition(wxPoint screenPt); void Add(wxWindow& wnd, const wxRect& rect, wxString tip, Flags flags = NONE) @@ -2283,6 +2292,7 @@ namespace CB } private: + enum /*Flags*/ { TRACK_ON = 4 }; void Add(wxWindow& wnd, std::optional&& rect, wxString&& tip, Flags flags); void Delete(wxWindow& wnd, std::optional rect); @@ -2295,6 +2305,7 @@ namespace CB int autopopMs = -1; int maxWidth = -1; bool enabled = false; + bool balloon = false; struct ToolInfo { @@ -2310,8 +2321,7 @@ namespace CB // tool shown by tipWindow decltype(toolInfos)::iterator tipTool = toolInfos.end(); - // owned by wx - wxTipWindow* tipWindow = nullptr; + wxTipWindow::Ref tipWindow; enum State { sNoTool, @@ -2319,7 +2329,6 @@ namespace CB sDisplay, }; State state = sNoTool; - }; /* emulate CRect::Inflate() and CRect::Normalize() sequence @@ -2504,6 +2513,51 @@ namespace CB wxDC* dc = nullptr; wxRasterOperationMode oldRop; }; + + class DCLogicalOriginChanger + { + public: + DCLogicalOriginChanger() = default; + DCLogicalOriginChanger(wxDC& d, wxPoint org) : + dc(&d) + { + oldOrigin = dc->GetLogicalOrigin(); + dc->SetLogicalOrigin(org.x, org.y); + } + DCLogicalOriginChanger(const DCLogicalOriginChanger&) = delete; + DCLogicalOriginChanger(DCLogicalOriginChanger&& other) noexcept + { + *this = std::move(other); + } + DCLogicalOriginChanger& operator=(const DCLogicalOriginChanger&) = delete; + DCLogicalOriginChanger& operator=(DCLogicalOriginChanger&& other) noexcept + { + if (this != &other) + { + Reset(); + dc = other.dc; + other.dc = nullptr; + oldOrigin = other.oldOrigin; + } + return *this; + } + ~DCLogicalOriginChanger() + { + Reset(); + } + + private: + void Reset() + { + if (dc) + { + dc->SetLogicalOrigin(oldOrigin.x, oldOrigin.y); + } + } + + wxDC* dc = nullptr; + wxPoint oldOrigin; + }; } // provide wxMouseState equivalent of wxKeyboardState::GetModifiers() @@ -2595,4 +2649,18 @@ namespace CB dc.DrawEllipse(temp); } } + +template +std::vector> ToRefPtr(const std::vector>& v) +{ + static_assert(!std::is_const_v); + std::vector> retval; + retval.reserve(v.size()); + for (size_t i = size_t(0) ; i < v.size() ; ++i) + { + // v[i] is not_null, so this is safe + retval.emplace_back(&*v[i]); + } + return retval; +} #endif diff --git a/GShr/DragDrop.cpp b/GShr/DragDrop.cpp index b1be7f60..444cd1a7 100644 --- a/GShr/DragDrop.cpp +++ b/GShr/DragDrop.cpp @@ -100,6 +100,7 @@ void DragInfoWx::SetDragType(DragType dt) case DRAG_PIECE: subInfos.m_piece.~SubInfo(); break; +#endif case DRAG_PIECELIST: subInfos.m_pieceList.~SubInfo(); break; @@ -109,6 +110,7 @@ void DragInfoWx::SetDragType(DragType dt) case DRAG_SELECTLIST: subInfos.m_selectList.~SubInfo(); break; +#if 0 case DRAG_SELECTVIEW: subInfos.m_selectView.~SubInfo(); break; @@ -134,6 +136,7 @@ void DragInfoWx::SetDragType(DragType dt) case DRAG_PIECE: new (&subInfos.m_piece) SubInfo; break; +#endif case DRAG_PIECELIST: new (&subInfos.m_pieceList) SubInfo; break; @@ -143,6 +146,7 @@ void DragInfoWx::SetDragType(DragType dt) case DRAG_SELECTLIST: new (&subInfos.m_selectList) SubInfo; break; +#if 0 case DRAG_SELECTVIEW: new (&subInfos.m_selectView) SubInfo; break; diff --git a/GShr/DragDrop.h b/GShr/DragDrop.h index 9277139c..27fc951b 100644 --- a/GShr/DragDrop.h +++ b/GShr/DragDrop.h @@ -1,6 +1,6 @@ // DragDrop.h // -// Copyright (c) 1994-2024 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -70,6 +70,9 @@ class DragDropEvent : public wxEvent wxCursor GetCursor() const { return cursor; } void SetCursor(wxCursor c) { cursor = c; } + const std::optional& GetResult() const { return result; } + void SetResult(bool b) { wxASSERT(!result); result = b; } + wxEvent* Clone() const override { return new DragDropEvent(*this); } private: @@ -77,6 +80,7 @@ class DragDropEvent : public wxEvent const DragInfoWx& dragInfo; bool allowScroll = true; wxCursor cursor; + std::optional result; }; typedef void (wxEvtHandler::*DragDropEventFunction)(DragDropEvent&); #define DragDropEventHandler(func) wxEVENT_HANDLER_CAST(DragDropEventFunction, func) @@ -174,7 +178,7 @@ struct DragInfo struct SubInfo { const std::vector>* m_ptrArray; - CGamDoc* m_gamDoc; + const CGamDoc* m_gamDoc; }; // TODO: when upgrade to c++ 17, use std::variant private: @@ -263,7 +267,6 @@ struct DragInfoWx wxSize m_size; const CGamDoc* m_gamDoc; }; -#if 0 template<> struct SubInfo { @@ -277,6 +280,7 @@ struct DragInfoWx CSelList* m_selectList; CGamDoc* m_gamDoc; }; +#if 0 template<> struct SubInfo { @@ -292,9 +296,9 @@ struct DragInfoWx SubInfo m_tileList; SubInfo m_piece; SubInfo m_pieceList; -#if 0 SubInfo m_marker; SubInfo m_selectList; +#if 0 SubInfo m_selectView; #endif @@ -305,7 +309,7 @@ struct DragInfoWx template const SubInfo
& GetSubInfo() const { - ASSERT(m_dragType == DT); + wxASSERT(m_dragType == DT); /* TODO: This check could be removed to improve release build performance if we trust ourselves to always catch any m_dragType mistakes in testing. Also, diff --git a/GShr/DrawObj.cpp b/GShr/DrawObj.cpp index f6856df2..10705ace 100644 --- a/GShr/DrawObj.cpp +++ b/GShr/DrawObj.cpp @@ -1,6 +1,6 @@ // DrawObj.cpp // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -1645,7 +1645,6 @@ static void DrawObjTile(CDC& pDC, CPoint pnt, CTileManager* pTMgr, TileID tid, static void DrawObjTile(wxDC& pDC, wxPoint pnt, CTileManager& pTMgr, TileID tid, TileScale eScale) { - wxASSERT(!"needs testing"); CTile tile = pTMgr.GetTile(tid, eScale); CB::DCUserScaleChanger setScale; @@ -2142,12 +2141,12 @@ void CDrawList::DrillDownHitTest(CPoint point, std::vector>& pLst) +void CDrawList::ArrangeObjectListInDrawOrder(std::vector>& pLst) { // Loop through the drawing list looking for objects that are // selected. Add them to a local list. When done, purge the caller's // list and transfer temp list to the callers list. - std::vector> tmpLst; + std::vector> tmpLst; for (iterator pos = begin() ; pos != end() ; ++pos) { @@ -2158,12 +2157,12 @@ void CDrawList::ArrangeObjectListInDrawOrder(std::vector pLst = std::move(tmpLst); } -void CDrawList::ArrangeObjectListInVisualOrder(std::vector>& pLst) +void CDrawList::ArrangeObjectListInVisualOrder(std::vector>& pLst) { // Loop backwards through the drawing list looking for objects that are // selected. Add them to a local list. When done, purge the caller's // list and transfer temp list to the callers list. - std::vector> tmpLst; + std::vector> tmpLst; for (reverse_iterator pos = rbegin() ; pos != rend() ; ++pos) { @@ -2230,12 +2229,12 @@ void CDrawList::ArrangePieceTableInVisualOrder(std::vector& pTbl) const pTbl = std::move(tmpTbl); } -void CDrawList::ArrangeObjectPtrTableInDrawOrder(std::vector>& pTbl) const +void CDrawList::ArrangeObjectPtrTableInDrawOrder(std::vector>& pTbl) const { // Loop through the drawing list looking for objects that are // selected. Add them to a local list. When done, purge the caller's // list and transfer temp list to the callers list. - std::vector> tmpTbl; + std::vector> tmpTbl; tmpTbl.reserve(pTbl.size()); for (const_iterator pos = begin(); pos != end(); ++pos) @@ -2245,7 +2244,7 @@ void CDrawList::ArrangeObjectPtrTableInDrawOrder(std::vector>& pTbl) const +void CDrawList::ArrangeObjectPtrTableInDrawOrder(std::vector>& pTbl) const +{ + std::vector> temp = ToRefPtr(pTbl); + ArrangeObjectPtrTableInDrawOrder(temp); + pTbl.clear(); + for (size_t i = size_t(0) ; i < temp.size() ; ++i) + { + pTbl.emplace_back(&*temp[i]); + } +} + +void CDrawList::ArrangeObjectPtrTableInVisualOrder(std::vector>& pTbl) const { // Loop through the drawing list looking for objects that are // selected. Add them to a local list. When done, purge the caller's // list and transfer temp list to the callers list. - std::vector> tmpTbl; + std::vector> tmpTbl; tmpTbl.reserve(pTbl.size()); for (const_reverse_iterator pos = rbegin(); pos != rend(); ++pos) @@ -2270,16 +2280,27 @@ void CDrawList::ArrangeObjectPtrTableInVisualOrder(std::vector>& pTbl) const +{ + std::vector> temp = ToRefPtr(pTbl); + ArrangeObjectPtrTableInVisualOrder(temp); + pTbl.clear(); + for (size_t i = size_t(0) ; i < temp.size() ; ++i) + { + pTbl.emplace_back(&*temp[i]); + } +} + #endif // GPLAY CDrawList::const_iterator CDrawList::Find(const CDrawObj& drawObj) const @@ -2293,11 +2314,11 @@ CDrawList::iterator CDrawList::Find(const CDrawObj& drawObj) } // NOTE: RemoveObject* do not erase -void CDrawList::RemoveObjectsInList(const std::vector>& pLst) +void CDrawList::RemoveObjectsInList(const std::vector>& pLst) { for (size_t i = size_t(0) ; i < pLst.size() ; ++i) { - CDrawObj& pDObj = *pLst[i]; + const CDrawObj& pDObj = *pLst[i]; RemoveObject(pDObj); } } diff --git a/GShr/DrawObj.h b/GShr/DrawObj.h index 10624cd3..8d85d43a 100644 --- a/GShr/DrawObj.h +++ b/GShr/DrawObj.h @@ -1104,7 +1104,7 @@ class CDrawList : private std::list iterator Find(const CDrawObj& drawObj); // NOTE: See WARNING: above void RemoveObject(const CDrawObj& pDrawObj); - void RemoveObjectsInList(const std::vector>& pLst); + void RemoveObjectsInList(const std::vector>& pLst); void AddToBack(CDrawObj::OwnerPtr pDrawObj) { push_front(std::move(pDrawObj)); } void AddToFront(CDrawObj::OwnerPtr pDrawObj) { push_back(std::move(pDrawObj)); } CDrawObj& Front() { return *back(); } @@ -1124,9 +1124,11 @@ class CDrawList : private std::list void ArrangePieceTableInDrawOrder(std::vector& pTbl) const; void ArrangePieceTableInVisualOrder(std::vector& pTbl) const; #endif - void ArrangeObjectListInDrawOrder(std::vector>& pLst); - void ArrangeObjectListInVisualOrder(std::vector>& pLst); + void ArrangeObjectListInDrawOrder(std::vector>& pLst); + void ArrangeObjectListInVisualOrder(std::vector>& pLst); + void ArrangeObjectPtrTableInDrawOrder(std::vector>& pTbl) const; void ArrangeObjectPtrTableInDrawOrder(std::vector>& pTbl) const; + void ArrangeObjectPtrTableInVisualOrder(std::vector>& pTbl) const; void ArrangeObjectPtrTableInVisualOrder(std::vector>& pTbl) const; #ifdef GPLAY void SetOwnerMasks(PlayerMask dwOwnerMask); diff --git a/GShr/GMisc.h b/GShr/GMisc.h index 40e2fdb7..09f03d5a 100644 --- a/GShr/GMisc.h +++ b/GShr/GMisc.h @@ -67,7 +67,7 @@ inline wxPoint GetMidRect(const wxRect& rct) { return CB::Convert(GetMidRect(CB::Convert(rct))); } -CPoint RotatePointAroundPoint(CPoint pntOrigin, CPoint pntXlate, int nAngleDeg); +wxPoint RotatePointAroundPoint(wxPoint pntOrigin, wxPoint pntXlate, int nAngleDeg); int32_t GridizeClosest1000(int32_t nVal, int32_t nMultiple, int32_t nOffset); int32_t GridizeClosest(int32_t nVal, int32_t nMultiple, int32_t nOffset); diff --git a/GShr/LBoxGfx2.cpp b/GShr/LBoxGfx2.cpp index 29ca86df..64daa3da 100644 --- a/GShr/LBoxGfx2.cpp +++ b/GShr/LBoxGfx2.cpp @@ -1,6 +1,6 @@ // LBoxGfx2.cpp // -// Copyright (c) 1994-2023 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -49,23 +49,25 @@ const int timerScrollID = 901; ///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CGrafixListBox2, CListBox) - //{{AFX_MSG_MAP(CGrafixListBox2) - ON_WM_LBUTTONDOWN() - ON_WM_MOUSEMOVE() - ON_WM_LBUTTONUP() +wxBEGIN_EVENT_TABLE(CGrafixListBox2, CB::VListBoxHScroll) + EVT_LEFT_DOWN(OnLButtonDown) + EVT_MOTION(OnMouseMove) + EVT_LEFT_UP(OnLButtonUp) +#if 0 ON_WM_TIMER() - ON_WM_CREATE() - ON_REGISTERED_MESSAGE(WM_DRAGDROP, OnDragItem) - //}}AFX_MSG_MAP -END_MESSAGE_MAP() +#endif + EVT_WINDOW_CREATE(OnCreate) + EVT_DRAGDROP(OnDragItem) +wxEND_EVENT_TABLE() ///////////////////////////////////////////////////////////////////////////// CGrafixListBox2::CGrafixListBox2() { m_nLastInsert = -1; +#if 0 m_nTimerID = uintptr_t(0); +#endif m_bAllowDrag = FALSE; m_bAllowSelfDrop = FALSE; m_bAllowDropScroll = FALSE; @@ -74,7 +76,7 @@ CGrafixListBox2::CGrafixListBox2() ///////////////////////////////////////////////////////////////////////////// -void CGrafixListBox2::SetItemMap(const std::vector>* pMap, +void CGrafixListBox2::SetItemMap(const std::vector>* pMap, BOOL bKeepPosition /* = TRUE */) { m_pItemMap = pMap; @@ -86,52 +88,52 @@ void CGrafixListBox2::UpdateList(BOOL bKeepPosition /* = TRUE */) { if (m_pItemMap == NULL) { - ResetContent(); + Clear(); return; } - int nCurSel = GetCurSel(); - int nTopIdx = GetTopIndex(); - int nFcsIdx = GetCaretIndex(); - int horzScroll = GetScrollPos(SB_HORZ); - SetRedraw(FALSE); - ResetContent(); - - LONG width = 0; - int nItem; - for (nItem = 0; nItem < value_preserving_cast(m_pItemMap->size()); nItem++) - { - AddString(" "_cbstring); // Fill with dummy data - width = CB::max(width, OnItemSize(value_preserving_cast(nItem)).cx); - } - SetHorizontalExtent(value_preserving_cast(width)); + int nCurSel = IsMultiSelect() ? wxNOT_FOUND : GetSelection(); + size_t nTopIdx = GetVisibleRowsBegin(); + int nFcsIdx = GetCurrent(); + int horzScroll = GetScrollPos(wxHORIZONTAL); +{ + wxWindowUpdateLocker freezer(this); + Clear(); + + size_t nItem = CB::max(size_t(1), m_pItemMap->size()); + SetItemCount(m_pItemMap->size()); if (bKeepPosition) { - if (nTopIdx >= 0) - SetTopIndex(std::min(nTopIdx, nItem - 1)); - if (nFcsIdx >= 0) - SetCaretIndex(std::min(nFcsIdx, nItem - 1), FALSE); - if (nCurSel >= 0) - SetCurSel(std::min(nCurSel, nItem - 1)); + ScrollToRow(CB::min(nTopIdx, nItem - size_t(1))); + if (nFcsIdx != wxNOT_FOUND) + { + SetCurrent(CB::min(nFcsIdx, value_preserving_cast(nItem - size_t(1)))); + } + if (nCurSel != wxNOT_FOUND) + { + SetSelection(CB::min(nCurSel, value_preserving_cast(nItem - size_t(1)))); + } } - SetRedraw(TRUE); +} if (bKeepPosition) { - SendMessage(WM_HSCROLL, MAKELONG(int16_t(SB_THUMBPOSITION), value_preserving_cast(horzScroll)), NULL); + SetScrollPos(wxHORIZONTAL, horzScroll); } - Invalidate(); + Refresh(); } ///////////////////////////////////////////////////////////////////////////// const CDrawObj& CGrafixListBox2::MapIndexToItem(size_t nIndex) const { - ASSERT(m_pItemMap); - ASSERT(nIndex < m_pItemMap->size()); + wxASSERT(m_pItemMap); + wxASSERT(nIndex < m_pItemMap->size()); return *m_pItemMap->at(nIndex); } +#if 0 size_t CGrafixListBox2::MapItemToIndex(const CDrawObj& pItem) const { + wxASSERT(!"dead code?"); ASSERT(m_pItemMap); for (size_t i = 0; i < m_pItemMap->size(); i++) { @@ -143,6 +145,7 @@ size_t CGrafixListBox2::MapItemToIndex(const CDrawObj& pItem) const const CDrawObj& CGrafixListBox2::GetCurMapItem() const { + wxASSERT(!"dead code?"); ASSERT(!IsMultiSelect()); ASSERT(m_pItemMap); int nItem = GetCurSel(); @@ -168,6 +171,7 @@ std::vector> CGrafixListBox2::GetCurMappedItemList void CGrafixListBox2::SetCurSelMapped(const CDrawObj& nMapVal) { + wxASSERT(!"dead code?"); ASSERT(m_pItemMap); for (size_t i = 0; i < m_pItemMap->size(); i++) { @@ -181,6 +185,7 @@ void CGrafixListBox2::SetCurSelMapped(const CDrawObj& nMapVal) void CGrafixListBox2::SetCurSelsMapped(const std::vector>& items) { + wxASSERT(!"dead code?"); ASSERT(m_pItemMap); ASSERT(IsMultiSelect()); @@ -199,6 +204,7 @@ void CGrafixListBox2::SetCurSelsMapped(const std::vector void CGrafixListBox2::ShowFirstSelection() { + wxASSERT(!"dead code?"); int nTopSel = GetTopSelectedItem(); CRect rctLBoxClient; GetClientRect(&rctLBoxClient); @@ -210,6 +216,7 @@ void CGrafixListBox2::ShowFirstSelection() int CGrafixListBox2::GetTopSelectedItem() const { + wxASSERT(!"dead code?"); int nTopSel; if (IsMultiSelect()) { @@ -231,6 +238,7 @@ int CGrafixListBox2::GetTopSelectedItem() const void CGrafixListBox2::MakeItemVisible(int nItem) { + wxASSERT(!"dead code?"); CRect rctLBoxClient; GetClientRect(&rctLBoxClient); CRect rct; @@ -243,6 +251,7 @@ void CGrafixListBox2::MakeItemVisible(int nItem) void CGrafixListBox2::SetSelFromPoint(CPoint point) { + wxASSERT(!"dead code?"); // Short circuit drag processing m_bAllowDrag = FALSE; SendMessage(WM_LBUTTONDOWN, (WPARAM)MK_LBUTTON, @@ -251,27 +260,28 @@ void CGrafixListBox2::SetSelFromPoint(CPoint point) MAKELPARAM(static_cast(point.x), static_cast(point.y))); m_bAllowDrag = TRUE; } +#endif ///////////////////////////////////////////////////////////////////////////// -void CGrafixListBox2::DoToolTipHitProcessing(CPoint point) +void CGrafixListBox2::DoToolTipHitProcessing(wxPoint point) { if (!OnIsToolTipsEnabled()) return; - if (m_toolTip.m_hWnd == NULL) - { - m_toolTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOPREFIX); - m_toolTip.SetMaxTipWidth(MAX_LISTITEM_TIP_WIDTH); - } + m_toolTip.SetMaxWidth(MAX_LISTITEM_TIP_WIDTH); - CRect rctTool; + wxRect rctTool; GameElement nItemCode = OnGetHitItemCodeAtPoint(point, rctTool); if (nItemCode != m_nCurItemCode) { // Object changed so delete previous tool definition - m_toolTip.DelTool(this, ID_TIP_LISTITEM_HIT); + if (!m_rectToolTip.IsEmpty()) + { + m_toolTip.Delete(*this, m_rectToolTip); + m_rectToolTip = wxRect(); + } m_nCurItemCode = nItemCode; if (nItemCode != Invalid_v) { @@ -279,19 +289,21 @@ void CGrafixListBox2::DoToolTipHitProcessing(CPoint point) CB::string strTip; // Call subclass for info - OnGetTipTextForItemCode(nItemCode, strTip); + strTip = OnGetTipTextForItemCode(nItemCode); if (!strTip.empty()) { - m_toolTip.AddTool(this, strTip, rctTool, ID_TIP_LISTITEM_HIT); - m_toolTip.Activate(TRUE); + m_toolTip.Add(*this, rctTool, strTip); + m_rectToolTip = rctTool; + m_toolTip.Enable(TRUE); } } else - m_toolTip.Activate(FALSE); + m_toolTip.Enable(FALSE); } } +#if 0 LRESULT CGrafixListBox2::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (m_toolTip.m_hWnd != NULL && message >= WM_MOUSEFIRST && @@ -329,35 +341,45 @@ void CGrafixListBox2::DrawItem(LPDRAWITEMSTRUCT lpDIS) CRect rct(lpDIS->rcItem); OnItemDraw(CheckedDeref(pDC), nIndex, lpDIS->itemAction, lpDIS->itemState, rct); } +#endif ///////////////////////////////////////////////////////////////////////////// // CGrafixListBox2 Message Processing -void CGrafixListBox2::OnLButtonDown(UINT nFlags, CPoint point) +void CGrafixListBox2::OnLButtonDown(wxMouseEvent& event) { - CListBox::OnLButtonDown(nFlags, point); // Allow field selection + ExecutePostProcessEvents(); + wxASSERT(!GetCapture()); + event.Skip(); // Allow field selection - int nIdx; - if ((nIdx = GetCurSel()) == -1) - return; - if (m_bAllowDrag) - { - m_hLastWnd = NULL; - m_clickPoint = point; // For hysteresis - m_triggeredCursor = FALSE; // -Ditto- - } + PushPostProcessEvent([this, event]{ + wxASSERT(GetCapture() == this); + if (GetSelectedCount() == 0) + return; + if (m_bAllowDrag) + { + wxASSERT(!"unreachable code"); + m_hLastWnd = NULL; + m_clickPoint = event.GetPosition(); // For hysteresis + m_triggeredCursor = FALSE; // -Ditto- + } + }); } -void CGrafixListBox2::OnLButtonUp(UINT nFlags, CPoint point) +void CGrafixListBox2::OnLButtonUp(wxMouseEvent& event) { + ExecutePostProcessEvents(); +#if 0 if (m_nTimerID) { KillTimer(m_nTimerID); m_nTimerID = uintptr_t(0); } +#endif if (m_bAllowDrag) { ASSERT(!"unreachable code"); +#if 0 BOOL bWasDragging = CWnd::GetCapture() == this; CListBox::OnLButtonUp(nFlags, point); @@ -370,25 +392,6 @@ void CGrafixListBox2::OnLButtonUp(UINT nFlags, CPoint point) #if defined(GPLAY) m_pDoc->AssignNewMoveGroup(); #endif - if (IsMultiSelect()) - { - CWnd *pWnd = GetParent(); - ASSERT(pWnd != NULL); - pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM_LIST2, (WPARAM)&m_multiSelList); - } - else - { - ASSERT(!"unreachable code"); - ASSERT(!"what is m_dragType here?"); -#if 0 - // The parent may want to override the value. - int nValueOverride = di.m_dwVal; - CWnd *pWnd = GetParent(); - ASSERT(pWnd != NULL); - pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM2, (WPARAM)&nValueOverride); - di.m_dwVal = nValueOverride; -#endif - } ReleaseCapture(); SetCursor(LoadCursor(NULL, IDC_ARROW)); @@ -410,22 +413,27 @@ void CGrafixListBox2::OnLButtonUp(UINT nFlags, CPoint point) OnDragCleanup(di); // Tell subclass we're all done. m_multiSelList.clear(); } +#endif } else - CListBox::OnLButtonUp(nFlags, point); + { + event.Skip(); + } } -void CGrafixListBox2::OnMouseMove(UINT nFlags, CPoint point) +void CGrafixListBox2::OnMouseMove(wxMouseEvent& event) { - if (CWnd::GetCapture() != this) + ExecutePostProcessEvents(); + if (!HasCapture()) { // Only process tool tips when we aren't draggin stuff around - DoToolTipHitProcessing(point); + DoToolTipHitProcessing(event.GetPosition()); } if (m_bAllowDrag) { - ASSERT(!"unreachable code"); + wxASSERT(!"unreachable code"); +#if 0 if (CWnd::GetCapture() != this) return; // OK...We are dragging. Let's check if the cursor has been @@ -485,15 +493,20 @@ void CGrafixListBox2::OnMouseMove(UINT nFlags, CPoint point) SetCursor(hCursor); else SetCursor(g_res.hcrNoDrop); +#endif } else - CListBox::OnMouseMove(nFlags, point); + { + event.Skip(); + } } ///////////////////////////////////////////////////////////////////////////// +#if 0 CWnd* CGrafixListBox2::GetWindowFromPoint(CPoint point) const { + wxASSERT(!"dead code?"); ClientToScreen(&point); CWnd* pWnd = WindowFromPoint(point); @@ -508,24 +521,26 @@ CWnd* CGrafixListBox2::GetWindowFromPoint(CPoint point) const return pWnd->IsWindowVisible() ? pWnd : NULL; } +#endif -int CGrafixListBox2::OnCreate(LPCREATESTRUCT lpCreateStruct) +void CGrafixListBox2::OnCreate(wxWindowCreateEvent& event) { - if (CListBox::OnCreate(lpCreateStruct) == -1) - return -1; + event.Skip(); m_pItemMap = NULL; +#if 0 m_nTimerID = uintptr_t(0); - - return 0; +#endif } ///////////////////////////////////////////////////////////////// -void CGrafixListBox2::DoInsertLineProcessing(const DragInfo& pdi) +void CGrafixListBox2::DoInsertLineProcessing(const DragInfoWx& pdi) { if (m_bAllowDropScroll) { + wxASSERT(!"dead code"); +#if 0 // Handle drawing of insert line CPoint pnt = pdi.m_point; int nSel = SpecialItemFromPoint(pnt); @@ -543,15 +558,19 @@ void CGrafixListBox2::DoInsertLineProcessing(const DragInfo& pdi) { DrawInsert(nSel); // Move insert line } +#endif } } ///////////////////////////////////////////////////////////////// -void CGrafixListBox2::DoAutoScrollProcessing(const DragInfo& pdi) +void CGrafixListBox2::DoAutoScrollProcessing(const DragInfoWx& pdi) { + wxASSERT(!m_bAllowDropScroll); +#if 0 if (m_bAllowDropScroll && m_nTimerID == uintptr_t(0)) { + wxASSERT(!"dead code"); CRect rct; GetClientRect(&rct); rct.InflateRect(0, -scrollZonePixels); @@ -562,13 +581,16 @@ void CGrafixListBox2::DoAutoScrollProcessing(const DragInfo& pdi) m_nTimerID = SetTimer(timerScrollIDStart, timerScrollStart, NULL); } } +#endif } ///////////////////////////////////////////////////////////////// // Pass it up to the parent by default. -LRESULT CGrafixListBox2::OnDragItem(WPARAM wParam, LPARAM lParam) +void CGrafixListBox2::OnDragItem(DragDropEvent& /*event*/) { + wxASSERT(!"dead code"); +#if 0 if (wParam != GetProcessId(GetCurrentProcess())) { return -1; @@ -583,13 +605,16 @@ LRESULT CGrafixListBox2::OnDragItem(WPARAM wParam, LPARAM lParam) if (pdi.m_phase == PhaseDrag::Over && lResult != 0) DoAutoScrollProcessing(di); return lResult; +#endif } +#if 0 void CGrafixListBox2::OnTimer(uintptr_t nIDEvent) { if (nIDEvent != m_nTimerID) return; + wxASSERT(!"dead code"); CPoint point; CRect rctClient; CRect rct; @@ -653,6 +678,7 @@ void CGrafixListBox2::OnTimer(uintptr_t nIDEvent) int CGrafixListBox2::SpecialItemFromPoint(CPoint pnt) const { + wxASSERT(!"dead code"); BOOL bBucket; int nSel = (int)ItemFromPoint(pnt, bBucket); CRect rct; @@ -715,21 +741,28 @@ void CGrafixListBox2::DrawSingle(int nIndex) ReleaseDC(pDC); } -CPoint CGrafixListBox2::ClientToItem(CPoint point) const +#endif + +void CGrafixListBox2::PushPostProcessEvent(std::function&& f) { - // account for horz scroll - int xOffset = GetScrollPos(SB_HORZ); - ASSERT(xOffset >= 0); - point.x += xOffset; - return point; + // I'm pretty sure we should have at most one partial event + /* TODO: after confirming at most one, + convert to std::optional<> instead of queue<> */ + wxASSERT(postProcessEvents.empty()); + postProcessEvents.push(std::move(f)); + CallAfter([this]{ ExecutePostProcessEvents(); }); } -CRect CGrafixListBox2::ItemToClient(CRect rect) const +void CGrafixListBox2::ExecutePostProcessEvents() { - // account for horz scroll - int xOffset = GetScrollPos(SB_HORZ); - ASSERT(xOffset >= 0); - rect.OffsetRect(-xOffset, 0); - return rect; + // I'm pretty sure we should have at most one partial event + wxASSERT(postProcessEvents.size() <= 1); + while (!postProcessEvents.empty()) + { + // need to pop before executing to avoid recursion + std::function f = std::move(postProcessEvents.front()); + postProcessEvents.pop(); + f(); + } } diff --git a/GShr/LBoxGfx2.h b/GShr/LBoxGfx2.h index 78e26236..85b1ede2 100644 --- a/GShr/LBoxGfx2.h +++ b/GShr/LBoxGfx2.h @@ -1,6 +1,6 @@ // LBoxGfx2.h // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -25,11 +25,14 @@ #ifndef _LBOXGFX2_H #define _LBOXGFX2_H +#include + #ifndef _DRAGDROP_H #include "DragDrop.h" #endif #include "MapStrng.h" +#include "LBoxVHScrl.h" class CDrawObj; @@ -38,17 +41,10 @@ class CDrawObj; #define ID_TIP_LISTITEM_HIT 1 #define MAX_LISTITEM_TIP_WIDTH 200 // Max pixel width of tips -///////////////////////////////////////////////////////////////////////////// -// These messages are sent by the CGrafixListBox2 to its parent window. -// It allows the list's content to be overridden. It's primary use -// is to deliver a random selection of pieces or markers. -#define WM_OVERRIDE_SELECTED_ITEM2 (WM_USER + 502) // WPARAM = int* -#define WM_OVERRIDE_SELECTED_ITEM_LIST2 (WM_USER + 503) // WPARAM = CDWordArray* - ///////////////////////////////////////////////////////////////////////////// // Custom Listbox - containing colors -class CGrafixListBox2 : public CListBox +class CGrafixListBox2 : public CB::VListBoxHScroll { // Construction public: @@ -60,11 +56,11 @@ class CGrafixListBox2 : public CListBox void EnableDrag(BOOL bEnable = TRUE) { m_bAllowDrag = bEnable; } void EnableSelfDrop(BOOL bEnable = TRUE) { m_bAllowSelfDrop = bEnable; } void EnableDropScroll(BOOL bEnable = TRUE) { m_bAllowDropScroll = bEnable; } - const std::vector>* GetItemMap() const { return m_pItemMap; } + const std::vector>* GetItemMap() const { return m_pItemMap; } const CDrawObj& GetCurMapItem() const; std::vector> GetCurMappedItemList() const; BOOL IsMultiSelect() const - { return (GetStyle() & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) != 0; } + { return HasMultipleSelection(); } // Note: the following pointer is only good during drag and drop. // the data is only good during the drop. It is essentially a // hack to have valid data when selecting items with Shift-Click. @@ -76,11 +72,11 @@ class CGrafixListBox2 : public CListBox // Operations public: - void SetItemMap(const std::vector>* pMap, BOOL bKeepPosition = TRUE); + void SetItemMap(const std::vector>* pMap, BOOL bKeepPosition = TRUE); void UpdateList(BOOL bKeepPosition = TRUE); void SetCurSelMapped(const CDrawObj& pMapVal); void SetCurSelsMapped(const std::vector>& items); - void SetSelFromPoint(CPoint point); + void SetSelFromPoint(wxPoint point); void ShowFirstSelection(); const CDrawObj& MapIndexToItem(size_t nIndex) const; CDrawObj& MapIndexToItem(size_t nIndex) @@ -92,75 +88,95 @@ class CGrafixListBox2 : public CListBox // Overrides - the subclass of this class must override these public: +#if 0 virtual CSize OnItemSize(size_t nIndex) const /* override */ = 0; virtual void OnItemDraw(CDC& pDC, size_t nIndex, UINT nAction, UINT nState, CRect rctItem) const /* override */ = 0; - virtual BOOL OnDragSetup(DragInfo& pDI) const /* override */ +#endif + virtual BOOL OnDragSetup(DragInfoWx& pDI) const /* override */ { pDI.SetDragType(DRAG_INVALID); return FALSE; } - virtual void OnDragCleanup(const DragInfo& pDI) const /* override */ { } + virtual void OnDragCleanup(const DragInfoWx& pDI) const /* override */ { } // For tool tip processing virtual BOOL OnIsToolTipsEnabled() const /* override */ { return FALSE; } - virtual GameElement OnGetHitItemCodeAtPoint(CPoint point, CRect& rct) const /* override */ { return Invalid_v; } - virtual void OnGetTipTextForItemCode(GameElement nItemCode, CB::string& strTip) const /* override */ { } + virtual GameElement OnGetHitItemCodeAtPoint(wxPoint point, wxRect& rct) const /* override */ { return Invalid_v; } + virtual CB::string OnGetTipTextForItemCode(GameElement nItemCode) const /* override */ { return CB::string(); } // Implementation protected: /* N.B.: this class could be templatized to hold any pointer, but that generality isn't actually needed yet */ - const std::vector>* m_pItemMap; // Maps index to item + const std::vector>* m_pItemMap; // Maps index to item std::vector> m_multiSelList; // Holds mapped multi select items on drop // Tool tip support - CToolTipCtrl m_toolTip; - GameElement m_nCurItemCode; + CB::ToolTip m_toolTip; // Tooltip of tile text popups + GameElement m_nCurItemCode = Invalid_v; + wxRect m_rectToolTip = wxRect(); // Drag and scroll support vars BOOL m_bAllowDrag; BOOL m_bAllowSelfDrop; // Only if m_bAllowDrag == TRUE BOOL m_bAllowDropScroll; // Scroll on OnDragItem - CPoint m_clickPoint; - uintptr_t m_nTimerID; + wxPoint m_clickPoint; +#if 0 + wxTimer m_nTimerID; +#endif BOOL m_triggeredCursor; - HWND m_hLastWnd; + wxWindow* m_hLastWnd; int m_nLastInsert; // Last index with insert line void SetDocument(CGamDoc& doc) { m_pDoc = &doc; } - void DoInsertLineProcessing(const DragInfo& pdi); - void DoAutoScrollProcessing(const DragInfo& pdi); - void DoToolTipHitProcessing(CPoint point); + void DoInsertLineProcessing(const DragInfoWx& pdi); + void DoAutoScrollProcessing(const DragInfoWx& pdi); + void DoToolTipHitProcessing(wxPoint point); - CWnd* GetWindowFromPoint(CPoint point) const; - int SpecialItemFromPoint(CPoint pnt) const; + wxWindow* GetWindowFromPoint(wxPoint point); + int SpecialItemFromPoint(wxPoint pnt) const; void DrawInsert(int nIndex); void DrawSingle(int nIndex); - CPoint ClientToItem(CPoint point) const; - CRect ItemToClient(CRect rect) const; + wxPoint ClientToItem(wxPoint point) const + { + return CalcUnscrolledPosition(point); + } + wxRect ItemToClient(wxRect rect) const + { + return wxRect(CalcScrolledPosition(rect.GetTopLeft()), rect.GetSize()); + } // Overrides +#if 0 virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMIS) override; virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS) override; virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam) override; +#endif - //{{AFX_MSG(CGrafixListBox2) - afx_msg void OnLButtonDown(UINT nFlags, CPoint point); - afx_msg void OnMouseMove(UINT nFlags, CPoint point); - afx_msg void OnLButtonUp(UINT nFlags, CPoint point); - afx_msg void OnTimer(uintptr_t nIDEvent); - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - afx_msg LRESULT OnDragItem(WPARAM wParam, LPARAM lParam); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() + void OnLButtonDown(wxMouseEvent& event); + void OnMouseMove(wxMouseEvent& event); + void OnLButtonUp(wxMouseEvent& event); +#if 0 + void OnTimer(wxTimerEvent& event); +#endif + void OnCreate(wxWindowCreateEvent& event); + void OnDragItem(DragDropEvent& event); + wxDECLARE_EVENT_TABLE(); private: CB::propagate_const m_pDoc = nullptr; -}; + /* wxWidgets does not support post-processing of events + (see https://docs.wxwidgets.org/stable/overview_events.html#overview_events_virtual), + so we need to use wxEvtHandler::CallAfter() to + approximate post-processing. */ + void PushPostProcessEvent(std::function&& f); + void ExecutePostProcessEvents(); + std::queue> postProcessEvents; +}; #endif diff --git a/GShr/LBoxGrfx.cpp b/GShr/LBoxGrfx.cpp index 10864890..4acfcbcd 100644 --- a/GShr/LBoxGrfx.cpp +++ b/GShr/LBoxGrfx.cpp @@ -1,6 +1,6 @@ // LBoxGrfx.cpp // -// Copyright (c) 1994-2024 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -34,6 +34,8 @@ #define new DEBUG_NEW #endif +wxDEFINE_EVENT(WM_OVERRIDE_SELECTED_ITEM_WX, OverrideSelectedItemEvent); +wxDEFINE_EVENT(WM_OVERRIDE_SELECTED_ITEM_LIST_WX, OverrideSelectedItemListEvent); wxDEFINE_EVENT(WM_GET_DRAG_SIZE_WX, GetDragSizeEvent); DragInfo CGrafixListBox::di; @@ -673,11 +675,13 @@ wxBEGIN_EVENT_TABLE(CGrafixListBoxWx, CB::VListBoxHScroll) ON_WM_CREATE() #endif EVT_DRAGDROP(OnDragItem) + EVT_TIMER(XRCID("ID_TIP_LISTITEM_MSG_TIMER"), NotificationTipTimeoutHandler) wxEND_EVENT_TABLE() ///////////////////////////////////////////////////////////////////////////// CGrafixListBoxWx::CGrafixListBoxWx() : + m_toolMsgTipTimer(this, XRCID("ID_TIP_LISTITEM_MSG_TIMER")), m_nCurItemCode(Invalid_v), m_nTimerID(this) { @@ -685,6 +689,9 @@ CGrafixListBoxWx::CGrafixListBoxWx() : m_bAllowDrag = FALSE; m_bAllowSelfDrop = FALSE; m_bAllowDropScroll = FALSE; + + m_toolMsgTip.SetBalloonMode(true); + m_toolMsgTip.SetMaxWidth(MAX_LISTITEM_TIP_WIDTH); } CGrafixListBoxWx::~CGrafixListBoxWx() @@ -704,65 +711,46 @@ void CGrafixListBoxWx::SetNotificationTip(int nItem, UINT nResID) CB::string str = CB::string::LoadString(nResID); SetNotificationTip(nItem, str); } +#endif // Shows a notification tip over a specified item. If the item // doesn't exist, the center of the listbox receives the tip. -void CGrafixListBoxWx::SetNotificationTip(int nItem, const CB::string& pszTip) +void CGrafixListBoxWx::SetNotificationTip(size_t nItem, const CB::string& pszTip) { - if (m_toolMsgTip.m_hWnd == NULL) - { - m_toolMsgTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOPREFIX); - m_toolMsgTip.SetMaxTipWidth(MAX_LISTITEM_TIP_WIDTH); - } - ClearNotificationTip(); - TOOLINFO ti; - m_toolMsgTip.FillInToolInfo(ti, this, ID_TIP_LISTITEM_MSG); - ti.uFlags |= TTF_TRACK; - ti.lpszText = const_cast(pszTip.v_str()); - - m_toolMsgTip.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti); + m_toolMsgTip.Add(*this, pszTip, CB::ToolTip::TRACK); MakeItemVisible(nItem); - CRect rctItem; - if (!GetItemRect(nItem, rctItem)) - GetClientRect(rctItem); + wxRect rctItem = GetItemRect(nItem); + if (rctItem.IsEmpty()) + rctItem = GetClientRect(); - CPoint pntClient = rctItem.CenterPoint(); + wxPoint pntClient = GetMidRect(rctItem); - CPoint pntScreen(pntClient); - ClientToScreen(&pntScreen); + wxPoint pntScreen = ClientToScreen(pntClient); - m_toolMsgTip.Activate(TRUE); - m_toolMsgTip.SendMessage(TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&ti); - m_toolMsgTip.SendMessage(TTM_TRACKPOSITION, 0, - (LPARAM)MAKELONG(static_cast(pntScreen.x), static_cast(pntScreen.y))); + m_toolMsgTip.Enable(TRUE); + m_toolMsgTip.TrackActivate(*this, true); + m_toolMsgTip.TrackPosition(pntScreen); - SetTimer(ID_TIP_LISTITEM_MSG_TIMER, MAX_TIP_LISTITEM_MSG_TIME, - NotificationTipTimeoutHandler); + m_toolMsgTipTimer.Start(MAX_TIP_LISTITEM_MSG_TIME, wxTIMER_ONE_SHOT); } void CGrafixListBoxWx::ClearNotificationTip() { - KillTimer(ID_TIP_LISTITEM_MSG_TIMER); // Kill it in case it's still running + m_toolMsgTipTimer.Stop(); - CToolInfo ti; - m_toolMsgTip.GetToolInfo(ti, this, ID_TIP_LISTITEM_MSG); - m_toolMsgTip.SendMessage(TTM_TRACKACTIVATE, (WPARAM)FALSE, (LPARAM)&ti); - m_toolMsgTip.DelTool(this, ID_TIP_LISTITEM_MSG); - m_toolMsgTip.Activate(FALSE); + m_toolMsgTip.TrackActivate(*this, false); + m_toolMsgTip.Delete(*this); + m_toolMsgTip.Enable(FALSE); } -void CALLBACK CGrafixListBoxWx::NotificationTipTimeoutHandler(HWND hwnd, - UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +void CGrafixListBoxWx::NotificationTipTimeoutHandler(wxTimerEvent& /*event*/) { - CGrafixListBox* pWnd = (CGrafixListBox*)CWnd::FromHandle(hwnd); - ASSERT(pWnd != NULL); - pWnd->ClearNotificationTip(); + ClearNotificationTip(); } -#endif ///////////////////////////////////////////////////////////////////////////// @@ -806,33 +794,28 @@ int CGrafixListBoxWx::GetTopSelectedItem() const ///////////////////////////////////////////////////////////////////////////// // If the selection is out of view, force it into view. -#if 0 -void CGrafixListBoxWx::MakeItemVisible(int nItem) +void CGrafixListBoxWx::MakeItemVisible(size_t nItem) { - CRect rctLBoxClient; - GetClientRect(&rctLBoxClient); - CRect rct; - GetItemRect(nItem, &rct); - if (!rct.IntersectRect(rct, rctLBoxClient)) - SetTopIndex(nItem); + wxRect rctLBoxClient = GetClientRect(); + wxRect rct = GetItemRect(nItem); + if (!rct.Intersects(rctLBoxClient)) + ScrollToRow(nItem); } -#endif ///////////////////////////////////////////////////////////////////////////// void CGrafixListBoxWx::SetSelFromPoint(wxPoint point) { wxASSERT(postProcessEvents.empty()); - // Short circuit drag processing - m_bAllowDrag = FALSE; - wxMouseEvent down(wxEVT_LEFT_DOWN); - down.SetPosition(point); - ProcessWindowEvent(down); - wxMouseEvent up(wxEVT_LEFT_UP); - up.SetPosition(point); - ProcessWindowEvent(up); - m_bAllowDrag = TRUE; - wxASSERT(postProcessEvents.empty()); + if (GetItemCount() == size_t(0)) + { + return; + } + int itemFromPoint = VirtualHitTest(point.y); + if (itemFromPoint != wxNOT_FOUND) + { + SetSelection(itemFromPoint); + } } ///////////////////////////////////////////////////////////////////////////// @@ -865,7 +848,7 @@ void CGrafixListBoxWx::DoToolTipHitProcessing(wxPoint point) if (!strTip.empty()) { wxRect screenTool(ClientToScreen(rctTool.GetTopLeft()), rctTool.GetSize()); - m_toolTip = new wxTipWindow(this, strTip, MAX_LISTITEM_TIP_WIDTH, &m_toolTip, &screenTool); + m_toolTip = wxTipWindow::New(this, strTip, MAX_LISTITEM_TIP_WIDTH, &screenTool); } } } diff --git a/GShr/LBoxGrfx.h b/GShr/LBoxGrfx.h index ce44d038..fadc2020 100644 --- a/GShr/LBoxGrfx.h +++ b/GShr/LBoxGrfx.h @@ -1,6 +1,6 @@ // LBoxGrfx.h // -// Copyright (c) 1994-2024 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -26,6 +26,7 @@ #define _LBOXGRFX_H #include +#include #ifndef _DRAGDROP_H #include "DragDrop.h" @@ -48,55 +49,95 @@ // These messages are sent by the CGrafixListBox to its parent window. // It allows the list's content to be overridden. It's primary use // is to deliver a random selection of pieces or markers. -#define WM_OVERRIDE_SELECTED_ITEM (WM_USER + 500) // WPARAM = COverrideInfoBase<>* -struct COverrideInfoBase +#define WM_OVERRIDE_SELECTED_ITEM (WM_USER + 500) // WPARAM = OverrideSelectedItemEvent* +class OverrideSelectedItemEvent : public wxEvent { -protected: - COverrideInfoBase(DragType dt) : m_dragType(dt) {} +public: + /* currently supports MarkID and TileID + (easy to add more to variant) */ + template + OverrideSelectedItemEvent(T& id); - template - void CheckTypeBase() const + template + const T& ID() const { - ASSERT(m_dragType == DT); - /* TODO: This check could be removed to improve release - build performance if we trust ourselves to always - catch any m_dragType mistakes in testing. */ - if (m_dragType != DT) - { - AfxThrowInvalidArgException(); - } + return std::get>(id).get(); + } + + template + T& ID() + { + return const_cast(std::as_const(*this).ID()); } + wxEvent* Clone() const override { return new OverrideSelectedItemEvent(*this); } + private: - const DragType m_dragType; + std::variant< + std::reference_wrapper, + std::reference_wrapper, + std::nullptr_t // dummy for allowing , on previous line + > id; }; +wxDECLARE_EVENT(WM_OVERRIDE_SELECTED_ITEM_WX, OverrideSelectedItemEvent); -template -struct COverrideInfo +template +OverrideSelectedItemEvent::OverrideSelectedItemEvent(T& id) : + wxEvent(wxID_ANY, WM_OVERRIDE_SELECTED_ITEM_WX), + id(std::ref(id)) { -}; +} -template<> -struct COverrideInfo : private COverrideInfoBase +typedef void (wxEvtHandler::* OverrideSelectedItemEventFunction)(OverrideSelectedItemEvent&); +#define OverrideSelectedItemEventHandler(func) wxEVENT_HANDLER_CAST(OverrideSelectedItemEventFunction, func) +#define EVT_OVERRIDE_SELECTED_ITEM(func) \ + wx__DECLARE_EVT0(WM_OVERRIDE_SELECTED_ITEM_WX, OverrideSelectedItemEventHandler(func)) + +#define WM_OVERRIDE_SELECTED_ITEM_LIST (WM_USER + 501) // WPARAM = OverrideSelectedItemListEvent* +class OverrideSelectedItemListEvent : public wxEvent { - COverrideInfo(MarkID& mid) : COverrideInfoBase(DRAG_MARKER), m_markID(mid) {} +public: + /* currently supports MarkID, PieceID, and TileID + (easy to add more to variant) */ + template + OverrideSelectedItemListEvent(std::vector& id); + + template + const std::vector& Vector() const + { + return std::get>>(vector).get(); + } + + template + std::vector& Vector() + { + return const_cast&>(std::as_const(*this).Vector()); + } - void CheckType() const { CheckTypeBase(); } + wxEvent* Clone() const override { return new OverrideSelectedItemListEvent(*this); } - MarkID& m_markID; +private: + std::variant< + std::reference_wrapper>, + std::reference_wrapper>, + std::reference_wrapper>, + std::nullptr_t // dummy for allowing , on previous line + > vector; }; +wxDECLARE_EVENT(WM_OVERRIDE_SELECTED_ITEM_LIST_WX, OverrideSelectedItemListEvent); -template<> -struct COverrideInfo : private COverrideInfoBase +template +OverrideSelectedItemListEvent::OverrideSelectedItemListEvent(std::vector& v) : + wxEvent(wxID_ANY, WM_OVERRIDE_SELECTED_ITEM_LIST_WX), + vector(std::ref(v)) { - COverrideInfo(TileID& tid) : COverrideInfoBase(DRAG_TILE), m_tileID(tid) {} +} - void CheckType() const { CheckTypeBase(); } +typedef void (wxEvtHandler::* OverrideSelectedItemListEventFunction)(OverrideSelectedItemListEvent&); +#define OverrideSelectedItemListEventHandler(func) wxEVENT_HANDLER_CAST(OverrideSelectedItemListEventFunction, func) +#define EVT_OVERRIDE_SELECTED_ITEM_LIST(func) \ + wx__DECLARE_EVT0(WM_OVERRIDE_SELECTED_ITEM_LIST_WX, OverrideSelectedItemListEventHandler(func)) - TileID& m_tileID; -}; - -#define WM_OVERRIDE_SELECTED_ITEM_LIST (WM_USER + 501) // WPARAM = std::vector>*, LPARAM = XxxxID::PREFIX /* We don't allow drop if the dropped objects are too big for the destination, but checking requires knowing the size of the dropped objects. So, parallel to @@ -398,21 +439,22 @@ class CGrafixListBoxData : public BASE_WND CWnd* pWnd = this->GetParent(); ASSERT(pWnd != NULL); - pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM_LIST, reinterpret_cast(&m_multiSelList), T::PREFIX); + OverrideSelectedItemListEvent oil(m_multiSelList); + pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM_LIST, reinterpret_cast(&oil)); } else { // The parent may want to override the value. if (BASE_WND::di.GetDragType() == DRAG_MARKER) { - COverrideInfo oi(BASE_WND::di.GetSubInfo().m_markID); + OverrideSelectedItemEvent oi(BASE_WND::di.GetSubInfo().m_markID); CWnd* pWnd = this->GetParent(); ASSERT(pWnd != NULL); pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM, reinterpret_cast(&oi)); } else if (BASE_WND::di.GetDragType() == DRAG_TILE) { - COverrideInfo oi(BASE_WND::di.GetSubInfo().m_tileID); + OverrideSelectedItemEvent oi(BASE_WND::di.GetSubInfo().m_tileID); CWnd* pWnd = this->GetParent(); ASSERT(pWnd != NULL); pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM, reinterpret_cast(&oi)); @@ -483,16 +525,15 @@ class CGrafixListBoxWx : public CB::VListBoxHScroll public: void SetSelFromPoint(wxPoint point); void ShowFirstSelection(); -#if 0 - void MakeItemVisible(int nItem); + void MakeItemVisible(size_t nItem); // Notification Tooltip Support +#if 0 void SetNotificationTip(int nItem, UINT nResID); - void SetNotificationTip(int nItem, const CB::string& pszTip); - void ClearNotificationTip(); - static void CALLBACK NotificationTipTimeoutHandler(HWND hwnd, UINT uMsg, - UINT_PTR idEvent, DWORD dwTime); #endif + void SetNotificationTip(size_t nItem, const CB::string& pszTip); + void ClearNotificationTip(); + void NotificationTipTimeoutHandler(wxTimerEvent& event); // Overrides - the subclass of this class must override these public: @@ -522,10 +563,9 @@ class CGrafixListBoxWx : public CB::VListBoxHScroll // Implementation protected: // Tool tip support -#if 0 - CToolTipCtrl m_toolMsgTip; // Tooltip for notifications -#endif - wxTipWindow* m_toolTip = nullptr; // Tooltip of tile text popups + CB::ToolTip m_toolMsgTip; // Tooltip for notifications + wxTimer m_toolMsgTipTimer; + wxTipWindow::Ref m_toolTip; // Tooltip of tile text popups GameElement m_nCurItemCode; // current active tip item code // Drag and scroll support vars @@ -674,9 +714,11 @@ class CGrafixListBoxDataWx : public BASE_WND if (bKeepPosition) { this->ScrollToRow(CB::min(nTopIdx, nItem - size_t(1))); - if (nFcsIdx != wxNOT_FOUND) + if (nFcsIdx != wxNOT_FOUND && + this->GetItemCount() >= size_t(1)) this->SetCurrent(CB::min(nFcsIdx, value_preserving_cast(nItem - size_t(1)))); - if (nCurSel != wxNOT_FOUND) + if (nCurSel != wxNOT_FOUND && + this->GetItemCount() >= size_t(1)) this->SetSelection(CB::min(nCurSel, value_preserving_cast(nItem - size_t(1)))); } } @@ -746,39 +788,26 @@ class CGrafixListBoxDataWx : public BASE_WND m_multiSelList = GetCurMappedItemList(); // this is only needed for PalTray, so don't implement now -#if defined(GPLAY) - wxASSERT(!"TODO:"); -#if 0 - CWnd* pWnd = this->GetParent(); - ASSERT(pWnd != NULL); - pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM_LIST, reinterpret_cast(&m_multiSelList), T::PREFIX); -#endif -#endif + wxWindow& pWnd = CheckedDeref(this->GetParent()); + OverrideSelectedItemListEvent oil(m_multiSelList); + pWnd.ProcessWindowEvent(oil); } else { // The parent may want to override the value. if (BASE_WND::di.GetDragType() == DRAG_MARKER) { - wxASSERT(!"TODO:"); -#if 0 - COverrideInfo oi(BASE_WND::di.GetSubInfo().m_markID); - CWnd* pWnd = this->GetParent(); - ASSERT(pWnd != NULL); - pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM, reinterpret_cast(&oi)); -#endif + OverrideSelectedItemEvent oi(BASE_WND::di.GetSubInfo().m_markID); + wxWindow* pWnd = this->GetParent(); + wxASSERT(pWnd != NULL); + pWnd->ProcessWindowEvent(oi); } else if (BASE_WND::di.GetDragType() == DRAG_TILE) { -#if defined(GPLAY) - wxASSERT(!"TODO:"); -#if 0 - COverrideInfo oi(BASE_WND::di.GetSubInfo().m_tileID); - CWnd* pWnd = this->GetParent(); - ASSERT(pWnd != NULL); - pWnd->SendMessage(WM_OVERRIDE_SELECTED_ITEM, reinterpret_cast(&oi)); -#endif -#endif + OverrideSelectedItemEvent oi(BASE_WND::di.GetSubInfo().m_tileID); + wxWindow* pWnd = this->GetParent(); + wxASSERT(pWnd != NULL); + pWnd->ProcessWindowEvent(oi); } else { diff --git a/GShr/LBoxMark.cpp b/GShr/LBoxMark.cpp index 30b9b615..64b2cbc2 100644 --- a/GShr/LBoxMark.cpp +++ b/GShr/LBoxMark.cpp @@ -1,6 +1,6 @@ // LBoxMark.cpp // -// Copyright (c) 1994-2024 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -333,42 +333,44 @@ BOOL CMarkListBoxWx::OnDoesItemHaveTipText(size_t nItem) const ///////////////////////////////////////////////////////////////////////////// -#if 0 -void CMarkListBox::SelectMarker(MarkID mid) +void CMarkListBoxWx::SelectMarker(MarkID mid) { size_t nIndex = MapItemToIndex(mid); // NO LONGER IMPOSSIBLE SINCE HIDE ALL MARKERS. ASSERT(nIndex != -1); if (nIndex == Invalid_v) { - if (GetCount() >= 1) - SetCurSel(0); // Just select the first one. + if (GetItemCount() >= 1) + SetSelection(0); // Just select the first one. } else { - ShowListIndex(value_preserving_cast(nIndex)); - SetCurSel(value_preserving_cast(nIndex)); + ShowListIndex(nIndex); + SetSelection(value_preserving_cast(nIndex)); } } ///////////////////////////////////////////////////////////////////////////// -void CMarkListBox::ShowListIndex(int nPos) +void CMarkListBoxWx::ShowListIndex(size_t nPos) { - if (nPos < GetTopIndex()) + if (nPos < GetVisibleRowsBegin()) { - SetTopIndex(nPos); + ScrollToRow(nPos); return; } +#if 0 CRect rct; GetItemRect(nPos, &rct); CRect rctClient; GetClientRect(&rctClient); if (rct.IntersectRect(&rct, &rctClient)) +#else + if (IsRowVisible(nPos)) +#endif return; - SetTopIndex(nPos); + ScrollToRow(nPos); } -#endif ///////////////////////////////////////////////////////////////////////////// @@ -424,8 +426,7 @@ void CMarkListBoxWx::OnDrawItem(wxDC& pDC, const wxRect& rctItem, size_t nIndex) } } -#if 0 -BOOL CMarkListBox::OnDragSetup(DragInfo& pDI) const +BOOL CMarkListBoxWx::OnDragSetup(DragInfoWx& pDI) const { #ifdef GPLAY if (m_pDoc->IsPlaying()) @@ -438,8 +439,7 @@ BOOL CMarkListBox::OnDragSetup(DragInfo& pDI) const pDI.GetSubInfo().m_markID = GetCurMapItem(); pDI.GetSubInfo().m_size = GetDragSize(); pDI.GetSubInfo().m_gamDoc = m_pDoc; - pDI.m_hcsrSuggest = g_res.hcrDragTile; + pDI.m_hcsrSuggest = g_res.hcrDragTileWx; return TRUE; } -#endif diff --git a/GShr/LBoxMark.h b/GShr/LBoxMark.h index a40e83bf..addde736 100644 --- a/GShr/LBoxMark.h +++ b/GShr/LBoxMark.h @@ -127,10 +127,8 @@ class CMarkListBoxWx : public CGrafixListBoxDataWx m_pDoc = pDoc; } -#if 0 void SelectMarker(MarkID mid); - void ShowListIndex(int nPos); -#endif + void ShowListIndex(size_t nPos); // Implementation protected: @@ -141,9 +139,7 @@ class CMarkListBoxWx : public CGrafixListBoxDataWx // Overrides wxSize GetItemSize(size_t nIndex) const override; void OnDrawItem(wxDC& pDC, const wxRect& rctItem, size_t nIndex) const override; -#if 0 - virtual BOOL OnDragSetup(DragInfo& pDI) const override; -#endif + BOOL OnDragSetup(DragInfoWx& pDI) const override; // Tool tip processing virtual BOOL OnIsToolTipsEnabled() const override; diff --git a/GShr/LBoxTileBase2.cpp b/GShr/LBoxTileBase2.cpp index cb8eb246..bf87b3ed 100644 --- a/GShr/LBoxTileBase2.cpp +++ b/GShr/LBoxTileBase2.cpp @@ -1,7 +1,7 @@ // LBoxTileBase2.cpp - base class used to handle a variety of tile oriented // listbox functions. // -// Copyright (c) 1994-2023 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -40,11 +40,9 @@ const int tileGap = 6; ///////////////////////////////////////////////////////////////////////////// -BEGIN_MESSAGE_MAP(CTileBaseListBox2, CGrafixListBox2) - //{{AFX_MSG_MAP(CTileBaseListBox2) - ON_WM_CREATE() - //}}AFX_MSG_MAP -END_MESSAGE_MAP() +wxBEGIN_EVENT_TABLE(CTileBaseListBox2, CGrafixListBox2) + EVT_WINDOW_CREATE(OnCreate) +wxEND_EVENT_TABLE() ///////////////////////////////////////////////////////////////////////////// @@ -53,14 +51,14 @@ CTileBaseListBox2::CTileBaseListBox2() m_bDisplayIDs = AfxGetApp()->GetProfileInt("Settings"_cbstring, "DisplayIDs"_cbstring, 0); m_bTipMarkItems = TRUE; - m_sizeTipMark = CSize(0,0); + m_sizeTipMark = wxSize(0,0); } ///////////////////////////////////////////////////////////////////////////// -CSize CTileBaseListBox2::DoOnItemSize(size_t nItem, const std::vector& tids) const +wxSize CTileBaseListBox2::DoOnItemSize(size_t nItem, const std::vector& tids) const { - ASSERT(!tids.empty() && tids[size_t(0)] != nullTid); // At least one tile needs to exist + wxASSERT(!tids.empty() && tids[size_t(0)] != nullTid); // At least one tile needs to exist int nHt = 0; for (size_t i = size_t(0) ; i < tids.size() ; ++i) @@ -78,12 +76,10 @@ CSize CTileBaseListBox2::DoOnItemSize(size_t nItem, const std::vector& t BOOL bItemHasTipText = OnDoesItemHaveTipText(nItem); // only using DC for measurement, so const_cast safe - CClientDC pDC(const_cast(this)); - CRect rctItem(0, 0, 32000, 32000); + wxWindowDC pDC(const_cast(this)); + wxRect rctItem(0, 0, 32000, 32000); - pDC.SaveDC(); - - int x = rctItem.left + tileBorder; + int x = rctItem.GetLeft() + tileBorder; DrawTipMarker(pDC, rctItem, bItemHasTipText, x); DrawItemDebugIDCode(pDC, nItem, rctItem, false, x); @@ -92,51 +88,36 @@ CSize CTileBaseListBox2::DoOnItemSize(size_t nItem, const std::vector& t DrawTileImage(pDC, rctItem, false, x, tids[i]); } - pDC.RestoreDC(-1); - - return CSize(x, nHt); + return wxSize(x, nHt); } ///////////////////////////////////////////////////////////////////////////// -void CTileBaseListBox2::DoOnDrawItem(CDC& pDC, size_t nItem, UINT nAction, UINT nState, - CRect rctItem, const std::vector& tids) const +void CTileBaseListBox2::DoOnDrawItem(wxDC& pDC, size_t nItem, + wxRect rctItem, const std::vector& tids) const { - if (nAction & (ODA_DRAWENTIRE | ODA_SELECT)) - { - ASSERT(!tids.empty() && tids[size_t(0)] != nullTid); - - BOOL bItemHasTipText = OnDoesItemHaveTipText(nItem); - - pDC.SaveDC(); - pDC.IntersectClipRect(&rctItem); - pDC.SetBkMode(TRANSPARENT); + wxASSERT(!tids.empty() && tids[size_t(0)] != nullTid); - CBrush brBack(GetSysColor(nState & ODS_SELECTED ? - COLOR_HIGHLIGHT : COLOR_WINDOW)); - pDC.FillRect(&rctItem, &brBack); // Fill background color + BOOL bItemHasTipText = OnDoesItemHaveTipText(nItem); - pDC.SetTextColor(GetSysColor(nState & ODS_SELECTED ? - COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)); + pDC.SetClippingRegion(rctItem); - int x = rctItem.left + tileBorder; + pDC.SetTextForeground(wxSystemSettings::GetColour(IsSelected(nItem) ? + wxSYS_COLOUR_HIGHLIGHTTEXT : wxSYS_COLOUR_WINDOWTEXT)); - DrawTipMarker(pDC, rctItem, bItemHasTipText, x); - DrawItemDebugIDCode(pDC, nItem, rctItem, TRUE, x); - for (size_t i = size_t(0); i < tids.size(); ++i) - { - DrawTileImage(pDC, rctItem, true, x, tids[i]); - } + wxCoord x = rctItem.GetLeft() + tileBorder; - pDC.RestoreDC(-1); + DrawTipMarker(pDC, rctItem, bItemHasTipText, x); + DrawItemDebugIDCode(pDC, nItem, rctItem, TRUE, x); + for (size_t i = size_t(0); i < tids.size(); ++i) + { + DrawTileImage(pDC, rctItem, true, x, tids[i]); } - if (nAction & ODA_FOCUS) - pDC.DrawFocusRect(&rctItem); } ///////////////////////////////////////////////////////////////////////////// -void CTileBaseListBox2::DrawTileImage(CDC& pDC, CRect rctItem, BOOL bDrawIt, int& x, TileID tid) const +void CTileBaseListBox2::DrawTileImage(wxDC& pDC, wxRect rctItem, BOOL bDrawIt, wxCoord& x, TileID tid) const { if (tid == nullTid) return; // Nothing to do @@ -145,10 +126,7 @@ void CTileBaseListBox2::DrawTileImage(CDC& pDC, CRect rctItem, BOOL bDrawIt, int if (bDrawIt) { - if (tile.GetHeight() >= 255) - tile.BitBlt(pDC, x, rctItem.top + tileBorder);// Too large. Don't draw vertically centered - else - tile.BitBlt(pDC, x, (rctItem.Height() - tile.GetHeight()) / 2 + rctItem.top); + tile.BitBlt(pDC, CalcScrolledX(x), (rctItem.GetHeight() - tile.GetHeight()) / 2 + rctItem.GetTop()); } x += tile.GetWidth() + tileGap; } @@ -157,19 +135,20 @@ void CTileBaseListBox2::DrawTileImage(CDC& pDC, CRect rctItem, BOOL bDrawIt, int // Optionally draw debug code string for item. If bDrawIt is false, // x is advanced the size of the string anyway but nothing is rendered -void CTileBaseListBox2::DrawItemDebugIDCode(CDC& pDC, size_t nItem, CRect rctItem, BOOL bDrawIt, int& x) const +void CTileBaseListBox2::DrawItemDebugIDCode(wxDC& pDC, size_t nItem, wxRect rctItem, BOOL bDrawIt, wxCoord& x) const { if (m_bDisplayIDs) { CB::string str = OnGetItemDebugString(nItem); - CFont* prvFont = (CFont*)pDC.SelectObject(CFont::FromHandle(g_res.h8ss)); - int y = rctItem.top + rctItem.Height() / 2 - + pDC.SetFont(g_res.h8ssWx); + wxCoord y = rctItem.GetTop() + rctItem.GetHeight() / 2 - (g_res.tm8ss.tmHeight + g_res.tm8ss.tmExternalLeading) / 2; if (bDrawIt) - pDC.TextOut(x, y, str); - x += pDC.GetTextExtent(str).cx; - pDC.SelectObject(prvFont); + { + pDC.DrawText(str, CalcScrolledX(x), y); + } + x += pDC.GetTextExtent(str).x; } } @@ -179,36 +158,32 @@ void CTileBaseListBox2::SetupTipMarkerIfRequired() { if (m_bTipMarkItems) { - ASSERT(m_hWnd != NULL); - if (m_sizeTipMark.cx == 0) + wxASSERT(GetHandle()); + if (m_sizeTipMark.x == 0) { // Hasn't been initialized yet. m_strTipMark = CB::string::LoadString(IDS_TIP_LBOXITEM_MARKER); - CDC* pDC = GetDC(); + wxWindowDC pDC(this); - CFont* prvFont = (CFont*)pDC->SelectObject(CFont::FromHandle(g_res.h8ss)); - m_sizeTipMark.cx = pDC->GetTextExtent(m_strTipMark).cx; - m_sizeTipMark.cy = g_res.tm8ss.tmHeight + g_res.tm8ss.tmExternalLeading; - pDC->SelectObject(prvFont); - - ReleaseDC(pDC); + pDC.SetFont(g_res.h8ssWx); + m_sizeTipMark.x = pDC.GetTextExtent(m_strTipMark).x; + m_sizeTipMark.y = g_res.tm8ss.tmHeight + g_res.tm8ss.tmExternalLeading; } } } -void CTileBaseListBox2::DrawTipMarker(CDC& pDC, CRect rctItem, BOOL bVisible, int& x) const +void CTileBaseListBox2::DrawTipMarker(wxDC& pDC, wxRect rctItem, BOOL bVisible, int& x) const { if (m_bTipMarkItems) { - CFont* prvFont = (CFont*)pDC.SelectObject(CFont::FromHandle(g_res.h8ss)); + pDC.SetFont(g_res.h8ssWx); if (bVisible) // Draw only if visible. Else just move 'x' { - int y = rctItem.top + (rctItem.Height() - m_sizeTipMark.cy) / 2; - pDC.TextOut(x, y, m_strTipMark); + wxCoord y = rctItem.GetTop() + (rctItem.GetHeight() - m_sizeTipMark.y) / 2; + pDC.DrawText(m_strTipMark, CalcScrolledX(x), y); } - x += m_sizeTipMark.cx; - pDC.SelectObject(prvFont); + x += m_sizeTipMark.x; } } @@ -219,45 +194,38 @@ CB::string CTileBaseListBox2::OnGetItemDebugString(size_t nItem) const ///////////////////////////////////////////////////////////////////////////// -std::vector CTileBaseListBox2::GetTileRectsForItem(size_t nItem, +std::vector CTileBaseListBox2::GetTileRectsForItem(size_t nItem, const std::vector& tids) const { - ASSERT(!tids.empty() && tids[size_t(0)] != nullTid); + wxASSERT(!tids.empty() && tids[size_t(0)] != nullTid); - CRect rctItem; - GetItemRect(value_preserving_cast(nItem), &rctItem); + wxRect rctItem = GetItemRect(nItem); - int x = rctItem.left + tileBorder; // Set starting x position + wxCoord x = CalcScrolledX(rctItem.GetLeft()) + tileBorder; // Set starting x position // Need to account for possible markers and debug strings // rendered to left of tile images // only using DC for measurement, so const_cast safe - CDC& pDC = CheckedDeref(const_cast(this)->GetDC()); + wxWindowDC pDC(const_cast(this)); DrawTipMarker(pDC, rctItem, FALSE, x); DrawItemDebugIDCode(pDC, nItem, rctItem, FALSE, x); - const_cast(this)->ReleaseDC(&pDC); - std::vector retval(tids.size()); + std::vector retval(tids.size()); for (size_t i = size_t(0) ; i < tids.size() ; ++i) { - retval[i].SetRectEmpty(); - retval[i].top = rctItem.top; // Set the top & bottom values - retval[i].bottom = rctItem.bottom; - retval[i].left = x; + retval[i].SetTop(rctItem.GetTop()); // Set the top & bottom values + retval[i].SetBottom(rctItem.GetBottom()); + retval[i].SetLeft(x); DrawTileImage(pDC, rctItem, FALSE, x, tids[i]); - retval[i].right = x; + retval[i].SetRight(x); } return retval; } -int CTileBaseListBox2::OnCreate(LPCREATESTRUCT lpCreateStruct) +void CTileBaseListBox2::OnCreate(wxWindowCreateEvent& event) { - int retval = CGrafixListBox2::OnCreate(lpCreateStruct); - if (retval == 0) - { - SetupTipMarkerIfRequired(); - } - return retval; + event.Skip(); + SetupTipMarkerIfRequired(); } diff --git a/GShr/LBoxTileBase2.h b/GShr/LBoxTileBase2.h index e73baaa1..6640ea6e 100644 --- a/GShr/LBoxTileBase2.h +++ b/GShr/LBoxTileBase2.h @@ -1,7 +1,7 @@ // LBoxTileBase.h - class used to handle a variety of tile // oriented listbox functions // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -50,21 +50,21 @@ class CTileBaseListBox2 : public CGrafixListBox2 BOOL m_bTipMarkItems; CB::string m_strTipMark; - CSize m_sizeTipMark; + wxSize m_sizeTipMark; // Helpers... protected: - void DrawTileImage(CDC& pDC, CRect rctItem, BOOL bDrawIt, int& x, TileID tid) const; - void DrawItemDebugIDCode(CDC& pDC, size_t nItem, CRect rctItem, BOOL bDrawIt, int& x) const; + void DrawTileImage(wxDC& pDC, wxRect rctItem, BOOL bDrawIt, wxCoord& x, TileID tid) const; + void DrawItemDebugIDCode(wxDC& pDC, size_t nItem, wxRect rctItem, BOOL bDrawIt, wxCoord& x) const; void SetupTipMarkerIfRequired(); - void DrawTipMarker(CDC& pDC, CRect rctItem, BOOL bVisible, int& x) const; + void DrawTipMarker(wxDC& pDC, wxRect rctItem, BOOL bVisible, int& x) const; - CSize DoOnItemSize(size_t nItem, const std::vector& tids) const; - void DoOnDrawItem(CDC& pDC, size_t nItem, UINT nAction, UINT nState, CRect rctItem, + wxSize DoOnItemSize(size_t nItem, const std::vector& tids) const; + void DoOnDrawItem(wxDC& pDC, size_t nItem, wxRect rctItem, const std::vector& tids) const; - std::vector GetTileRectsForItem(size_t nItem, const std::vector& tids) const; + std::vector GetTileRectsForItem(size_t nItem, const std::vector& tids) const; // Overrides... public: @@ -78,10 +78,8 @@ class CTileBaseListBox2 : public CGrafixListBox2 virtual const void* OnGetItemDebugIDCode(size_t nItem) const /* override */ { return &MapIndexToItem(nItem); } virtual CB::string OnGetItemDebugString(size_t nItem) const /* override */; - //{{AFX_MSG(CTileBaseListBox) - afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() + void OnCreate(wxWindowCreateEvent& event); + wxDECLARE_EVENT_TABLE(); }; diff --git a/GShr/LBoxVHScrl.cpp b/GShr/LBoxVHScrl.cpp index 5d922b5a..0941c97e 100644 --- a/GShr/LBoxVHScrl.cpp +++ b/GShr/LBoxVHScrl.cpp @@ -1,6 +1,6 @@ // LBoxVHScrl.cpp // -// Copyright (c) 2024-2025 By William Su, All Rights Reserved. +// Copyright (c) 2024-2026 By William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -61,13 +61,24 @@ namespace CB std::vector VListBoxHScroll::GetSelections() const { std::vector retval; - retval.reserve(GetSelectedCount()); - unsigned long cookie; - for (int sel = GetFirstSelected(cookie) ; - sel != wxNOT_FOUND ; - sel = GetNextSelected(cookie)) + if (HasMultipleSelection()) { - retval.push_back(value_preserving_cast(sel)); + retval.reserve(GetSelectedCount()); + unsigned long cookie; + for (int sel = GetFirstSelected(cookie) ; + sel != wxNOT_FOUND ; + sel = GetNextSelected(cookie)) + { + retval.push_back(value_preserving_cast(sel)); + } + } + else + { + int sel = GetSelection(); + if (sel != wxNOT_FOUND) + { + retval.push_back(value_preserving_cast(sel)); + } } return retval; } diff --git a/GShr/LibMfc.cpp b/GShr/LibMfc.cpp index 55975a4c..b0205d0b 100644 --- a/GShr/LibMfc.cpp +++ b/GShr/LibMfc.cpp @@ -1,6 +1,6 @@ // LibMfc.cpp - Miscellaneous MFC Support Functions // -// Copyright (c) 1994-2025 By Dale L. Larson & William Su, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -785,7 +785,8 @@ CB::wxNativeContainerWindowMixin::operator const wxNativeContainerWindow*() cons // N.B.: this is a dirty hack wxNativeContainerWindowMixin* ncThis = const_cast(this); - wxWindow& rThis = const_cast(*ncThis); + wxWindow& rThis = *ncThis; + CPP20_TRACE("{}({}:{}) === {}:{}\n", typeid(*mfcWnd).name(), (const void*)&*mfcWnd, (void*)mfcWnd->m_hWnd, rThis, WXHANDLE(rThis.GetHWND())); // fill in wx children list for (CWnd* mfcChild = mfcWnd->GetWindow(GW_CHILD) ; @@ -1069,12 +1070,54 @@ void CB::ToolTip::SetMaxWidth(int width) maxWidth = width; } +void CB::ToolTip::TrackActivate(wxWindow& wnd, bool b) +{ + wxASSERT(!b || (!IsRunning() && state == sNoTool)); + auto it = std::find_if(toolInfos.begin(), toolInfos.end(), + [&wnd](const ToolInfo& ti) + { + return &ti.wnd.get() == &wnd && + !ti.rect; + }); + if (it == toolInfos.end() && !b) + { + return; + } + wxASSERT(it != toolInfos.end()); + + it->flags = Flags(it->flags & (~TRACK_ON) | (b ? TRACK_ON : 0)); + + // show/hide the tooltip immediately + if (b && !tipWindow) + { + wxASSERT(tipTool == toolInfos.end()); + tipTool = it; + state = sDisplayWait; + Notify(); + } + else if (!b && tipWindow) + { + CloseTipWindow(); + } +} + +void CB::ToolTip::TrackPosition(wxPoint screenPt) +{ + wxASSERT(tipTool != toolInfos.end() && + (tipTool->flags & Flags(TRACK_ON))); + + if (tipWindow) + { + tipWindow->SetPosition(screenPt); + } +} + void CB::ToolTip::Add(wxWindow& wnd, std::optional&& rect, wxString&& tip, Flags flags) { - wxASSERT(!(flags & TRACK) || !"TRACK not implemented"); // center shouldn't move, track should move wxASSERT((flags & (CENTER | TRACK)) != (CENTER | TRACK)); + wxASSERT(!rect || !rect->IsEmpty()); auto it = std::find_if(toolInfos.begin(), toolInfos.end(), [&wnd](const ToolInfo& ti) @@ -1089,6 +1132,9 @@ void CB::ToolTip::Add(wxWindow& wnd, std::optional&& rect, if (it == toolInfos.end()) { wnd.Bind(wxEVT_MOTION, &ToolTip::OnMouseMove, this); + /* leaving the window may need to be handled + as a move to a location outside the tool */ + wnd.Bind(wxEVT_LEAVE_WINDOW, &ToolTip::OnMouseMove, this); } toolInfos.emplace_back(wnd, std::move(rect), std::move(tip), flags); Enable(enabled); @@ -1102,11 +1148,16 @@ void CB::ToolTip::Delete(wxWindow& wnd, std::optional rect) return &ti.wnd.get() == &wnd && ti.rect == rect; }); - wxASSERT(it != toolInfos.end()); + if (it == toolInfos.end()) + { + return; + } if (it == tipTool) { CloseTipWindow(); + Stop(); + state = sNoTool; } toolInfos.erase(it); @@ -1119,6 +1170,7 @@ void CB::ToolTip::Delete(wxWindow& wnd, std::optional rect) if (it == toolInfos.end()) { wnd.Unbind(wxEVT_MOTION, &ToolTip::OnMouseMove, this); + wnd.Unbind(wxEVT_LEAVE_WINDOW, &ToolTip::OnMouseMove, this); } } @@ -1140,9 +1192,8 @@ void CB::ToolTip::Notify() { screenRect = tipTool->wnd.get().GetScreenRect(); } - tipWindow = new wxTipWindow(&tipTool->wnd.get(), - tipTool->tip, maxWidth, - &tipWindow, + tipWindow = wxTipWindow::New(&tipTool->wnd.get(), + tipTool->tip, maxWidth != -1 ? maxWidth : std::numeric_limits::max(), &screenRect); if (tipTool->flags & CENTER) { @@ -1150,7 +1201,7 @@ void CB::ToolTip::Notify() wxCoord left = center - tipWindow->GetRect().GetWidth() / 2; tipWindow->Move(left, screenRect.GetBottom() + 1); } - Start(autopopMs); + StartOnce(autopopMs); state = sDisplay; break; } @@ -1186,6 +1237,12 @@ void CB::ToolTip::OnMouseMove(wxMouseEvent& event) return &ti.wnd.get() == &wnd && (!ti.rect || ti.rect->Contains(pt)); }); + if (it != toolInfos.end() && + !it->rect && + event.GetEventType() == wxEVT_LEAVE_WINDOW) + { + it = toolInfos.end(); + } if (it != toolInfos.end()) { @@ -1307,8 +1364,84 @@ namespace CB #if defined(GPLAY) switch (id) { + case ID_ACT_AUTOSTACK_DECK: + return XRCID("ID_ACT_AUTOSTACK_DECK"); + case ID_ACT_LOCK_SUSPEND: + return XRCID("ID_ACT_LOCK_SUSPEND"); + case ID_ACT_LOCKOBJECT: + return XRCID("ID_ACT_LOCKOBJECT"); + case ID_ACT_PLOTDISCARD: + return XRCID("ID_ACT_PLOTDISCARD"); + case ID_ACT_PLOTDONE: + return XRCID("ID_ACT_PLOTDONE"); + case ID_ACT_RELEASE_OWNERSHIP: + return XRCID("ID_ACT_RELEASE_OWNERSHIP"); + case ID_ACT_ROTATE_0: + return XRCID("ID_ACT_ROTATE_0"); + case ID_ACT_ROTATE_30: + return XRCID("ID_ACT_ROTATE_30"); + case ID_ACT_ROTATE_45: + return XRCID("ID_ACT_ROTATE_45"); + case ID_ACT_ROTATE_60: + return XRCID("ID_ACT_ROTATE_60"); + case ID_ACT_ROTATE_90: + return XRCID("ID_ACT_ROTATE_90"); + case ID_ACT_ROTATE_120: + return XRCID("ID_ACT_ROTATE_120"); + case ID_ACT_ROTATE_135: + return XRCID("ID_ACT_ROTATE_135"); + case ID_ACT_ROTATE_150: + return XRCID("ID_ACT_ROTATE_150"); + case ID_ACT_ROTATE_180: + return XRCID("ID_ACT_ROTATE_180"); + case ID_ACT_ROTATE_210: + return XRCID("ID_ACT_ROTATE_210"); + case ID_ACT_ROTATE_225: + return XRCID("ID_ACT_ROTATE_225"); + case ID_ACT_ROTATE_240: + return XRCID("ID_ACT_ROTATE_240"); + case ID_ACT_ROTATE_270: + return XRCID("ID_ACT_ROTATE_270"); + case ID_ACT_ROTATE_300: + return XRCID("ID_ACT_ROTATE_300"); + case ID_ACT_ROTATE_315: + return XRCID("ID_ACT_ROTATE_315"); + case ID_ACT_ROTATE_330: + return XRCID("ID_ACT_ROTATE_330"); + case ID_ACT_ROTATEGROUP: + return XRCID("ID_ACT_ROTATEGROUP"); + case ID_ACT_ROTATEREL: + return XRCID("ID_ACT_ROTATEREL"); + case ID_ACT_SET_OWNER: + return XRCID("ID_ACT_SET_OWNER"); + case ID_ACT_SHUFFLE_SELECTED: + return XRCID("ID_ACT_SHUFFLE_SELECTED"); + case ID_ACT_STACK: + return XRCID("ID_ACT_STACK"); + case ID_ACT_TAKE_OWNERSHIP: + return XRCID("ID_ACT_TAKE_OWNERSHIP"); + case ID_ACT_TOBACK: + return XRCID("ID_ACT_TOBACK"); + case ID_ACT_TOFRONT: + return XRCID("ID_ACT_TOFRONT"); + case ID_ACT_TURNOVER: + return XRCID("ID_ACT_TURNOVER"); + case ID_ACT_TURNOVER_PREV: + return XRCID("ID_ACT_TURNOVER_PREV"); + case ID_ACT_TURNOVER_RANDOM: + return XRCID("ID_ACT_TURNOVER_RANDOM"); + case ID_ACT_TURNOVER_SELECT: + return XRCID("ID_ACT_TURNOVER_SELECT"); + case ID_EDIT_BRD2FILE: + return XRCID("ID_EDIT_BRD2FILE"); case ID_EDIT_BRDPROP: return XRCID("ID_EDIT_BRDPROP"); + case ID_EDIT_ELEMENT_TEXT: + return XRCID("ID_EDIT_ELEMENT_TEXT"); + case ID_EDIT_SELALLMARKERS: + return XRCID("ID_EDIT_SELALLMARKERS"); + case ID_INDICATOR_CELLNUM: + return XRCID("ID_INDICATOR_CELLNUM"); case ID_PPROJITEM_DELETE: return XRCID("ID_PPROJITEM_DELETE"); case ID_PPROJITEM_EDIT: @@ -1317,6 +1450,30 @@ namespace CB return XRCID("ID_PPROJITEM_PROPERTIES"); case ID_PPROJITEM_VIEW: return XRCID("ID_PPROJITEM_VIEW"); + case ID_PTOOL_LINE: + return XRCID("ID_PTOOL_LINE"); + case ID_PTOOL_PLOTMOVE: + return XRCID("ID_PTOOL_PLOTMOVE"); + case ID_PTOOL_SELECT: + return XRCID("ID_PTOOL_SELECT"); + case ID_PTOOL_TEXTBOX: + return XRCID("ID_PTOOL_TEXTBOX"); + case ID_VIEW_BOARD_ROTATE180: + return XRCID("ID_VIEW_BOARD_ROTATE180"); + case ID_VIEW_DRAW_IND_ON_TOP: + return XRCID("ID_VIEW_DRAW_IND_ON_TOP"); + case ID_VIEW_FULLSCALEBRD: + return XRCID("ID_VIEW_FULLSCALEBRD"); + case ID_VIEW_HALFSCALEBRD: + return XRCID("ID_VIEW_HALFSCALEBRD"); + case ID_VIEW_PIECES: + return XRCID("ID_VIEW_PIECES"); + case ID_VIEW_SMALLSCALEBRD: + return XRCID("ID_VIEW_SMALLSCALEBRD"); + case ID_VIEW_SNAPGRID: + return XRCID("ID_VIEW_SNAPGRID"); + case ID_VIEW_TOGGLESCALE: + return XRCID("ID_VIEW_TOGGLESCALE"); default: return wxID_NONE; } @@ -1473,6 +1630,7 @@ BOOL CB::RelayOnCmdMsg(wxEvtHandler& dest, so approximate this way */ class CDummyCmdUI : public CCmdUI { + void Enable(BOOL) override {} void SetCheck(int nCheck = 1) override {} // 0, 1 or 2 (indeterminate) }; CDummyCmdUI dummy; @@ -1485,6 +1643,7 @@ BOOL CB::RelayOnCmdMsg(wxEvtHandler& dest, { CCmdUI& pCmdUI = CheckedDeref(static_cast(pExtra)); wxUpdateUIEvent event(CB::ToWxID(nID)); + event.Allow3rdState(); #if !defined(GPLAY) CColorCmdUI* colorCmdUI = dynamic_cast(&pCmdUI); if (colorCmdUI) @@ -1509,7 +1668,20 @@ BOOL CB::RelayOnCmdMsg(wxEvtHandler& dest, } if (event.GetSetChecked()) { - pCmdUI.SetCheck(event.GetChecked()); + switch (event.Get3StateValue()) + { + case wxCHK_UNCHECKED: + pCmdUI.SetCheck(0); + break; + case wxCHK_CHECKED: + pCmdUI.SetCheck(1); + break; + case wxCHK_UNDETERMINED: + pCmdUI.SetCheck(2); + break; + default: + wxASSERT(!"impossible value"); + } } if (event.GetSetText()) { @@ -1537,6 +1709,10 @@ namespace CB { XRCID("ID_TOOLS_ROT180"), ID_TOOLS_ROT180 }, { XRCID("ID_TOOLS_ROT270"), ID_TOOLS_ROT270 }, #else + { XRCID("ID_ACT_TURNOVER"), ID_ACT_TURNOVER }, + { XRCID("ID_ACT_TURNOVER_PREV"), ID_ACT_TURNOVER_PREV }, + { XRCID("ID_ACT_TURNOVER_RANDOM"), ID_ACT_TURNOVER_RANDOM }, + { XRCID("ID_ACT_TURNOVER_SELECT"), ID_ACT_TURNOVER_SELECT }, { XRCID("ID_EDIT_CREATE_GEOMORPHIC"), ID_EDIT_CREATE_GEOMORPHIC }, { XRCID("ID_EDIT_CREATETRAY"), ID_EDIT_CREATETRAY }, { XRCID("ID_EDIT_SELECTBOARDS"), ID_EDIT_SELECTBOARDS }, diff --git a/GShr/ResTbl.cpp b/GShr/ResTbl.cpp index e9ca7843..ef3c94d3 100644 --- a/GShr/ResTbl.cpp +++ b/GShr/ResTbl.cpp @@ -85,7 +85,7 @@ void ResourceTable::LoadCursors(HINSTANCE hInst) hcrColorChange = LoadCursor(hInst, MAKEINTRESOURCE(IDC_COLORCHANGE)); hcrColorChangeWx.SetHCURSOR(reinterpret_cast(LoadCursor(hInst, MAKEINTRESOURCE(IDC_COLORCHANGE)))); #else - hcrCompMoveActive = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CMOVMODE)); + hcrCompMoveActive.SetHCURSOR(reinterpret_cast(LoadCursor(hInst, MAKEINTRESOURCE(IDC_CMOVMODE)))); #endif } @@ -106,8 +106,6 @@ void ResourceTable::FreeCursors(void) DestroyCursor(hcrPencil); DestroyCursor(hcrBrush); DestroyCursor(hcrColorChange); -#else - DestroyCursor(hcrCompMoveActive); #endif } diff --git a/GShr/ResTbl.h b/GShr/ResTbl.h index 74df90ce..b2de3fc6 100644 --- a/GShr/ResTbl.h +++ b/GShr/ResTbl.h @@ -63,7 +63,7 @@ struct ResourceTable HCURSOR hcrColorChange; wxCursor hcrColorChangeWx; #else - HCURSOR hcrCompMoveActive; + wxCursor hcrCompMoveActive; #endif #ifndef GPLAY // ======== Brushes ========= // diff --git a/GShr/Versions.h b/GShr/Versions.h index 148e8823..0e258eab 100644 --- a/GShr/Versions.h +++ b/GShr/Versions.h @@ -865,7 +865,8 @@ inline CArchive& operator>>(CArchive& ar, T& v) return ar; } -inline CArchive& operator<<(CArchive& ar, const std::vector& v) +template +CArchive& operator<<(CArchive& ar, const std::vector& v) { CB::WriteCount(ar, v.size()); for (size_t i = size_t(0) ; i < v.size() ; ++i) @@ -875,7 +876,8 @@ inline CArchive& operator<<(CArchive& ar, const std::vector& v) return ar; } -inline CArchive& operator>>(CArchive& ar, std::vector& v) +template +CArchive& operator>>(CArchive& ar, std::vector& v) { size_t size = CB::ReadCount(ar); v.resize(size); diff --git a/GShr/WinState.cpp b/GShr/WinState.cpp index 123e66c6..55eba22a 100644 --- a/GShr/WinState.cpp +++ b/GShr/WinState.cpp @@ -31,6 +31,8 @@ #include "GamDoc.h" #endif +wxDEFINE_EVENT(WM_WINSTATE_WX, WinStateEvent); + /////////////////////////////////////////////////////////////////////////// // Returns FALSE if no frame restoration data is supplied by frames. @@ -172,6 +174,7 @@ BOOL CWinStateManager::RestoreWindowState(CWnd* pWnd, CWinStateElement& pWse) { CMemFile file(pWse.m_pWinStateBfr, value_preserving_cast(pWse.m_pWinStateBfr.GetSize())); CArchive ar(&file, CArchive::load); + SetFileFeaturesGuard setFileFeaturesGuard(ar, fileFeatures); bOK = (BOOL)pWnd->SendMessage(WM_WINSTATE, (WPARAM)&ar, 1); ar.Close(); file.Detach(); @@ -260,6 +263,7 @@ void CWinStateManager::Serialize(CArchive& ar) if (dwCount == size_t(0)) return; fileVersion = CB::GetVersion(ar); + fileFeatures = CB::GetFeatures(ar); m_pList = MakeOwner(); while (dwCount--) { diff --git a/GShr/WinState.h b/GShr/WinState.h index 57006fcd..a90079c4 100644 --- a/GShr/WinState.h +++ b/GShr/WinState.h @@ -1,6 +1,6 @@ // WinState.h - classes used to manage window state. // -// Copyright (c) 1994-2020 By Dale L. Larson, All Rights Reserved. +// Copyright (c) 1994-2026 By Dale L. Larson & William Su, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -26,6 +26,7 @@ #define _WINSTATE_H #include "Board.h" +#include "Versions.h" /////////////////////////////////////////////////////////////////////// @@ -34,6 +35,30 @@ // the frame's *contents* to it's current visual state. #define WM_WINSTATE (WM_USER + 300) // WPARAM = CArchive*, LPARAM = 0 if save, 1 if restore +class WinStateEvent : public wxEvent +{ +public: + WinStateEvent(CArchive& ar, bool restore); + + CArchive& GetArchive() const { return ar; } + + wxEvent* Clone() const override { return new WinStateEvent(*this); } + +private: + CArchive& ar; +}; +wxDECLARE_EVENT(WM_WINSTATE_WX, WinStateEvent); +inline WinStateEvent::WinStateEvent(CArchive& a, bool restore) : + wxEvent(wxID_ANY, WM_WINSTATE_WX), + ar(a) +{ + WXUNUSED_UNLESS_DEBUG(restore); + wxASSERT(bool(ar.IsLoading()) == restore); +} +typedef void (wxEvtHandler::* WinStateEventFunction)(WinStateEvent&); +#define WinStateEventHandler(func) wxEVENT_HANDLER_CAST(WinStateEventFunction, func) +#define EVT_WINSTATE(func) \ + wx__DECLARE_EVT0(WM_WINSTATE_WX, WinStateEventHandler(func)) /////////////////////////////////////////////////////////////////////// // Helper class for working with the Windows WINDOWPLACEMENT structure @@ -141,6 +166,7 @@ class CWinStateManager protected: CDocument* m_pDoc; int fileVersion = INT_MAX; + Features fileFeatures; typedef std::list> CWinStateList; OwnerOrNullPtr m_pList; // Win state element list }; diff --git a/build-all-configs.bat b/build-all-configs.bat index 5e4ebdee..ecb57422 100644 --- a/build-all-configs.bat +++ b/build-all-configs.bat @@ -7,7 +7,11 @@ rem execute in bat's directory pushd %~dp0 call %VSROOTDIR%"\2022\Community\VC\Auxiliary\Build\vcvars64.bat" -if errorlevel 1 goto fail_vc_x64 +if errorlevel 1 ( + rem MSVS 2026 + call %VSROOTDIR%"\18\Community\VC\Auxiliary\Build\vcvars64.bat" + if errorlevel 1 goto fail_vc_x64 +) echo on cmake -G Ninja -B out/build/x64-Debug -DCMAKE_BUILD_TYPE=Debug @@ -25,7 +29,11 @@ if errorlevel 1 cmake --build out/build/x64-Release if errorlevel 1 goto fail_build call %VSROOTDIR%"\2022\Community\VC\Auxiliary\Build\vcvars32.bat" -if errorlevel 1 goto fail_vc_x86 +if errorlevel 1 ( + rem MSVS 2026 + call %VSROOTDIR%"\18\Community\VC\Auxiliary\Build\vcvars32.bat" + if errorlevel 1 goto fail_vc_x86 +) echo on cmake -G Ninja -B out/build/x86-Debug -DCMAKE_BUILD_TYPE=Debug diff --git a/deps/wxWidgets b/deps/wxWidgets index 0396c266..d05c5c1d 160000 --- a/deps/wxWidgets +++ b/deps/wxWidgets @@ -1 +1 @@ -Subproject commit 0396c2661f434176c5198f2cac84ef91e5f1b540 +Subproject commit d05c5c1d3e55542e63711778193175c099774f60