diff -r 0eb16f656c52 src/signs_gui.cpp --- a/src/signs_gui.cpp Mon Jun 21 21:31:19 2010 +0200 +++ b/src/signs_gui.cpp Mon Jun 21 22:01:59 2010 +0200 @@ -127,7 +127,11 @@ }; struct SignListWindow : QueryStringBaseWindow, SignList { - int text_offset; // Offset of the sign text relative to the left edge of the SLW_LIST widget. +private: + const Sign *selected; ///< The selected sign + +public: + int text_offset; ///< Offset of the sign text relative to the left edge of the SLW_LIST widget. SignListWindow(const WindowDesc *desc, WindowNumber window_number) : QueryStringBaseWindow(MAX_LENGTH_SIGN_NAME_BYTES) { @@ -141,6 +145,7 @@ /* Initialize the filtering variables */ this->SetFilterString(""); + this->selected = NULL; /* Create initial list. */ this->signs.ForceRebuild(); @@ -193,8 +198,29 @@ /* Rebuild the list of signs */ this->InvalidateData(); + + /* Unset the selected sign pointer if the selected sign has + * been filtered out of the list. + */ + if (this->selected != NULL && this->signs.Find(this->selected) == this->signs.End()) { + this->selected = NULL; + } + + if (this->selected != NULL) this->ScrollToSelected(); } + /** Make sure that the currently selected sign is within the visible part of the sign list */ + void ScrollToSelected() + { + if (this->selected) { + /* Get the index of the selected sign */ + int idx = this->signs.FindIndex(this->selected); + if (idx == -1) return; // abort if the selected sign is not in the list anymore (got filtered away) + + this->vscroll.ScrollTowards(idx); + } + } + virtual void OnPaint() { this->DrawWidgets(); @@ -225,7 +251,7 @@ if (si->owner != OWNER_NONE) DrawCompanyIcon(si->owner, icon_left, y + sprite_offset_y); SetDParam(0, si->index); - DrawString(text_left, text_right, y, STR_SIGN_NAME, TC_YELLOW); + DrawString(text_left, text_right, y, STR_SIGN_NAME, this->selected == si ? TC_BLUE : TC_YELLOW); y += this->resize.step_height; } break; @@ -255,15 +281,12 @@ case SLW_FILTER_CLEAR_BTN: this->ClearFilterTextWidget(); this->SetFilterString(0); + this->selected = NULL; break; case SLW_FILTER_MATCH_CASE_BTN: SignList::match_case = !SignList::match_case; - if (SignList::match_case) { - this->LowerWidget(SLW_FILTER_MATCH_CASE_BTN); - } else { - this->RaiseWidget(SLW_FILTER_MATCH_CASE_BTN); - } + this->SetWidgetLoweredState(SLW_FILTER_MATCH_CASE_BTN, SignList::match_case); /* Rebuild the list of signs */ this->InvalidateData(); break; @@ -286,17 +309,20 @@ this->SetFilterString(this->text.buf); break; - case HEBR_CONFIRM: // Enter pressed -> goto first sign in list - if (this->signs.Length() >= 1) { - const Sign *si = this->signs[0]; + case HEBR_CONFIRM: { // Enter pressed -> goto selected sign in list (or first if no selected sign) + uint n_signs = this->signs.Length(); + if (n_signs >= 1) { + const Sign *si = this->selected ? this->selected : this->signs[0]; ScrollMainWindowToTile(TileVirtXY(si->x, si->y)); } return state; + } case HEBR_CANCEL: // ESC pressed, clear filter this->ClearFilterTextWidget(); // Empty the text in the EditBox widget this->SetFilterString(0); // Use empty text as filter text (= view all signs) this->UnfocusFocusedWidget(); // Unfocus the text box + this->selected = NULL; // Deselect sign in sign list return state; case HEBR_NOT_FOCUSED: // The filter text box is not globaly focused @@ -313,6 +339,64 @@ if (state == ES_HANDLED) OnOSKInput(SLW_FILTER_TEXT); + /* Selection of signs using arrow up/down , page up/down and ctrl + home/end keys. + * This only happens if the edit box is globaly focused. + */ + int selected_idx = this->selected ? this->signs.FindIndex(this->selected) : 0; + if (selected_idx == -1) selected_idx = 0; // FindIndex could return -1 if a non-available sign is selected + if (state != ES_HANDLED && this->IsWidgetGloballyFocused(SLW_FILTER_TEXT)) { + switch (keycode) { + case WKC_UP: + /* scroll up by one */ + selected_idx--; + selected_idx = Clamp(selected_idx, 0, (int)this->signs.Length() - 1); + state = ES_HANDLED; + break; + + case WKC_DOWN: + /* scroll down by one */ + selected_idx++; + selected_idx = Clamp(selected_idx, 0, (int)this->signs.Length() - 1); + state = ES_HANDLED; + break; + + case WKC_PAGEUP: + /* scroll up a page */ + selected_idx = max(0, selected_idx - (int)this->vscroll.GetCapacity()); + state = ES_HANDLED; + break; + + case WKC_PAGEDOWN: + /* scroll down a page */ + selected_idx = min(selected_idx + this->vscroll.GetCapacity(), (int)this->signs.Length() - 1); + state = ES_HANDLED; + break; + + case WKC_CTRL | WKC_HOME: // Home key without ctrl is processed by the edit box + /* jump to beginning */ + selected_idx = 0; + state = ES_HANDLED; + break; + + case WKC_CTRL | WKC_END: // End key without ctrl is processed by the edit box + /* jump to end */ + selected_idx = (int)this->signs.Length() - 1; + state = ES_HANDLED; + break; + } + + if (state == ES_HANDLED) { + /* Update the selected pointer */ + this->selected = this->signs[selected_idx]; + + /* Make sure the selected sign is visible */ + this->ScrollToSelected(); + + /* Repaint the window */ + this->SetDirty(); + } + } + return state; } @@ -363,6 +447,9 @@ } this->SortSignsList(); + + /* Make sure the selected sign is visible after the change of the contents */ + this->ScrollToSelected(); } };