/* ** AreaEditor - a program for editing SMAUG and ROM area files. ** Author: Nick Gammon ** http://www.gammon.com.au/ ** See Copyright Notice at the end of AreaEditor.h */ // AreaView.cpp : implementation file // #include "stdafx.h" #include "AreaEditor.h" #include "AreaEditorDoc.h" #include "AreaView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define SUMMARY_PAGE 0 ///////////////////////////////////////////////////////////////////////////// // CAreaView IMPLEMENT_DYNCREATE(CAreaView, CFormView) CAreaView::CAreaView() : CFormView(CAreaView::IDD) { //{{AFX_DATA_INIT(CAreaView) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_area = NULL; m_bEditingText = false; m_pLHview = NULL; } CAreaView::~CAreaView() { // Delete the memory space for the C++ dialog object. The actual dialog // (or page) will be destroyed when tab control is destroyed because it // is the child window of the tab control (see code in CreatePages()). for (int i = 0; i < m_DlgArray.GetSize(); i++) delete m_DlgArray[i]; } void CAreaView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAreaView) DDX_Control(pDX, IDC_AREA_TABS, m_ctlTabControl); //}}AFX_DATA_MAP // send update to child pane if (pDX->m_bSaveAndValidate) { int sel_index = m_ctlTabControl.GetCurSel(); if (sel_index != -1) { CDialog * dlg = m_DlgArray[sel_index]->m_pDlg; if (!dlg->UpdateData (TRUE)) { // *post* a message putting the focus back on the naughty control PostMessage (WM_SETFOCUS, 0, 0); pDX->Fail(); // bad update - fail this one } } } // end of saving and validating } BEGIN_MESSAGE_MAP(CAreaView, CFormView) //{{AFX_MSG_MAP(CAreaView) ON_NOTIFY(TCN_SELCHANGE, IDC_AREA_TABS, OnSelchangeAreaTabs) ON_NOTIFY(TCN_SELCHANGING, IDC_AREA_TABS, OnSelchangingAreaTabs) ON_WM_SIZE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CAreaView diagnostics #ifdef _DEBUG void CAreaView::AssertValid() const { CFormView::AssertValid(); } void CAreaView::Dump(CDumpContext& dc) const { CFormView::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CAreaView message handlers void CAreaView::OnSelchangeAreaTabs(NMHDR* pNMHDR, LRESULT* pResult) { // Call GetCurSel() will return the index of the page that is newly // selected. This page will be visible soon. int sel_index = m_ctlTabControl.GetCurSel(); if (sel_index == -1) return; m_pDoc->m_iCurrentAreaTab = sel_index; if (!m_DlgArray[sel_index]->m_bCreated) { VERIFY(m_DlgArray[sel_index]->m_pDlg->Create(m_DlgArray[sel_index]->m_DlgID, this)); m_DlgArray[sel_index]->m_bCreated = true; } // Get the rectangle size of the tab control so we know the position // and size of the page that will be shown. RECT rc; m_ctlTabControl.GetItemRect (sel_index, &rc); m_DlgArray[sel_index]->m_pDlg->SetWindowPos ( NULL, 5, rc.bottom + 5, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE); CDialog * dlg = m_DlgArray[sel_index]->m_pDlg; if (dlg) dlg->UpdateData (FALSE); // force reload of contents // *pResult = TRUE; // no return value according to online documentation } // -------------------------------------------------------------------------- // CMobileView::OnTabSelChanging // // This function will hide the currently visible page in the tab control // (CTabCtrl) so the newly selected page can be shown in OnTabSelChange(). // -------------------------------------------------------------------------- void CAreaView::OnSelchangingAreaTabs(NMHDR* pNMHDR, LRESULT* pResult) { *pResult = FALSE; // return FALSE to allow seletion to change // Call GetCurSel() here will return the index of the page that // will be hidden soon. This is NOT the newly selected page when // OnTabSelChange() is called. int sel_index = m_ctlTabControl.GetCurSel(); if (sel_index == -1) return; CDialog * dlg = m_DlgArray[sel_index]->m_pDlg; if (dlg->UpdateData (TRUE)) dlg->ShowWindow(SW_HIDE); // good update - hide window else *pResult = TRUE; // bad update - cancel pane change } void CAreaView::OnSize(UINT nType, int cx, int cy) { CFormView::OnSize(nType, cx, cy); if (m_ctlTabControl.m_hWnd) { m_ctlTabControl.MoveWindow(0, 0, cx, cy); int sel_index = m_ctlTabControl.GetCurSel(); if (sel_index != -1) { // Get the rectangle size of the tab control so we know the position // and size of the page that will be shown. RECT rc; m_ctlTabControl.GetItemRect (sel_index, &rc); m_DlgArray[sel_index]->m_pDlg->SetWindowPos ( NULL, 5, rc.bottom + 5, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOACTIVATE); RECT rcclient; m_DlgArray[sel_index]->m_pDlg->GetClientRect (&rcclient); SetScrollSizes (MM_TEXT, CSize (rcclient.right, rcclient.bottom + rc.bottom + 5)); } } } void CAreaView::ShowPages (CAreaEditorDoc * pDoc) { m_pDoc = pDoc; m_ctlTabControl.SetCurSel (m_pDoc->m_iCurrentAreaTab); OnSelchangeAreaTabs(NULL, NULL); } // -------------------------------------------------------------------------- // CMobileView::HandleKeyDownMsg // // This functin will handle the following keydown messages: // // CTRL+TAB - used to activate the tab after the current selected tab // SHIFT+CTRL+TAB - used to activate the tab before the current selected tab // ENTER - OnOK() is called to dismiss the current selected tab // ESCAPE - OnCancel() is called to dismiss the current selected tab // // Keystrokes messages are different from the mouse messages. The former // will be sent to the window that has the input focus. However, the // latter will be sent to the window in which the mouse is clicked on except in // the case when SetCapture() is called. // // When those keys are pressed, the edit control inside the dialog box (or // page) will have the input focus. So, all keystrokes messages will be // routed to the parent window i.e. the dialog box. When dialog box receives // the keystrokes messages, it will handle some of them (such as CTRL+TAB, // TAB, arrow keys, etc.) and then forward unhandled ones to the edit control. // Because of this, we need a way to trap those keystrokes messages before // it gets routed to the dialog box. The PreTranslateMessage() function // in your CWinApp-derived class would be a good place for this. // // In the overriden CWinApp::PreTranslateMessage() function, all WM_KEYDOWN // messages will be passed to the view window first. So we have a chance // to handle the keystrokes messages that we are interested in. // NOTE: We can't intercept those keydown messages in PreTranslateMessage() // of either CView or CMainFrame class because they are being handled by // the dialog box (or page) before they get routed to the view or frame // window. Refer to the code in CWnd::WalkPreTranslateTree() in wincore.cpp // file. CWnd::WalkPreTranslateTree() is called in thrdcore.cpp file. // // This fucntion will return TRUE if those keystroke messages are processed; // FALSE otherwise. // -------------------------------------------------------------------------- BOOL CAreaView::HandleKeyDownMsg(MSG* pMsg) { // Was the CTRL key pressed? If not, we don't handle this keydown // message here. if (pMsg->wParam == VK_TAB && GetKeyState(VK_CONTROL) < 0) { // Was the SHIFT key pressed? If it was pressed, then we need // to activate the tab before the current selected tab. // Otherwise, the tab after the current selected tab will be // activated. BOOL shift_down = GetKeyState(VK_SHIFT) < 0; int old_sel = m_ctlTabControl.GetCurSel(); int num = m_ctlTabControl.GetItemCount() ; int new_sel = shift_down ? (old_sel + (num -1)) % num : (old_sel + 1) % num; // Okay, here is the trick... Simulate a mouse click message // to fool tab control that one of its tab is selected. RECT r; m_ctlTabControl.GetItemRect(new_sel, &r); m_ctlTabControl.SendMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(r.left, r.top)); return TRUE; } // if we are editing the description, don't throw away return and escape if (m_bEditingText) return FALSE; // a child edit control with the focus will be given the return key TCHAR szClass[10]; CWnd* pWndFocus; if ((pMsg->wParam == VK_RETURN) && ((pWndFocus = GetFocus()) != NULL) && IsChild(pWndFocus) && (pWndFocus->GetStyle() & ES_WANTRETURN) && GetClassName(pWndFocus->m_hWnd, szClass, 10) && (_tcsicmp(szClass, _T("EDIT")) == 0)) return FALSE; // Trapping the ENTER and ESCAPE keys here so the current active page won't be // dismissed. In MFC, ENTER and ESCAPE keys will be routed to CDialog::OnOK() and // CDialog::OnCancel() functions that will destroy the current active dialog (or // the page). if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) return TRUE; // Unhandled keydown messages. return FALSE; } #include "AreaNameView.h" #include "AreaRangesView.h" #include "AreaVnumsView.h" #include "FlagsListPage.h" #include "AreaClimateView.h" #include "AreaNeighbourView.h" #define AddPageHelper(dlg, name, dlgclass, dlgIDC) \ page = new CTabPage; \ m_DlgArray.Add(page); \ dlgclass * dlg; \ dlg = new dlgclass; \ page->m_pDlg = dlg; \ ASSERT(page->m_pDlg); \ page->m_name = name; \ page->m_DlgID = dlgIDC; #define AddPage(dlg, name, dlgclass, dlgIDC) \ AddPageHelper (dlg, name, dlgclass, dlgIDC); \ dlg->m_area = m_area; #define AddFlag(dlg, name, flag, flagarray) \ AddPageHelper (dlg, name, CFlagsListPage, IDD_SELECT_FROM_LIST); \ dlg->m_pFlags = &m_area->flag; \ dlg->m_pFlagsArray = &flagarray; \ dlg->m_pDoc = pDoc; void CAreaView::CreatePages() { CAreaEditorDoc* pDoc = (CAreaEditorDoc* ) GetDocument(); ASSERT_VALID(pDoc); CTabPage * page; // Add all pages to the dialog array. // Warning - if you move the summary page, update SUMMARY_PAGE define AddPage (namedlg, "Name", CAreaNameView, IDD_AREA_NAME); AddPage (vnumsdlg, "Vnums", CAreaVnumsView, IDD_AREA_VNUMS); if (pDoc->m_AreaType == eSMAUG) { AddPage (rangesdlg, "Ranges / Economy", CAreaRangesView, IDD_AREA_RANGES); AddFlag (flagsdlg, "Flags", flags, AreaFlags); AddPage (climatedlg, "Climate", CAreaClimateView, IDD_AREA_CLIMATE); AddPage (neighboursdlg, "Neighbours", CAreaNeighbourView, IDD_AREA_NEIGHBOUR); } namedlg->m_pDoc = pDoc; namedlg->m_pLHview = m_pLHview; // Add the tabs TC_ITEM tci; tci.mask = TCIF_TEXT; tci.iImage = -1; for (int i = 0; i < m_DlgArray.GetSize (); i++) { tci.pszText = (char *) (const char *) m_DlgArray[i]->m_name; m_ctlTabControl.InsertItem(i, &tci); } }