#include "SRBookChooser.h" #include "SwordReaderResource.h" #include BOOL SRBookChooser::s_fRegistered = false; SRBookChooser::SRBookChooser(WCString *wcsBookNames, WORD wNextMenuID) :m_nEndBook(BIBLE_TOTAL_BOOKS) ,m_nSelectedBook(0) ,m_nStartAt(1) ,m_wcsPrompt("Select a Book:") ,m_wNextMenuID(wNextMenuID) ,m_wcsBookNames(wcsBookNames) { RECT rect = {0,0,1,1}; m_wcsClassName = "SRBookChooser"; m_wcsWindowName = "Book Chooser"; // Calculate the button size. the ZZZ string should be a good representation of the largest string. // Future representations will reflect a preferred font. HDC hdc = ::GetDC(m_hWnd); INT h = ::DrawText(hdc, L"ZZZ", -1, &rect, DT_CALCRECT | DT_SINGLELINE | DT_CENTER | DT_VCENTER); m_nButtonHeight = 2*BUTTON_INTERNAL_PADDING + (rect.bottom - rect.top); m_nButtonWidth = 2*BUTTON_INTERNAL_PADDING + (rect.right - rect.left); ::ReleaseDC(m_hWnd, hdc); } BOOL SRBookChooser::Create(SRWnd *pParentWnd, RECT bounds) { if(!Register()) return FALSE; if(!SRWnd::Create(m_wcsClassName,m_wcsWindowName,WS_CHILD | WS_VISIBLE, bounds, pParentWnd, NULL, m_hInstance)) return FALSE; return TRUE; } SRBookChooser::~SRBookChooser() { } BOOL SRBookChooser::Register() { // Register window class... WNDCLASS wc; if(s_fRegistered) return TRUE; wc.style = CS_HREDRAW | CS_VREDRAW | CS_PARENTDC; wc.lpfnWndProc = (WNDPROC) MessageRoute; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = m_hInstance; wc.hIcon = NULL; wc.hCursor = 0; wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = m_wcsClassName.w_str(); if(RegisterClass(&wc) == 0) return FALSE; s_fRegistered = TRUE; return TRUE; } INT SRBookChooser::MaxCols() { RECT clientRect; ::GetClientRect(m_hWnd,&clientRect); return ( ((clientRect.right - BUTTON_PADDING_WIDTH) - clientRect.left)/(BUTTON_PADDING_WIDTH + m_nButtonWidth) ); } INT SRBookChooser::MaxRows() { RECT clientRect; INT nMaxBooks = 0; INT nMaxRows = 0; ::GetClientRect(m_hWnd,&clientRect); // 2 less rows due to the Prompt and the More Prev buttons. nMaxRows = ( ((clientRect.bottom - BUTTON_PADDING_HEIGHT) - clientRect.top)/(BUTTON_PADDING_HEIGHT + m_nButtonHeight) ) - 2; nMaxBooks = MaxCols() * nMaxRows; if(m_nStartAt == 1 && m_nEndBook <= nMaxBooks + MaxCols()) nMaxRows++; // We can fit another row since there is no need for a More or Prev button. return nMaxRows; } INT SRBookChooser::MaxBooksPerScreen() { return MaxCols() * MaxRows(); } // Tries to center the buttons by calculating a left edge INT SRBookChooser::LeftEdge() { RECT clientRect; GetClientRect(m_hWnd, &clientRect); return ((clientRect.right - clientRect.left)/2) - ((MaxCols()*m_nButtonWidth + (MaxCols() - 1)*BUTTON_PADDING_WIDTH)/2 ); } BOOL SRBookChooser::OnPaint() { RECT buttonRect; RECT clientRect; INT nCurrent = m_nStartAt; INT nColStart = 0; PAINTSTRUCT ps; INT nRow; INT nCol; INT nMaxCols = MaxCols(); INT nMaxRows = MaxRows(); UINT nTestament; HDC hdc = BeginPaint(m_hWnd, &ps); if (m_nSelectedBook < 1 || m_nSelectedBook > m_nEndBook) m_nSelectedBook = 1; GetClientRect(m_hWnd, &clientRect); FillRect(hdc, &clientRect, (HBRUSH)GetStockObject(WHITE_BRUSH)); // Draw the prompt. buttonRect.top = BUTTON_PADDING_HEIGHT; buttonRect.left = LeftEdge(); buttonRect.right = clientRect.right - LeftEdge(); buttonRect.bottom = buttonRect.top + m_nButtonHeight; DrawText(hdc, m_wcsPrompt.w_str(), -1, &buttonRect, DT_CENTER | DT_VCENTER); // Init the first button's bounds buttonRect.top = 2*BUTTON_PADDING_HEIGHT + m_nButtonHeight; buttonRect.bottom = buttonRect.top + m_nButtonHeight; buttonRect.left = LeftEdge(); buttonRect.right = buttonRect.left + m_nButtonWidth; for(nRow = 0; nRow < nMaxRows; nRow++){ for(nCol = 0; nCol < nMaxCols; nCol++){ nCurrent = m_nStartAt + (nRow * nMaxCols) + nCol; if (nCurrent <= BIBLE_OT_BOOKS) { nTestament = SWORD_OLD_TESTAMENT; } else { nTestament = SWORD_NEW_TESTAMENT; } if(m_nSelectedBook == nCurrent) { DrawButton(hdc, buttonRect, m_wcsBookNames[nCurrent - 1].w_str(), nTestament, TRUE); } else { DrawButton(hdc, buttonRect, m_wcsBookNames[nCurrent - 1].w_str(), nTestament, FALSE); } if(nCurrent == m_nEndBook) break; // Move the bounds right. buttonRect.left += m_nButtonWidth + BUTTON_PADDING_WIDTH; buttonRect.right = buttonRect.left + m_nButtonWidth; } // Move the bounds down and all the way back to the left. buttonRect.left = LeftEdge(); buttonRect.right = buttonRect.left + m_nButtonWidth; buttonRect.top += m_nButtonHeight + BUTTON_PADDING_HEIGHT; buttonRect.bottom = buttonRect.top + m_nButtonHeight; if(nCurrent == m_nEndBook) break; } // If we didn't reach the end we need to draw the More button... if(nCurrent < m_nEndBook){ buttonRect.left = clientRect.right - (BUTTON_WIDTH_MORE + LeftEdge()); buttonRect.right = buttonRect.left + BUTTON_WIDTH_MORE; buttonRect.top = clientRect.bottom - (m_nButtonHeight + BUTTON_PADDING_HEIGHT); buttonRect.bottom = clientRect.bottom - BUTTON_PADDING_HEIGHT; DrawButton(hdc, buttonRect, L"More >>", 0, FALSE); } // We are not on the first page of Books we need to draw a Prev button... if(m_nStartAt != 1){ buttonRect.left = LeftEdge(); buttonRect.right = buttonRect.left + BUTTON_WIDTH_MORE; buttonRect.top = clientRect.bottom - (m_nButtonHeight + BUTTON_PADDING_HEIGHT); buttonRect.bottom = clientRect.bottom - BUTTON_PADDING_HEIGHT; DrawButton(hdc, buttonRect, L"<< Prev", 0, FALSE); } //Clean up. EndPaint(m_hWnd,&ps); return TRUE; } void SRBookChooser::DrawButton(HDC hdc, RECT buttonRect, LPCWSTR caption, UINT nTestament, bool selected) { HBRUSH brushBG = CreateSolidBrush((COLORREF)BUTTON_BACKGROUND); if (nTestament == SWORD_OLD_TESTAMENT) { SetTextColor(hdc, BUTTON_OT_FOREGROUND); } else if (nTestament == SWORD_NEW_TESTAMENT){ SetTextColor(hdc, BUTTON_NT_FOREGROUND); } else { SetTextColor(hdc, BUTTON_FOREGROUND); } if (selected) { SetBkColor(hdc, BUTTON_SEL_BACKGROUND); FillRect(hdc, &buttonRect, brushBG); Rectangle(hdc, buttonRect.left, buttonRect.top, buttonRect.right, buttonRect.bottom); } else { SetBkColor(hdc, BUTTON_BACKGROUND); FillRect(hdc, &buttonRect, brushBG); } DrawText(hdc, caption, -1, &buttonRect, DT_CENTER | DT_VCENTER); DeleteObject(brushBG); } /* Return: * > 0 - the Book found. * 0 - More button pressed. * -1 - Prev button pressed. * -2 - White space tapped. Ignore */ INT SRBookChooser::BookAt(int x, int y) { RECT clientRect; INT nCols = (x - BUTTON_PADDING_WIDTH) / (m_nButtonWidth + BUTTON_PADDING_WIDTH); INT nRows = (y - BUTTON_PADDING_HEIGHT)/ (m_nButtonHeight + BUTTON_PADDING_HEIGHT) - 1; GetClientRect(m_hWnd, &clientRect); // I ignore the minimal amount of white space between the buttons. INT nBook = m_nStartAt + (nRows * MaxCols()) + nCols; if(y < m_nButtonHeight + 2*BUTTON_PADDING_HEIGHT) return -2; // Tapped the title area. // Check if the tap was on a button... if(y > clientRect.bottom - (m_nButtonHeight + BUTTON_PADDING_HEIGHT) ){ if(x > BUTTON_PADDING_WIDTH && x < BUTTON_PADDING_WIDTH + BUTTON_WIDTH_MORE){ return -1; }else if( (x > (MaxCols()*(m_nButtonWidth+BUTTON_PADDING_WIDTH) - BUTTON_WIDTH_MORE)) && (x < (MaxCols()*(m_nButtonWidth+BUTTON_PADDING_WIDTH))) ){ return 0; }else return -2; } if(nBook > m_nEndBook || nBook >= m_nStartAt + MaxBooksPerScreen()) return -2; return nBook; } BOOL SRBookChooser::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){ if(nChar == VK_RIGHT){ m_nLastChar = VK_RIGHT; MoveRight(); RefreshWindow(); } else if(nChar == VK_DOWN){ m_nLastChar = VK_DOWN; MoveDown(); RefreshWindow(); } else if(nChar == VK_LEFT){ m_nLastChar = VK_LEFT; MoveLeft(); RefreshWindow(); } else if(nChar == VK_UP){ m_nLastChar = VK_UP; MoveUp(); RefreshWindow(); } else if (nChar == VK_ROCKER) { if (m_nLastChar == VK_UP) { MoveDown(); MoveLeft(); RefreshWindow(); } else if (m_nLastChar == VK_DOWN) { MoveUp(); MoveRight(); RefreshWindow(); } } else if(nChar == VK_RETURN){ ::SendMessage(m_pParentWnd->GetWindowHandle(),WM_COMMAND,SR_SETBOOK, m_nSelectedBook); ::SendMessage(m_pParentWnd->GetWindowHandle(),WM_COMMAND,m_wNextMenuID, m_nSelectedBook); } return true; } void SRBookChooser::MoveDown() { INT nMaxCols = MaxCols(); INT nMaxRows = MaxRows(); INT curRow = (m_nSelectedBook - m_nStartAt + 1) / nMaxCols; INT curTrueRow = m_nSelectedBook / nMaxCols; INT curCol = m_nSelectedBook - (nMaxCols * curTrueRow); if (curCol != nMaxCols) curRow++; if ((m_nSelectedBook + nMaxCols) > m_nEndBook) { if ((curRow == nMaxRows) && (((nMaxCols - curCol) + m_nSelectedBook) < m_nEndBook)) m_nStartAt += nMaxCols; m_nSelectedBook = m_nEndBook; } else { if (curRow == nMaxRows) m_nStartAt += nMaxCols; m_nSelectedBook += nMaxCols; } } void SRBookChooser::MoveLeft() { if (m_nSelectedBook == m_nStartAt) { if (m_nStartAt != 1) { m_nSelectedBook--; m_nStartAt -= MaxCols(); } } else { m_nSelectedBook--; } } void SRBookChooser::MoveRight() { INT nMaxCols = MaxCols(); INT nMaxRows = MaxRows(); INT curRow = (m_nSelectedBook - m_nStartAt + 1) / nMaxCols; INT curTrueRow = m_nSelectedBook / nMaxCols; INT curCol = m_nSelectedBook - (nMaxCols * (curTrueRow - 1)); if (m_nSelectedBook != m_nEndBook) { if ((curRow == nMaxRows) && (curCol == nMaxCols)) { m_nStartAt += nMaxCols; } m_nSelectedBook++; } } void SRBookChooser::MoveUp() { INT nMaxCols = MaxCols(); if ((m_nSelectedBook - nMaxCols) < m_nStartAt) { if (!((m_nSelectedBook - nMaxCols) < 1)) { m_nSelectedBook -= nMaxCols; m_nStartAt -= nMaxCols; } } else { m_nSelectedBook -= nMaxCols; } } BOOL SRBookChooser::OnLButtonUp(WORD fwKeys, INT xPos, INT yPos) { TCHAR buf[16] = {0}; INT found = BookAt(xPos, yPos); m_fLButtonDown = FALSE; if(found == 0 && (m_nStartAt + MaxBooksPerScreen() <= m_nEndBook) ){ m_nStartAt += MaxBooksPerScreen(); RefreshWindow(); }else if(found == -1 && m_nStartAt != 1){ m_nStartAt -= MaxBooksPerScreen(); RefreshWindow(); }else if(found == -2){ return TRUE; }else if(found != 0 && found != -1){ m_nSelectedBook = found; // We also send the value found, thus when this messge is recv'd the new value can be processed. ::SendMessage(m_pParentWnd->GetWindowHandle(),WM_COMMAND,SR_SETBOOK, found); ::SendMessage(m_pParentWnd->GetWindowHandle(),WM_COMMAND,m_wNextMenuID, found); } return TRUE; } BOOL SRBookChooser::OnLButtonDown(WORD fwKeys, INT xPos, INT yPos) { INT found = BookAt(xPos, yPos); m_fLButtonDown = TRUE; if(found > 0){ m_nSelectedBook = found; RefreshWindow(); } return TRUE; } BOOL SRBookChooser::OnMouseMove(WORD fwKeys, INT xPos, INT yPos) { INT found = BookAt(xPos, yPos); if(found > 0 && m_nSelectedBook != found && m_fLButtonDown){ m_nSelectedBook = found; RefreshWindow(); } return TRUE; } void SRBookChooser::SetSelectedBook(INT nSelectedBook) { if(nSelectedBook < 0 || nSelectedBook > m_nEndBook) m_nSelectedBook = 0; else m_nSelectedBook = nSelectedBook; } void SRBookChooser::SetEndBook(INT nEndBook) { m_nEndBook = nEndBook; }