mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-09 23:50:25 +00:00
Feature: Object class selection string filtering (#8603)
This commit is contained in:
parent
7577dfa575
commit
96990b2ea7
@ -12,6 +12,10 @@
|
|||||||
#include "newgrf.h"
|
#include "newgrf.h"
|
||||||
#include "newgrf_object.h"
|
#include "newgrf_object.h"
|
||||||
#include "newgrf_text.h"
|
#include "newgrf_text.h"
|
||||||
|
#include "querystring_gui.h"
|
||||||
|
#include "sortlist_type.h"
|
||||||
|
#include "stringfilter_type.h"
|
||||||
|
#include "string_func.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
#include "viewport_func.h"
|
#include "viewport_func.h"
|
||||||
#include "tilehighlight_func.h"
|
#include "tilehighlight_func.h"
|
||||||
@ -25,23 +29,35 @@
|
|||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
static ObjectClassID _selected_object_class; ///< the currently visible object class
|
static const ObjectClass *_selected_object_class; ///< Currently selected available object class.
|
||||||
static int _selected_object_index; ///< the index of the selected object in the current class or -1
|
static int _selected_object_index; ///< Index of the currently selected object if existing, else \c -1.
|
||||||
static uint8 _selected_object_view; ///< the view of the selected object
|
static uint8 _selected_object_view; ///< the view of the selected object
|
||||||
|
|
||||||
/** The window used for building objects. */
|
/** The window used for building objects. */
|
||||||
class BuildObjectWindow : public Window {
|
class BuildObjectWindow : public Window {
|
||||||
static const int OBJECT_MARGIN = 4; ///< The margin (in pixels) around an object.
|
typedef GUIList<const ObjectClass *, StringFilter &> GUIObjectClassList; ///< Type definition for the list to hold available object classes.
|
||||||
int line_height; ///< The height of a single line.
|
|
||||||
int info_height; ///< The height of the info box.
|
static const uint EDITBOX_MAX_SIZE = 16; ///< The maximum number of characters for the filter edit box.
|
||||||
Scrollbar *vscroll; ///< The scrollbar.
|
static const int OBJECT_MARGIN = 4; ///< The margin (in pixels) around an object.
|
||||||
|
|
||||||
|
int line_height; ///< The height of a single line.
|
||||||
|
int info_height; ///< The height of the info box.
|
||||||
|
Scrollbar* vscroll; ///< The scrollbar.
|
||||||
|
|
||||||
|
static Listing last_sorting; ///< Default sorting of #GUIObjectClassList.
|
||||||
|
static Filtering last_filtering; ///< Default filtering of #GUIObjectClassList.
|
||||||
|
static GUIObjectClassList::SortFunction * const sorter_funcs[]; ///< Sort functions of the #GUIObjectClassList.
|
||||||
|
static GUIObjectClassList::FilterFunction * const filter_funcs[]; ///< Filter functions of the #GUIObjectClassList.
|
||||||
|
GUIObjectClassList object_classes; ///< Available object classes.
|
||||||
|
StringFilter string_filter; ///< Filter for available objects.
|
||||||
|
QueryString filter_editbox; ///< Filter editbox.
|
||||||
|
|
||||||
/** Scroll #WID_BO_CLASS_LIST so that the selected object class is visible. */
|
/** Scroll #WID_BO_CLASS_LIST so that the selected object class is visible. */
|
||||||
void EnsureSelectedObjectClassIsVisible()
|
void EnsureSelectedObjectClassIsVisible()
|
||||||
{
|
{
|
||||||
uint pos = 0;
|
uint pos = 0;
|
||||||
for (int i = 0; i < _selected_object_class; i++) {
|
for (auto objclass : this->object_classes) {
|
||||||
if (ObjectClass::Get((ObjectClassID) i)->GetUISpecCount() == 0) continue;
|
if (objclass == _selected_object_class) break;
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
this->vscroll->ScrollTowards(pos);
|
this->vscroll->ScrollTowards(pos);
|
||||||
@ -55,10 +71,9 @@ class BuildObjectWindow : public Window {
|
|||||||
{
|
{
|
||||||
if (_selected_object_index == -1) return false;
|
if (_selected_object_index == -1) return false;
|
||||||
|
|
||||||
ObjectClass *sel_objclass = ObjectClass::Get(_selected_object_class);
|
if ((int)_selected_object_class->GetSpecCount() <= _selected_object_index) return false;
|
||||||
if ((int)sel_objclass->GetSpecCount() <= _selected_object_index) return false;
|
|
||||||
|
|
||||||
return sel_objclass->GetSpec(_selected_object_index)->IsAvailable();
|
return _selected_object_class->GetSpec(_selected_object_index)->IsAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,42 +87,132 @@ class BuildObjectWindow : public Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BuildObjectWindow(WindowDesc *desc, WindowNumber number) : Window(desc), info_height(1)
|
BuildObjectWindow(WindowDesc *desc, WindowNumber number) : Window(desc), info_height(1), filter_editbox(EDITBOX_MAX_SIZE)
|
||||||
{
|
{
|
||||||
this->CreateNestedTree();
|
this->CreateNestedTree();
|
||||||
|
|
||||||
this->vscroll = this->GetScrollbar(WID_BO_SCROLLBAR);
|
this->vscroll = this->GetScrollbar(WID_BO_SCROLLBAR);
|
||||||
|
|
||||||
|
this->querystrings[WID_BO_FILTER] = &this->filter_editbox;
|
||||||
|
|
||||||
|
this->object_classes.SetListing(this->last_sorting);
|
||||||
|
this->object_classes.SetFiltering(this->last_filtering);
|
||||||
|
this->object_classes.SetSortFuncs(this->sorter_funcs);
|
||||||
|
this->object_classes.SetFilterFuncs(this->filter_funcs);
|
||||||
|
this->object_classes.ForceRebuild();
|
||||||
|
|
||||||
|
BuildObjectClassesAvailable();
|
||||||
|
SelectClassAndObject();
|
||||||
|
|
||||||
this->FinishInitNested(number);
|
this->FinishInitNested(number);
|
||||||
|
|
||||||
ResetObjectToPlace();
|
|
||||||
|
|
||||||
this->vscroll->SetPosition(0);
|
|
||||||
this->vscroll->SetCount(ObjectClass::GetUIClassCount());
|
|
||||||
|
|
||||||
NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_BO_SELECT_MATRIX);
|
NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_BO_SELECT_MATRIX);
|
||||||
matrix->SetScrollbar(this->GetScrollbar(WID_BO_SELECT_SCROLL));
|
matrix->SetScrollbar(this->GetScrollbar(WID_BO_SELECT_SCROLL));
|
||||||
|
|
||||||
this->SelectOtherClass(_selected_object_class);
|
this->SetFocusedWidget(WID_BO_FILTER);
|
||||||
|
this->GetWidget<NWidgetMatrix>(WID_BO_OBJECT_MATRIX)->SetCount(4);
|
||||||
|
|
||||||
|
ResetObjectToPlace();
|
||||||
|
|
||||||
|
this->vscroll->SetCount((int) this->object_classes.size());
|
||||||
|
|
||||||
|
EnsureSelectedObjectClassIsVisible();
|
||||||
|
|
||||||
|
this->InvalidateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sort object classes by class name. */
|
||||||
|
static bool NameSorter(const ObjectClass *const& a, const ObjectClass *const& b)
|
||||||
|
{
|
||||||
|
char buffer_a[DRAW_STRING_BUFFER];
|
||||||
|
GetString(buffer_a, a->name, lastof(buffer_a));
|
||||||
|
|
||||||
|
char buffer_b[DRAW_STRING_BUFFER];
|
||||||
|
GetString(buffer_b, b->name, lastof(buffer_b));
|
||||||
|
|
||||||
|
return strnatcmp(buffer_a, buffer_b, true) < 0; // Sort by name (natural sorting).
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Filter object classes by class name. */
|
||||||
|
static bool CDECL TagNameFilter(const ObjectClass *const* oc, StringFilter& filter)
|
||||||
|
{
|
||||||
|
char buffer[DRAW_STRING_BUFFER];
|
||||||
|
GetString(buffer, (*oc)->name, lastof(buffer));
|
||||||
|
|
||||||
|
filter.ResetState();
|
||||||
|
filter.AddLine(buffer);
|
||||||
|
return filter.GetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds the filter list of available object classes. */
|
||||||
|
void BuildObjectClassesAvailable()
|
||||||
|
{
|
||||||
|
if (!this->object_classes.NeedRebuild()) return;
|
||||||
|
|
||||||
|
this->object_classes.clear();
|
||||||
|
|
||||||
|
for (uint i = 0; i < ObjectClass::GetClassCount(); i++) {
|
||||||
|
ObjectClass *objclass = ObjectClass::Get((ObjectClassID)i);
|
||||||
|
if (objclass->GetUISpecCount() == 0) continue; // Is this needed here?
|
||||||
|
object_classes.push_back(objclass);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->object_classes.Filter(this->string_filter);
|
||||||
|
this->object_classes.shrink_to_fit();
|
||||||
|
this->object_classes.RebuildDone();
|
||||||
|
this->object_classes.Sort();
|
||||||
|
|
||||||
|
this->vscroll->SetCount((uint)this->object_classes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the previously selected current object class and object
|
||||||
|
* can be shown as selected to the user when the dialog is opened.
|
||||||
|
*/
|
||||||
|
void SelectClassAndObject()
|
||||||
|
{
|
||||||
|
assert(!this->object_classes.empty()); // object GUI should be disabled elsewise
|
||||||
|
if (_selected_object_class == nullptr) {
|
||||||
|
/* This happens during the first time the window is open during the game life cycle. */
|
||||||
|
this->SelectOtherClass(this->object_classes[0]);
|
||||||
|
} else {
|
||||||
|
/* Check if the previously selected object class is not available anymore as a
|
||||||
|
* result of starting a new game without the corresponding NewGRF. */
|
||||||
|
bool available = false;
|
||||||
|
for (uint i = 0; ObjectClass::GetClassCount(); ++i) {
|
||||||
|
ObjectClass* objclass = ObjectClass::Get((ObjectClassID)i);
|
||||||
|
if (objclass == _selected_object_class) {
|
||||||
|
available = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (available) {
|
||||||
|
this->SelectOtherClass(_selected_object_class);
|
||||||
|
} else {
|
||||||
|
this->SelectOtherClass(this->object_classes[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this->CanRestoreSelectedObject()) {
|
if (this->CanRestoreSelectedObject()) {
|
||||||
this->SelectOtherObject(_selected_object_index);
|
this->SelectOtherObject(_selected_object_index);
|
||||||
} else {
|
} else {
|
||||||
this->SelectFirstAvailableObject(true);
|
this->SelectFirstAvailableObject(true);
|
||||||
}
|
}
|
||||||
assert(ObjectClass::Get(_selected_object_class)->GetUISpecCount() > 0); // object GUI should be disables elsewise
|
assert(_selected_object_class->GetUISpecCount() > 0); // object GUI should be disabled elsewise
|
||||||
this->EnsureSelectedObjectClassIsVisible();
|
|
||||||
this->GetWidget<NWidgetMatrix>(WID_BO_OBJECT_MATRIX)->SetCount(4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStringParameters(int widget) const override
|
void SetStringParameters(int widget) const override
|
||||||
{
|
{
|
||||||
switch (widget) {
|
switch (widget) {
|
||||||
case WID_BO_OBJECT_NAME: {
|
case WID_BO_OBJECT_NAME: {
|
||||||
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
|
const ObjectSpec *spec = _selected_object_class->GetSpec(_selected_object_index);
|
||||||
SetDParam(0, spec != nullptr ? spec->name : STR_EMPTY);
|
SetDParam(0, spec != nullptr ? spec->name : STR_EMPTY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WID_BO_OBJECT_SIZE: {
|
case WID_BO_OBJECT_SIZE: {
|
||||||
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
|
const ObjectSpec *spec = _selected_object_class->GetSpec(_selected_object_index);
|
||||||
int size = spec == nullptr ? 0 : spec->size;
|
int size = spec == nullptr ? 0 : spec->size;
|
||||||
SetDParam(0, GB(size, HasBit(_selected_object_view, 0) ? 4 : 0, 4));
|
SetDParam(0, GB(size, HasBit(_selected_object_view, 0) ? 4 : 0, 4));
|
||||||
SetDParam(1, GB(size, HasBit(_selected_object_view, 0) ? 0 : 4, 4));
|
SetDParam(1, GB(size, HasBit(_selected_object_view, 0) ? 0 : 4, 4));
|
||||||
@ -122,8 +227,7 @@ public:
|
|||||||
{
|
{
|
||||||
switch (widget) {
|
switch (widget) {
|
||||||
case WID_BO_CLASS_LIST: {
|
case WID_BO_CLASS_LIST: {
|
||||||
for (uint i = 0; i < ObjectClass::GetClassCount(); i++) {
|
for (auto objclass : this->object_classes) {
|
||||||
ObjectClass *objclass = ObjectClass::Get((ObjectClassID)i);
|
|
||||||
if (objclass->GetUISpecCount() == 0) continue;
|
if (objclass->GetUISpecCount() == 0) continue;
|
||||||
size->width = std::max(size->width, GetStringBoundingBox(objclass->name).width);
|
size->width = std::max(size->width, GetStringBoundingBox(objclass->name).width);
|
||||||
}
|
}
|
||||||
@ -142,7 +246,7 @@ public:
|
|||||||
|
|
||||||
case WID_BO_OBJECT_MATRIX: {
|
case WID_BO_OBJECT_MATRIX: {
|
||||||
/* Get the right amount of buttons based on the current spec. */
|
/* Get the right amount of buttons based on the current spec. */
|
||||||
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
|
const ObjectSpec *spec = _selected_object_class->GetSpec(_selected_object_index);
|
||||||
if (spec != nullptr) {
|
if (spec != nullptr) {
|
||||||
if (spec->views >= 2) size->width += resize->width;
|
if (spec->views >= 2) size->width += resize->width;
|
||||||
if (spec->views >= 4) size->height += resize->height;
|
if (spec->views >= 4) size->height += resize->height;
|
||||||
@ -182,7 +286,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get the right size for the single widget based on the current spec. */
|
/* Get the right size for the single widget based on the current spec. */
|
||||||
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
|
const ObjectSpec *spec = _selected_object_class->GetSpec(_selected_object_index);
|
||||||
if (spec != nullptr) {
|
if (spec != nullptr) {
|
||||||
if (spec->views >= 2) size->width = size->width / 2 - 1;
|
if (spec->views >= 2) size->width = size->width / 2 - 1;
|
||||||
if (spec->views >= 4) size->height = size->height / 2 - 1;
|
if (spec->views >= 4) size->height = size->height / 2 - 1;
|
||||||
@ -214,19 +318,20 @@ public:
|
|||||||
case WID_BO_CLASS_LIST: {
|
case WID_BO_CLASS_LIST: {
|
||||||
int y = r.top;
|
int y = r.top;
|
||||||
uint pos = 0;
|
uint pos = 0;
|
||||||
for (uint i = 0; i < ObjectClass::GetClassCount(); i++) {
|
for (auto objclass : this->object_classes) {
|
||||||
ObjectClass *objclass = ObjectClass::Get((ObjectClassID)i);
|
|
||||||
if (objclass->GetUISpecCount() == 0) continue;
|
if (objclass->GetUISpecCount() == 0) continue;
|
||||||
if (!this->vscroll->IsVisible(pos++)) continue;
|
if (!this->vscroll->IsVisible(pos++)) continue;
|
||||||
DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, objclass->name,
|
DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, objclass->name,
|
||||||
((int)i == _selected_object_class) ? TC_WHITE : TC_BLACK);
|
(objclass == _selected_object_class) ? TC_WHITE : TC_BLACK);
|
||||||
y += this->line_height;
|
y += this->line_height;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WID_BO_OBJECT_SPRITE: {
|
case WID_BO_OBJECT_SPRITE: {
|
||||||
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
|
if (_selected_object_index == -1) break;
|
||||||
|
|
||||||
|
const ObjectSpec *spec = _selected_object_class->GetSpec(_selected_object_index);
|
||||||
if (spec == nullptr) break;
|
if (spec == nullptr) break;
|
||||||
|
|
||||||
/* Height of the selection matrix.
|
/* Height of the selection matrix.
|
||||||
@ -254,10 +359,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WID_BO_SELECT_IMAGE: {
|
case WID_BO_SELECT_IMAGE: {
|
||||||
ObjectClass *objclass = ObjectClass::Get(_selected_object_class);
|
int obj_index = _selected_object_class->GetIndexFromUI(GB(widget, 16, 16));
|
||||||
int obj_index = objclass->GetIndexFromUI(GB(widget, 16, 16));
|
|
||||||
if (obj_index < 0) break;
|
if (obj_index < 0) break;
|
||||||
const ObjectSpec *spec = objclass->GetSpec(obj_index);
|
const ObjectSpec *spec = _selected_object_class->GetSpec(obj_index);
|
||||||
if (spec == nullptr) break;
|
if (spec == nullptr) break;
|
||||||
|
|
||||||
if (!spec->IsAvailable()) {
|
if (!spec->IsAvailable()) {
|
||||||
@ -282,7 +386,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WID_BO_INFO: {
|
case WID_BO_INFO: {
|
||||||
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
|
const ObjectSpec *spec = _selected_object_class->GetSpec(_selected_object_index);
|
||||||
if (spec == nullptr) break;
|
if (spec == nullptr) break;
|
||||||
|
|
||||||
/* Get the extra message for the GUI */
|
/* Get the extra message for the GUI */
|
||||||
@ -315,12 +419,12 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Select the specified object class.
|
* Select the specified object class.
|
||||||
* @param object_class_index Object class index to select.
|
* @param object_class Object class select.
|
||||||
*/
|
*/
|
||||||
void SelectOtherClass(ObjectClassID object_class_index)
|
void SelectOtherClass(const ObjectClass *object_class)
|
||||||
{
|
{
|
||||||
_selected_object_class = object_class_index;
|
_selected_object_class = object_class;
|
||||||
this->GetWidget<NWidgetMatrix>(WID_BO_SELECT_MATRIX)->SetCount(ObjectClass::Get(_selected_object_class)->GetUISpecCount());
|
this->GetWidget<NWidgetMatrix>(WID_BO_SELECT_MATRIX)->SetCount(_selected_object_class->GetUISpecCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -331,7 +435,7 @@ public:
|
|||||||
{
|
{
|
||||||
_selected_object_index = object_index;
|
_selected_object_index = object_index;
|
||||||
if (_selected_object_index != -1) {
|
if (_selected_object_index != -1) {
|
||||||
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
|
const ObjectSpec *spec = _selected_object_class->GetSpec(_selected_object_index);
|
||||||
_selected_object_view = std::min<int>(_selected_object_view, spec->views - 1);
|
_selected_object_view = std::min<int>(_selected_object_view, spec->views - 1);
|
||||||
this->ReInit();
|
this->ReInit();
|
||||||
} else {
|
} else {
|
||||||
@ -350,7 +454,7 @@ public:
|
|||||||
if (_selected_object_index == -1) {
|
if (_selected_object_index == -1) {
|
||||||
SetTileSelectSize(1, 1);
|
SetTileSelectSize(1, 1);
|
||||||
} else {
|
} else {
|
||||||
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
|
const ObjectSpec *spec = _selected_object_class->GetSpec(_selected_object_index);
|
||||||
int w = GB(spec->size, HasBit(_selected_object_view, 0) ? 4 : 0, 4);
|
int w = GB(spec->size, HasBit(_selected_object_view, 0) ? 4 : 0, 4);
|
||||||
int h = GB(spec->size, HasBit(_selected_object_view, 0) ? 0 : 4, 4);
|
int h = GB(spec->size, HasBit(_selected_object_view, 0) ? 0 : 4, 4);
|
||||||
SetTileSelectSize(w, h);
|
SetTileSelectSize(w, h);
|
||||||
@ -359,11 +463,11 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update buttons to show the selection to the user.
|
* Update buttons to show the selection to the user.
|
||||||
* @param sel_class The class of the selected object.
|
* @param object_class The class of the selected object.
|
||||||
* @param sel_index Index of the object to select, or \c -1 .
|
* @param sel_index Index of the object to select, or \c -1 .
|
||||||
* @param sel_view View of the object to select.
|
* @param sel_view View of the object to select.
|
||||||
*/
|
*/
|
||||||
void UpdateButtons(ObjectClassID sel_class, int sel_index, uint sel_view)
|
void UpdateButtons(const ObjectClass *object_class, int sel_index, uint sel_view)
|
||||||
{
|
{
|
||||||
int view_number, object_number;
|
int view_number, object_number;
|
||||||
if (sel_index == -1) {
|
if (sel_index == -1) {
|
||||||
@ -371,7 +475,7 @@ public:
|
|||||||
object_number = -1;
|
object_number = -1;
|
||||||
} else {
|
} else {
|
||||||
view_number = sel_view;
|
view_number = sel_view;
|
||||||
object_number = ObjectClass::Get(sel_class)->GetUIFromIndex(sel_index);
|
object_number = object_class->GetUIFromIndex(sel_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->GetWidget<NWidgetMatrix>(WID_BO_OBJECT_MATRIX)->SetClicked(view_number);
|
this->GetWidget<NWidgetMatrix>(WID_BO_OBJECT_MATRIX)->SetClicked(view_number);
|
||||||
@ -380,6 +484,13 @@ public:
|
|||||||
this->SetDirty();
|
this->SetDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||||
|
{
|
||||||
|
if (!gui_scope) return;
|
||||||
|
|
||||||
|
this->BuildObjectClassesAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
void OnResize() override
|
void OnResize() override
|
||||||
{
|
{
|
||||||
this->vscroll->SetCapacityFromWidget(this, WID_BO_CLASS_LIST);
|
this->vscroll->SetCapacityFromWidget(this, WID_BO_CLASS_LIST);
|
||||||
@ -390,17 +501,16 @@ public:
|
|||||||
switch (GB(widget, 0, 16)) {
|
switch (GB(widget, 0, 16)) {
|
||||||
case WID_BO_CLASS_LIST: {
|
case WID_BO_CLASS_LIST: {
|
||||||
int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height;
|
int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height;
|
||||||
if (num_clicked >= (int)ObjectClass::GetUIClassCount()) break;
|
if (num_clicked >= (int)this->object_classes.size()) break;
|
||||||
|
|
||||||
this->SelectOtherClass(ObjectClass::GetUIClass(num_clicked));
|
this->SelectOtherClass(this->object_classes[num_clicked]);
|
||||||
this->SelectFirstAvailableObject(false);
|
this->SelectFirstAvailableObject(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case WID_BO_SELECT_IMAGE: {
|
case WID_BO_SELECT_IMAGE: {
|
||||||
ObjectClass *objclass = ObjectClass::Get(_selected_object_class);
|
int num_clicked = _selected_object_class->GetIndexFromUI(GB(widget, 16, 16));
|
||||||
int num_clicked = objclass->GetIndexFromUI(GB(widget, 16, 16));
|
if (num_clicked >= 0 && _selected_object_class->GetSpec(num_clicked)->IsAvailable()) this->SelectOtherObject(num_clicked);
|
||||||
if (num_clicked >= 0 && objclass->GetSpec(num_clicked)->IsAvailable()) this->SelectOtherObject(num_clicked);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,7 +525,7 @@ public:
|
|||||||
|
|
||||||
void OnPlaceObject(Point pt, TileIndex tile) override
|
void OnPlaceObject(Point pt, TileIndex tile) override
|
||||||
{
|
{
|
||||||
DoCommandP(tile, ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index(),
|
DoCommandP(tile, _selected_object_class->GetSpec(_selected_object_index)->Index(),
|
||||||
_selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform);
|
_selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,6 +534,14 @@ public:
|
|||||||
this->UpdateButtons(_selected_object_class, -1, _selected_object_view);
|
this->UpdateButtons(_selected_object_class, -1, _selected_object_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnEditboxChanged(int wid) override
|
||||||
|
{
|
||||||
|
string_filter.SetFilterTerm(this->filter_editbox.text.buf);
|
||||||
|
this->object_classes.SetFilterState(!string_filter.IsEmpty());
|
||||||
|
this->object_classes.ForceRebuild();
|
||||||
|
this->InvalidateData();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select the first available object.
|
* Select the first available object.
|
||||||
* @param change_class If true, change the class if no object in the current
|
* @param change_class If true, change the class if no object in the current
|
||||||
@ -432,9 +550,8 @@ public:
|
|||||||
void SelectFirstAvailableObject(bool change_class)
|
void SelectFirstAvailableObject(bool change_class)
|
||||||
{
|
{
|
||||||
/* First try to select an object in the selected class. */
|
/* First try to select an object in the selected class. */
|
||||||
ObjectClass *sel_objclass = ObjectClass::Get(_selected_object_class);
|
for (uint i = 0; i < _selected_object_class->GetSpecCount(); i++) {
|
||||||
for (uint i = 0; i < sel_objclass->GetSpecCount(); i++) {
|
const ObjectSpec *spec = _selected_object_class->GetSpec(i);
|
||||||
const ObjectSpec *spec = sel_objclass->GetSpec(i);
|
|
||||||
if (spec->IsAvailable()) {
|
if (spec->IsAvailable()) {
|
||||||
this->SelectOtherObject(i);
|
this->SelectOtherObject(i);
|
||||||
return;
|
return;
|
||||||
@ -443,12 +560,11 @@ public:
|
|||||||
if (change_class) {
|
if (change_class) {
|
||||||
/* If that fails, select the first available object
|
/* If that fails, select the first available object
|
||||||
* from a random class. */
|
* from a random class. */
|
||||||
for (ObjectClassID j = OBJECT_CLASS_BEGIN; j < OBJECT_CLASS_MAX; j++) {
|
for (auto objclass : this->object_classes) {
|
||||||
ObjectClass *objclass = ObjectClass::Get(j);
|
|
||||||
for (uint i = 0; i < objclass->GetSpecCount(); i++) {
|
for (uint i = 0; i < objclass->GetSpecCount(); i++) {
|
||||||
const ObjectSpec *spec = objclass->GetSpec(i);
|
const ObjectSpec *spec = objclass->GetSpec(i);
|
||||||
if (spec->IsAvailable()) {
|
if (spec->IsAvailable()) {
|
||||||
this->SelectOtherClass(j);
|
this->SelectOtherClass(objclass);
|
||||||
this->SelectOtherObject(i);
|
this->SelectOtherObject(i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -456,11 +572,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* If all objects are unavailable, select nothing... */
|
/* If all objects are unavailable, select nothing... */
|
||||||
if (ObjectClass::Get(_selected_object_class)->GetUISpecCount() == 0) {
|
if (_selected_object_class->GetUISpecCount() == 0) {
|
||||||
/* ... but make sure that the class is not empty. */
|
/* ... but make sure that the class is not empty. */
|
||||||
for (ObjectClassID j = OBJECT_CLASS_BEGIN; j < OBJECT_CLASS_MAX; j++) {
|
for (auto objclass : this->object_classes) {
|
||||||
if (ObjectClass::Get(j)->GetUISpecCount() > 0) {
|
if (objclass->GetUISpecCount() > 0) {
|
||||||
this->SelectOtherClass(j);
|
this->SelectOtherClass(objclass);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -469,6 +585,17 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Listing BuildObjectWindow::last_sorting = { false, 0 };
|
||||||
|
Filtering BuildObjectWindow::last_filtering = { false, 0 };
|
||||||
|
|
||||||
|
BuildObjectWindow::GUIObjectClassList::SortFunction* const BuildObjectWindow::sorter_funcs[] = {
|
||||||
|
&NameSorter,
|
||||||
|
};
|
||||||
|
|
||||||
|
BuildObjectWindow::GUIObjectClassList::FilterFunction* const BuildObjectWindow::filter_funcs[] = {
|
||||||
|
&TagNameFilter,
|
||||||
|
};
|
||||||
|
|
||||||
static const NWidgetPart _nested_build_object_widgets[] = {
|
static const NWidgetPart _nested_build_object_widgets[] = {
|
||||||
NWidget(NWID_HORIZONTAL),
|
NWidget(NWID_HORIZONTAL),
|
||||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||||
@ -478,6 +605,11 @@ static const NWidgetPart _nested_build_object_widgets[] = {
|
|||||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
|
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
|
||||||
NWidget(NWID_HORIZONTAL), SetPadding(2, 0, 0, 0),
|
NWidget(NWID_HORIZONTAL), SetPadding(2, 0, 0, 0),
|
||||||
NWidget(NWID_VERTICAL),
|
NWidget(NWID_VERTICAL),
|
||||||
|
NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 5),
|
||||||
|
NWidget(WWT_TEXT, COLOUR_DARK_GREEN), SetFill(0, 1), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL),
|
||||||
|
NWidget(WWT_EDITBOX, COLOUR_GREY, WID_BO_FILTER), SetFill(1, 0), SetResize(1, 0),
|
||||||
|
SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||||
|
EndContainer(),
|
||||||
NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 5),
|
NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 5),
|
||||||
NWidget(WWT_MATRIX, COLOUR_GREY, WID_BO_CLASS_LIST), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_OBJECT_BUILD_CLASS_TOOLTIP), SetScrollbar(WID_BO_SCROLLBAR),
|
NWidget(WWT_MATRIX, COLOUR_GREY, WID_BO_CLASS_LIST), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_OBJECT_BUILD_CLASS_TOOLTIP), SetScrollbar(WID_BO_SCROLLBAR),
|
||||||
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BO_SCROLLBAR),
|
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BO_SCROLLBAR),
|
||||||
@ -530,5 +662,5 @@ void ShowBuildObjectPicker()
|
|||||||
/** Reset all data of the object GUI. */
|
/** Reset all data of the object GUI. */
|
||||||
void InitializeObjectGui()
|
void InitializeObjectGui()
|
||||||
{
|
{
|
||||||
_selected_object_class = (ObjectClassID)0;
|
_selected_object_class = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
/** Widgets of the #BuildObjectWindow class. */
|
/** Widgets of the #BuildObjectWindow class. */
|
||||||
enum BuildObjectWidgets {
|
enum BuildObjectWidgets {
|
||||||
|
WID_BO_FILTER, ///< The filter text box for the object list.
|
||||||
WID_BO_CLASS_LIST, ///< The list with classes.
|
WID_BO_CLASS_LIST, ///< The list with classes.
|
||||||
WID_BO_SCROLLBAR, ///< The scrollbar associated with the list.
|
WID_BO_SCROLLBAR, ///< The scrollbar associated with the list.
|
||||||
WID_BO_OBJECT_MATRIX, ///< The matrix with preview sprites.
|
WID_BO_OBJECT_MATRIX, ///< The matrix with preview sprites.
|
||||||
|
Loading…
Reference in New Issue
Block a user