diff options
author | rubidium <rubidium@openttd.org> | 2010-08-28 19:43:41 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2010-08-28 19:43:41 +0000 |
commit | 7b16c7650bb5df437f7ba98acb1fdd917f4b8177 (patch) | |
tree | fadde11668192305b36cac77de20302729b8c827 /src | |
parent | 2d10b0f11d0300eebabccb48399f35c9acb55be0 (diff) | |
download | openttd-7b16c7650bb5df437f7ba98acb1fdd917f4b8177.tar.xz |
(svn r20670) -Add: support for action F
-Add: a window to select (NewGRF) objects
Diffstat (limited to 'src')
-rw-r--r-- | src/lang/english.txt | 8 | ||||
-rw-r--r-- | src/misc.cpp | 2 | ||||
-rw-r--r-- | src/newgrf_callbacks.h | 2 | ||||
-rw-r--r-- | src/newgrf_gui.cpp | 3 | ||||
-rw-r--r-- | src/object.h | 3 | ||||
-rw-r--r-- | src/object_gui.cpp | 336 | ||||
-rw-r--r-- | src/terraform_gui.cpp | 31 | ||||
-rw-r--r-- | src/window_type.h | 1 |
8 files changed, 383 insertions, 3 deletions
diff --git a/src/lang/english.txt b/src/lang/english.txt index 94f73c505..fa8b5287f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -334,6 +334,7 @@ STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industry STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Road construction STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant trees STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Place sign +STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Place object ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Save scenario @@ -2060,6 +2061,13 @@ STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Raise a STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level land STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use +# Object construction window +STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection +STR_OBJECT_BUILD_TOOLTIP :{BLACK}Select object to build +STR_OBJECT_BUILD_CLASS_LABEL :{BLACK}Object class +STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Preview of the object +STR_OBJECT_BUILD_SIZE :{BLACK}Size: {GOLD}{NUM} x {NUM} tiles + STR_OBJECT_CLASS_LTHS :Lighthouses STR_OBJECT_CLASS_TRNS :Transmitters diff --git a/src/misc.cpp b/src/misc.cpp index 75ec9f305..40fd7e0d8 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -42,6 +42,7 @@ void InitializeRailGui(); void InitializeRoadGui(); void InitializeAirportGui(); void InitializeDockGui(); +void InitializeObjectGui(); void InitializeIndustries(); void InitializeObjects(); void InitializeTowns(); @@ -93,6 +94,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin InitializeRoadGui(); InitializeAirportGui(); InitializeDockGui(); + InitializeObjectGui(); InitializeAIGui(); InitializeTowns(); InitializeSubsidies(); diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h index 5001cdc8e..8cc5f9359 100644 --- a/src/newgrf_callbacks.h +++ b/src/newgrf_callbacks.h @@ -268,7 +268,7 @@ enum CallbackID { CBID_OBJECT_COLOUR = 0x15B, // 15 bit callback /** Called to determine more text in the fund object window */ - CBID_OBJECT_FUND_MORE_TEXT = 0x15C, // 15 bit callback, not implemented + CBID_OBJECT_FUND_MORE_TEXT = 0x15C, // 15 bit callback /** Called to determine if one can alter the ground below an object tile */ CBID_OBJECT_AUTOSLOPE = 0x15D, // 15 bit callback diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index bc20c61a4..c659ac8fd 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -1530,6 +1530,9 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed) nw->avails.ForceRebuild(); w->InvalidateData(); + + ReInitAllWindows(); + DeleteWindowByClass(WC_BUILD_OBJECT); } } diff --git a/src/object.h b/src/object.h index 834cd8c9a..4ec12ceee 100644 --- a/src/object.h +++ b/src/object.h @@ -34,4 +34,7 @@ void UpdateCompanyHQ(TileIndex tile, uint score); */ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner = OWNER_NONE, struct Town *town = NULL); +void PlaceProc_Object(TileIndex tile); +void ShowBuildObjectPicker(struct Window *w); + #endif /* OBJECT_H */ diff --git a/src/object_gui.cpp b/src/object_gui.cpp new file mode 100644 index 000000000..31a1f93e7 --- /dev/null +++ b/src/object_gui.cpp @@ -0,0 +1,336 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file object_gui.cpp The GUI for objects. */ + +#include "stdafx.h" +#include "command_func.h" +#include "core/geometry_func.hpp" +#include "newgrf.h" +#include "newgrf_object.h" +#include "newgrf_text.h" +#include "sprite.h" +#include "strings_func.h" +#include "viewport_func.h" +#include "widgets/dropdown_type.h" +#include "window_gui.h" + +#include "table/strings.h" + +static ObjectClassID _selected_object_class; ///< the currently visible object class +static int _selected_object_index; ///< the index of the selected object in the current class or -1 + +/** Object widgets in the object picker window. */ +enum BuildObjectWidgets { + BOW_CLASS_DROPDOWN, ///< The dropdown with classes. + BOW_OBJECT_LIST, ///< The list with objects of a given class. + BOW_SCROLLBAR, ///< The scrollbar associated with the list. + BOW_OBJECT_SPRITE, ///< A preview sprite of the object. + BOW_OBJECT_SIZE, ///< The size of an object. + BOW_INFO, ///< Other information about the object (from the NewGRF). +}; + +/** The window used for building objects. */ +class BuildObjectWindow : public PickerWindowBase { + static const int OBJECT_MARGIN = 4; ///< The margin (in pixels) around an object. + int line_height; ///< The height of a single line. + int object_height; ///< The height of the object box. + int info_height; ///< The height of the info box. + Scrollbar *vscroll; ///< The scollbar. + + /** Build a dropdown list of available object classes */ + static DropDownList *BuildObjectClassDropDown() + { + DropDownList *list = new DropDownList(); + + for (uint i = 0; i < ObjectClass::GetCount(); i++) { + list->push_back(new DropDownListStringItem(ObjectClass::GetName((ObjectClassID)i), i, false)); + } + + return list; + } + +public: + BuildObjectWindow(const WindowDesc *desc, Window *w) : PickerWindowBase(w) + { + this->CreateNestedTree(desc); + + this->vscroll = this->GetScrollbar(BOW_SCROLLBAR); + this->vscroll->SetCapacity(5); + this->vscroll->SetPosition(0); + + this->FinishInitNested(desc, 0); + + this->vscroll->SetCount(ObjectClass::GetCount(_selected_object_class)); + this->SelectFirstAvailableObject(true); + } + + virtual ~BuildObjectWindow() + { + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case BOW_CLASS_DROPDOWN: + SetDParam(0, ObjectClass::GetName(_selected_object_class)); + break; + + case BOW_OBJECT_SIZE: { + const ObjectSpec *spec = ObjectClass::Get(_selected_object_class, _selected_object_index); + int size = spec == NULL ? 0 : spec->size; + SetDParam(0, GB(size, 0, 4)); + SetDParam(1, GB(size, 4, 4)); + break; + } + + default: break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case BOW_CLASS_DROPDOWN: { + Dimension d = {0, 0}; + for (uint i = 0; i < ObjectClass::GetCount(); i++) { + SetDParam(0, ObjectClass::GetName((ObjectClassID)i)); + d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case BOW_OBJECT_LIST: { + for (int i = 0; i < NUM_OBJECTS; i++) { + const ObjectSpec *spec = ObjectSpec::Get(i); + if (!spec->enabled) continue; + + size->width = max(size->width, GetStringBoundingBox(spec->name).width); + } + + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + size->height = this->vscroll->GetCapacity() * this->line_height; + break; + } + + case BOW_OBJECT_SPRITE: { + byte height = 0; + for (int i = 0; i < NUM_OBJECTS; i++) { + height = max(ObjectSpec::Get(i)->height, height); + } + this->object_height = height * TILE_HEIGHT; + size->height = TILE_PIXELS + this->object_height + 2 * OBJECT_MARGIN; + break; + } + + case BOW_INFO: + size->height = this->info_height; + break; + + default: break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case BOW_OBJECT_LIST: { + int y = r.top; + for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < ObjectClass::GetCount(_selected_object_class); i++) { + const ObjectSpec *spec = ObjectClass::Get(_selected_object_class, i); + if (!spec->IsAvailable()) { + GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, 0, FILLRECT_CHECKER); + } + DrawString(r.left + WD_MATRIX_LEFT, r.right + WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, spec->name, ((int)i == _selected_object_index) ? TC_WHITE : TC_BLACK); + y += this->line_height; + } + break; + } + + case BOW_OBJECT_SPRITE: { + const ObjectSpec *spec = ObjectClass::Get(_selected_object_class, _selected_object_index); + if (spec == NULL) break; + + DrawPixelInfo tmp_dpi; + /* Set up a clipping area for the preview. */ + if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + DrawNewObjectTileInGUI((r.right - r.left) / 2 - 1, this->object_height + OBJECT_MARGIN, spec); + _cur_dpi = old_dpi; + } + break; + } + + case BOW_INFO: { + const ObjectSpec *spec = ObjectClass::Get(_selected_object_class, _selected_object_index); + if (spec == NULL) break; + + /* Get the extra message for the GUI */ + if (HasBit(spec->callback_mask, CBM_OBJ_FUND_MORE_TEXT)) { + uint16 callback_res = GetObjectCallback(CBID_OBJECT_FUND_MORE_TEXT, 0, 0, spec, NULL, INVALID_TILE); + if (callback_res != CALLBACK_FAILED) { + StringID message = GetGRFStringID(spec->grf_prop.grffile->grfid, 0xD000 + callback_res); + if (message != STR_NULL && message != STR_UNDEFINED) { + PrepareTextRefStackUsage(6); + /* Use all the available space left from where we stand up to the + * end of the window. We ALSO enlarge the window if needed, so we + * can 'go' wild with the bottom of the window. */ + int y = DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, message); + StopTextRefStackUsage(); + if (y > this->info_height) { + BuildObjectWindow *bow = const_cast<BuildObjectWindow *>(this); + bow->info_height = y + 2; + bow->ReInit(); + } + } + } + } + } + } + } + + virtual void OnPaint() + { + this->DrawWidgets(); + } + + void SelectOtherObject(int object_index) + { + _selected_object_index = object_index; + + this->UpdateSelectSize(); + this->SetDirty(); + } + + void UpdateSelectSize() + { + if (_selected_object_index == -1) { + SetTileSelectSize(1, 1); + } else { + const ObjectSpec *spec = ObjectClass::Get(_selected_object_class, _selected_object_index); + int w = GB(spec->size, 0, 4); + int h = GB(spec->size, 4, 4); + SetTileSelectSize(w, h); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case BOW_CLASS_DROPDOWN: + ShowDropDownList(this, BuildObjectClassDropDown(), _selected_object_class, BOW_CLASS_DROPDOWN); + break; + + case BOW_OBJECT_LIST: { + int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height; + if (num_clicked >= this->vscroll->GetCount()) break; + const ObjectSpec *spec = ObjectClass::Get(_selected_object_class, num_clicked); + if (spec->IsAvailable()) this->SelectOtherObject(num_clicked); + break; + } + } + } + + /** + * Select the first available object. + * @param change_class If true, change the class if no object in the current + * class is available. + */ + void SelectFirstAvailableObject(bool change_class) + { + /* First try to select an object in the selected class. */ + for (uint i = 0; i < ObjectClass::GetCount(_selected_object_class); i++) { + const ObjectSpec *spec = ObjectClass::Get(_selected_object_class, i); + if (spec->IsAvailable()) { + this->SelectOtherObject(0); + return; + } + } + if (change_class) { + /* If that fails, select the first available object + * from a random class. */ + for (ObjectClassID j = OBJECT_CLASS_BEGIN; j < OBJECT_CLASS_MAX; j++) { + for (uint i = 0; i < ObjectClass::GetCount(j); i++) { + const ObjectSpec *spec = ObjectClass::Get(j, i); + if (spec->IsAvailable()) { + _selected_object_class = j; + this->SelectOtherObject(i); + return; + } + } + } + } + /* If all objects are unavailable, select nothing. */ + this->SelectOtherObject(-1); + } + + virtual void OnDropdownSelect(int widget, int index) + { + assert(widget == BOW_CLASS_DROPDOWN); + _selected_object_class = (ObjectClassID)index; + this->vscroll->SetCount(ObjectClass::GetCount(_selected_object_class)); + this->SelectFirstAvailableObject(false); + } +}; + +static const NWidgetPart _nested_build_object_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_OBJECT_BUILD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetPadding(2, 5, 2, 5), SetDataTip(STR_OBJECT_BUILD_CLASS_LABEL, STR_NULL), SetFill(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, BOW_CLASS_DROPDOWN), SetPadding(0, 5, 2, 5), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_OBJECT_BUILD_TOOLTIP), + NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 5), + NWidget(WWT_MATRIX, COLOUR_GREY, BOW_OBJECT_LIST), SetFill(1, 0), SetDataTip(0x501, STR_OBJECT_BUILD_TOOLTIP), SetScrollbar(BOW_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, BOW_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 0, 5), + NWidget(WWT_PANEL, COLOUR_GREY, BOW_OBJECT_SPRITE), SetMinimalSize(130, 0), SetFill(1, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_DARK_GREEN, BOW_OBJECT_SIZE), SetDataTip(STR_OBJECT_BUILD_SIZE, STR_NULL), SetPadding(2, 5, 2, 5), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BOW_INFO), SetPadding(2, 5, 0, 5), + EndContainer(), +}; + +static const WindowDesc _build_object_desc( + WDP_AUTO, 0, 0, + WC_BUILD_OBJECT, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_build_object_widgets, lengthof(_nested_build_object_widgets) +); + +/** + * Show our object picker. + * @param w The toolbar window we're associated with. + */ +void ShowBuildObjectPicker(Window *w) +{ + new BuildObjectWindow(&_build_object_desc, w); +} + +/** Reset all data of the object GUI. */ +void InitializeObjectGui() +{ + _selected_object_class = (ObjectClassID)0; +} + +/** + * PlaceProc function, called when someone pressed the button if the + * object-tool is selected + * @param tile on which to place the object + */ +void PlaceProc_Object(TileIndex tile) +{ + DoCommandP(tile, ObjectClass::Get(_selected_object_class, _selected_object_index)->Index(), 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); +} diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index c4b5ac6de..cfb9e5328 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -22,13 +22,14 @@ #include "functions.h" #include "sound_func.h" #include "base_station_base.h" -#include "object_type.h" #include "textbuf_gui.h" #include "genworld.h" #include "tree_map.h" #include "landscape_type.h" #include "tilehighlight_func.h" #include "strings_func.h" +#include "newgrf_object.h" +#include "object.h" #include "hotkeys.h" #include "table/strings.h" @@ -159,6 +160,7 @@ static void PlaceProc_LevelLand(TileIndex tile) /** Enum referring to the widgets of the terraform toolbar */ enum TerraformToolbarWidgets { + TTW_SHOW_PLACE_OBJECT, ///< Should the place object button be shown? TTW_BUTTONS_START, ///< Start of pushable buttons TTW_LOWER_LAND = TTW_BUTTONS_START, ///< Lower land button TTW_RAISE_LAND, ///< Raise land button @@ -167,6 +169,7 @@ enum TerraformToolbarWidgets { TTW_BUY_LAND, ///< Buy land button TTW_PLANT_TREES, ///< Plant trees button (note: opens seperate window, no place-push-button) TTW_PLACE_SIGN, ///< Place sign button + TTW_PLACE_OBJECT, ///< Place object button }; static void TerraformClick_Lower(Window *w) @@ -205,6 +208,13 @@ static void TerraformClick_PlaceSign(Window *w) HandlePlacePushButton(w, TTW_PLACE_SIGN, SPR_CURSOR_SIGN, HT_RECT, PlaceProc_Sign); } +static void TerraformClick_PlaceObject(Window *w) +{ + /* Don't show the place object button when there are no objects to place. */ + if (ObjectClass::GetCount() == 0) return; + if (HandlePlacePushButton(w, TTW_PLACE_OBJECT, SPR_CURSOR_TRANSMITTER, HT_RECT, PlaceProc_Object)) ShowBuildObjectPicker(w); +} + static OnButtonClick * const _terraform_button_proc[] = { TerraformClick_Lower, TerraformClick_Raise, @@ -213,18 +223,29 @@ static OnButtonClick * const _terraform_button_proc[] = { TerraformClick_BuyLand, TerraformClick_Trees, TerraformClick_PlaceSign, + TerraformClick_PlaceObject, }; struct TerraformToolbarWindow : Window { TerraformToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window() { - this->InitNested(desc, window_number); + /* This is needed as we like to have the tree available on OnInit. */ + this->CreateNestedTree(desc); + this->FinishInitNested(desc, window_number); } ~TerraformToolbarWindow() { } + virtual void OnInit() + { + /* Don't show the place object button when there are no objects to place. */ + NWidgetStacked *show_object = this->GetWidget<NWidgetStacked>(TTW_SHOW_PLACE_OBJECT); + show_object->SetDisplayedPlane(ObjectClass::GetCount() != 0 ? 0 : SZSP_NONE); + } + + virtual void OnPaint() { this->DrawWidgets(); @@ -277,6 +298,7 @@ struct TerraformToolbarWindow : Window { virtual void OnPlaceObjectAbort() { + DeleteWindowById(WC_BUILD_OBJECT, 0); this->RaiseButtons(); } @@ -291,6 +313,7 @@ Hotkey<TerraformToolbarWindow> TerraformToolbarWindow::terraform_hotkeys[] = { Hotkey<TerraformToolbarWindow>('U', "buyland", TTW_BUY_LAND), Hotkey<TerraformToolbarWindow>('I', "trees", TTW_PLANT_TREES), Hotkey<TerraformToolbarWindow>('O', "placesign", TTW_PLACE_SIGN), + Hotkey<TerraformToolbarWindow>('P', "placeobject", TTW_PLACE_OBJECT), HOTKEY_LIST_END(TerraformToolbarWindow) }; Hotkey<TerraformToolbarWindow> *_terraform_hotkeys = TerraformToolbarWindow::terraform_hotkeys; @@ -319,6 +342,10 @@ static const NWidgetPart _nested_terraform_widgets[] = { SetFill(0, 1), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, TTW_PLACE_SIGN), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), + NWidget(NWID_SELECTION, INVALID_COLOUR, TTW_SHOW_PLACE_OBJECT), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, TTW_PLACE_OBJECT), SetMinimalSize(22, 22), + SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT), + EndContainer(), EndContainer(), }; diff --git a/src/window_type.h b/src/window_type.h index e6c1adb3d..458ba70ae 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -110,6 +110,7 @@ enum WindowClass { WC_SPRITE_ALIGNER, WC_INDUSTRY_CARGOES, WC_GRF_PARAMETERS, + WC_BUILD_OBJECT, WC_INVALID = 0xFFFF }; |