void GridView::MoveFocus(Direction direction) { signed focusPos = GetIndexOfItemInFocus(); if (focusPos == -1) // We are on a page without enabled items. // We should show the next page if exists ShowNextPage(direction); else { signed newFocusPos = GetNextItemIndex(focusPos, direction); if (newFocusPos != -1) { // we are on the same page items[newFocusPos]->SetFocus(); if (!items[newFocusPos]->HasFocus()) { /* unable to set the focus, let's try simple Tab/Shift-Tab behavior instead */ newFocusPos = GetNextEnabledItemIndex(focusPos, direction); if (newFocusPos != -1) items[newFocusPos]->SetFocus(); } RefreshLayout(); } else ShowNextPage(direction); } }
void GridView::RefreshLayout() { const PixelRect rc = GetClientRect(); unsigned maxColumns = (rc.right - rc.left + horizontal_spacing) / (column_width + horizontal_spacing); if (maxColumns == 0) maxColumns = 1; unsigned maxRows = (rc.bottom - rc.top + vertical_spacing) / (row_height + vertical_spacing); if (maxRows == 0) maxRows = 1; if (maxColumns < num_columns) num_columns = maxColumns; if (maxRows < num_rows) num_rows = maxRows; unsigned pageSize = num_columns * num_rows; // Center grid in the client area unsigned reminderH = rc.right - rc.left + horizontal_spacing - num_columns * (column_width + horizontal_spacing); unsigned reminderV = rc.bottom - rc.top + vertical_spacing - num_rows * (row_height + vertical_spacing); unsigned leftOrigin = rc.left + reminderH / 2; unsigned topOrigin= rc.top + reminderV / 2; // Determine current page from item that has focus // If there is no item with focus or the item with focus is on current page, // the current page remains unchanged signed focusPos = GetIndexOfItemInFocus(); if (focusPos != -1) current_page = focusPos / pageSize; for (unsigned i = items.size(); i--;) { unsigned pagePos = i % pageSize; unsigned itemPage = i / pageSize; unsigned colNum = pagePos % num_columns; unsigned rowNum = pagePos / num_columns; items[i]->Move(leftOrigin + colNum * (column_width + horizontal_spacing), topOrigin + rowNum * (row_height + vertical_spacing), column_width, row_height); items[i]->SetVisible(itemPage == current_page); } }
void GridView::ShowNextPage(Direction direction) { signed newPos = -1; unsigned pageSize = num_columns * num_rows; unsigned lastPage = items.size() / pageSize; if (direction == Direction::LEFT && current_page > 0) current_page--; else if (direction == Direction::RIGHT && current_page < lastPage) current_page++; else return; unsigned currentPageSize = current_page == lastPage ? items.size() % pageSize : pageSize; signed focusPos = GetIndexOfItemInFocus(); if (focusPos != -1) { unsigned oldPagePos = focusPos % pageSize; unsigned oldRowNum = oldPagePos / num_columns; if (direction == Direction::LEFT) // last column in the same row newPos = current_page * pageSize + (oldRowNum + 1) * num_columns - 1; else { // direction == Direction::RIGHT // first column in the same row newPos = current_page * pageSize + oldRowNum * num_columns; if (newPos >= (signed)items.size()) { // first columns in the last row newPos = current_page * pageSize + currentPageSize - (currentPageSize - 1) % num_columns - 1; } } } if (newPos != -1) { items[newPos]->SetFocus(); /* unable to set the focus on the desired item, let's try Tab/Shift-Tab behavior instead */ if (!items[newPos]->HasFocus()) { if (direction == Direction::LEFT) newPos = GetNextEnabledItemIndex(current_page * pageSize + currentPageSize, direction); else newPos = GetNextEnabledItemIndex(current_page * pageSize - 1, direction); // set focus only if it is on the same page if (newPos != -1 && newPos >= (signed)(current_page * pageSize) && newPos < (signed)(current_page * pageSize + currentPageSize)) { items[newPos]->SetFocus(); } } else if (focusPos != -1) { #ifdef USE_WINUSER HWND oldFocusHwnd = ::GetFocus(); if (oldFocusHwnd != nullptr) ::SendMessage(oldFocusHwnd, WM_CANCELMODE, 0, 0); #else items[focusPos]->ClearFocus(); #endif /* USE_WINUSER */ } RefreshLayout(); } }