void SkeinWindow::OnContextMenu(CWnd* pWnd, CPoint point) { // No menu if currently editing if (m_edit.IsWindowVisible()) return; // No menu if running the game bool gameRunning = GetParentFrame()->SendMessage(WM_GAMERUNNING) != 0; bool gameWaiting = GetParentFrame()->SendMessage(WM_GAMEWAITING) != 0; if (gameRunning && !gameWaiting) return; // Find the node under the mouse, if any CPoint cp(point); ScreenToClient(&cp); Skein::Node* node = NodeAtPoint(cp); if (node == NULL) return; // Get the context menu CMenu popup; popup.LoadMenu(IDR_SKEIN); CMenu* menu = popup.GetSubMenu(0); // Update the state of the context menu items if (node->GetParent() == NULL) { menu->RemoveMenu(ID_SKEIN_EDIT,MF_BYCOMMAND); menu->RemoveMenu(ID_SKEIN_ADD_LABEL,MF_BYCOMMAND); menu->RemoveMenu(ID_SKEIN_EDIT_LABEL,MF_BYCOMMAND); menu->RemoveMenu(ID_SKEIN_INSERT_KNOT,MF_BYCOMMAND); menu->RemoveMenu(ID_SKEIN_DELETE,MF_BYCOMMAND); menu->RemoveMenu(ID_SKEIN_DELETE_BELOW,MF_BYCOMMAND); menu->RemoveMenu(ID_SKEIN_DELETE_THREAD,MF_BYCOMMAND); menu->RemoveMenu(ID_SKEIN_LOCK,MF_BYCOMMAND|MF_GRAYED); menu->RemoveMenu(ID_SKEIN_UNLOCK,MF_BYCOMMAND|MF_GRAYED); menu->RemoveMenu(ID_SKEIN_LOCK_THREAD,MF_BYCOMMAND|MF_GRAYED); menu->RemoveMenu(ID_SKEIN_UNLOCK_THREAD,MF_BYCOMMAND|MF_GRAYED); } else { if (gameRunning && m_skein->InCurrentThread(node)) { menu->EnableMenuItem(ID_SKEIN_DELETE,MF_BYCOMMAND|MF_GRAYED); menu->EnableMenuItem(ID_SKEIN_DELETE_BELOW,MF_BYCOMMAND|MF_GRAYED); } if (gameRunning && m_skein->InCurrentThread(m_skein->GetThreadTop(node))) menu->EnableMenuItem(ID_SKEIN_DELETE_THREAD,MF_BYCOMMAND|MF_GRAYED); if (node->GetLabel().IsEmpty()) menu->RemoveMenu(ID_SKEIN_EDIT_LABEL,MF_BYCOMMAND); else menu->RemoveMenu(ID_SKEIN_ADD_LABEL,MF_BYCOMMAND); } if (node->GetTemporary()) { menu->RemoveMenu(ID_SKEIN_UNLOCK,MF_BYCOMMAND|MF_GRAYED); menu->RemoveMenu(ID_SKEIN_UNLOCK_THREAD,MF_BYCOMMAND|MF_GRAYED); } else { menu->RemoveMenu(ID_SKEIN_LOCK,MF_BYCOMMAND|MF_GRAYED); menu->RemoveMenu(ID_SKEIN_LOCK_THREAD,MF_BYCOMMAND|MF_GRAYED); } // Show the context menu int cmd = menu->TrackPopupMenuEx(TPM_LEFTALIGN|TPM_TOPALIGN|TPM_NONOTIFY|TPM_RETURNCMD, point.x,point.y,GetParentFrame(),NULL); // Act on the context menu choice switch (cmd) { case ID_SKEIN_PLAY: GetParentFrame()->SendMessage(WM_PLAYSKEIN,(WPARAM)node); break; case ID_SKEIN_EDIT: StartEdit(node,false); break; case ID_SKEIN_ADD_LABEL: case ID_SKEIN_EDIT_LABEL: // Make sure that the label background is visible Invalidate(); StartEdit(node,true); break; case ID_SKEIN_TRANSCRIPT: GetParentFrame()->SendMessage(WM_SHOWTRANSCRIPT,(WPARAM)node,(LPARAM)GetSafeHwnd()); break; case ID_SKEIN_LOCK: m_skein->Lock(node); break; case ID_SKEIN_UNLOCK: m_skein->Unlock(node); break; case ID_SKEIN_LOCK_THREAD: m_skein->Lock(m_skein->GetThreadBottom(node)); break; case ID_SKEIN_UNLOCK_THREAD: m_skein->Unlock(m_skein->GetThreadTop(node)); break; case ID_SKEIN_NEW_THREAD: { Skein::Node* newNode = m_skein->AddNew(node); // Force a repaint so that the new node is drawn and recorded Invalidate(); UpdateWindow(); StartEdit(newNode,false); } break; case ID_SKEIN_INSERT_KNOT: { Skein::Node* newNode = m_skein->AddNewParent(node); Invalidate(); UpdateWindow(); StartEdit(newNode,false); } break; case ID_SKEIN_DELETE: if (CanRemove(node)) m_skein->RemoveSingle(node); break; case ID_SKEIN_DELETE_BELOW: if (CanRemove(node)) m_skein->RemoveAll(node); break; case ID_SKEIN_DELETE_THREAD: { Skein::Node* topNode = m_skein->GetThreadTop(node); if (CanRemove(topNode)) m_skein->RemoveAll(topNode); } break; case ID_SKEIN_SAVE_TRANSCRIPT: { SimpleFileDialog dialog(FALSE,"txt",NULL,OFN_HIDEREADONLY|OFN_ENABLESIZING, "Text Files (*.txt)|*.txt|All Files (*.*)|*.*||",this); dialog.m_ofn.lpstrTitle = "Save the transcript up to this knot"; if (dialog.DoModal() == IDOK) m_skein->SaveTranscript(node,dialog.GetPathName()); } break; case 0: // Make sure this window still has the focus SetFocus(); break; } }