Skip to content

Commit

Permalink
Change: Switch tree GUI to use a Matrix instead of individual buttons
Browse files Browse the repository at this point in the history
Mostly a code change, but has the neat side effect of not drawing more buttons than are tree types in the current climate.
Future proofing for maybe making NewGRF trees one day.
  • Loading branch information
nielsmh committed Jun 22, 2020
1 parent 87a069c commit 6bbea3c
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 109 deletions.
14 changes: 2 additions & 12 deletions src/script/api/game/game_window.hpp.sq
Expand Up @@ -1310,18 +1310,8 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOADING, "WID_TT_LOADING");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_END, "WID_TT_END");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS, "WID_TT_BUTTONS");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_11, "WID_BT_TYPE_11");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_12, "WID_BT_TYPE_12");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_13, "WID_BT_TYPE_13");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_14, "WID_BT_TYPE_14");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_21, "WID_BT_TYPE_21");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_22, "WID_BT_TYPE_22");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_23, "WID_BT_TYPE_23");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_24, "WID_BT_TYPE_24");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_31, "WID_BT_TYPE_31");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_32, "WID_BT_TYPE_32");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_33, "WID_BT_TYPE_33");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_34, "WID_BT_TYPE_34");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_MATRIX, "WID_BT_TYPE_MATRIX");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_SPRITE, "WID_BT_TYPE_SPRITE");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_RANDOM, "WID_BT_TYPE_RANDOM");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_MANY_RANDOM, "WID_BT_MANY_RANDOM");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CAPTION, "WID_VV_CAPTION");
Expand Down
14 changes: 2 additions & 12 deletions src/script/api/script_window.hpp
Expand Up @@ -2578,18 +2578,8 @@ class ScriptWindow : public ScriptObject {
/* automatically generated from ../../widgets/tree_widget.h */
/** Widgets of the #BuildTreesWindow class. */
enum BuildTreesWidgets {
WID_BT_TYPE_11 = ::WID_BT_TYPE_11, ///< Tree 1st column 1st row.
WID_BT_TYPE_12 = ::WID_BT_TYPE_12, ///< Tree 1st column 2nd row.
WID_BT_TYPE_13 = ::WID_BT_TYPE_13, ///< Tree 1st column 3rd row.
WID_BT_TYPE_14 = ::WID_BT_TYPE_14, ///< Tree 1st column 4th row.
WID_BT_TYPE_21 = ::WID_BT_TYPE_21, ///< Tree 2st column 1st row.
WID_BT_TYPE_22 = ::WID_BT_TYPE_22, ///< Tree 2st column 2nd row.
WID_BT_TYPE_23 = ::WID_BT_TYPE_23, ///< Tree 2st column 3rd row.
WID_BT_TYPE_24 = ::WID_BT_TYPE_24, ///< Tree 2st column 4th row.
WID_BT_TYPE_31 = ::WID_BT_TYPE_31, ///< Tree 3st column 1st row.
WID_BT_TYPE_32 = ::WID_BT_TYPE_32, ///< Tree 3st column 2nd row.
WID_BT_TYPE_33 = ::WID_BT_TYPE_33, ///< Tree 3st column 3rd row.
WID_BT_TYPE_34 = ::WID_BT_TYPE_34, ///< Tree 3st column 4th row.
WID_BT_TYPE_MATRIX = ::WID_BT_TYPE_MATRIX, ///< Tree type selection matrix.
WID_BT_TYPE_SPRITE = ::WID_BT_TYPE_SPRITE, ///< Tree type selection sprite/button inside matrix.
WID_BT_TYPE_RANDOM = ::WID_BT_TYPE_RANDOM, ///< Button to build random type of tree.
WID_BT_MANY_RANDOM = ::WID_BT_MANY_RANDOM, ///< Button to build many random trees.
};
Expand Down
159 changes: 86 additions & 73 deletions src/tree_gui.cpp
Expand Up @@ -15,6 +15,8 @@
#include "company_base.h"
#include "command_func.h"
#include "sound_func.h"
#include "strings_func.h"
#include "zoom_func.h"
#include "tree_map.h"

#include "widgets/tree_widget.h"
Expand Down Expand Up @@ -47,28 +49,61 @@ const PalSpriteID tree_sprites[] = {
*/
class BuildTreesWindow : public Window
{
/** Visual Y offset of tree root from the bottom of the tree type buttons */
static const int BUTTON_BOTTOM_OFFSET = 7;

uint16 base; ///< Base tree number used for drawing the window.
uint16 count; ///< Number of different trees available.
TreeType tree_to_plant; ///< Tree number to plant, \c TREE_INVALID for a random tree.
int tree_to_plant; ///< Tree number to plant, \c TREE_INVALID for a random tree.

/**
* Handle click on a tree build button.
* Update GUI elements and set state to begin/end building trees.
* @param tree_type Index of the button that was clicked, or -1 to abort building.
*/
void SetButtons(int tree_type)
{
/* Clicking the same type = abort placement */
if (this->tree_to_plant == tree_type) tree_type = -1;

if (tree_type >= 0) {
/* Activate placement */
if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
SetObjectToPlace(SPR_CURSOR_TREE, PAL_NONE, HT_RECT, this->window_class, this->window_number);
this->tree_to_plant = tree_type;
} else {
/* Deactivate placement */
this->tree_to_plant = -1;
ResetObjectToPlace();
}

this->SetWidgetLoweredState(WID_BT_TYPE_RANDOM, this->tree_to_plant == TREE_INVALID);
this->GetWidget<NWidgetMatrix>(WID_BT_TYPE_MATRIX)->SetClicked(this->tree_to_plant);
this->SetDirty();
}

public:
BuildTreesWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
{
this->InitNested(window_number);
auto *matrix = this->GetWidget<NWidgetMatrix>(WID_BT_TYPE_MATRIX);
matrix->SetCount(this->count);
matrix->SetupSmallestSize(this, false);
this->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL);
ResetObjectToPlace();
}

/**
* Calculate the maximum size of all tree sprites
* @return Dimension of the largest tree sprite
*/
Dimension GetMaxTreeSpriteSize()
Dimension GetMaxTreeSpriteSize() const
{
Dimension size, this_size;
Point offset;
/* Avoid to use it uninitialized */
size.width = 32; // default width - 2
size.height = 39; // default height - 7
size.height = 39; // default height - BUTTON_BOTTOM_OFFSET
offset.x = 0;
offset.y = 0;

Expand All @@ -84,48 +119,64 @@ class BuildTreesWindow : public Window

void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
{
if (widget >= WID_BT_TYPE_11 && widget <= WID_BT_TYPE_34) {
Dimension d = GetMaxTreeSpriteSize();
/* Allow some pixels extra width and height */
size->width = d.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
size->height = d.height + WD_FRAMERECT_RIGHT + WD_FRAMERECT_BOTTOM + 7; // we need some more space
return;
}
Dimension d;

if (widget != WID_BT_MANY_RANDOM) return;
switch (GB(widget, 0, 16)) {
case WID_BT_TYPE_MATRIX:
/* Size matrix to 4 columns and appropriate number of rows */
size->width += resize->width * 3;
size->height += ((this->count + 3) / 4 - 1) * resize->height;
break;

case WID_BT_TYPE_SPRITE:
/* Ensure tree type buttons are sized after the largest tree type */
d = GetMaxTreeSpriteSize();
size->width = d.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
size->height = d.height + WD_FRAMERECT_RIGHT + WD_FRAMERECT_BOTTOM + ScaleGUITrad(BUTTON_BOTTOM_OFFSET); // we need some more space
if (this->nested_root != nullptr && this->nested_root->current_x > 10) {
size->width = max(size->width, (this->nested_root->current_x - 2 - 2) / 4 - 1);
}
break;

if (_game_mode != GM_EDITOR) {
size->width = 0;
size->height = 0;
case WID_BT_MANY_RANDOM:
/* Hide the "plant many random trees" button outside of editor */
if (_game_mode != GM_EDITOR) {
size->width = 0;
size->height = 0;
}
break;
}
}

void DrawWidget(const Rect &r, int widget) const override
{
if (widget < WID_BT_TYPE_11 || widget > WID_BT_TYPE_34 || widget - WID_BT_TYPE_11 >= this->count) return;
const int index = GB(widget, 16, 16) + this->base;

switch (GB(widget, 0, 16)) {
case WID_BT_TYPE_SPRITE: {
/* Trees "grow" in the centre on the bottom line of the buttons */
DrawSprite(tree_sprites[index].sprite, tree_sprites[index].pal, (r.left + r.right) / 2 + WD_FRAMERECT_LEFT, r.bottom - ScaleGUITrad(BUTTON_BOTTOM_OFFSET));
break;
}

int i = this->base + widget - WID_BT_TYPE_11;
/* Trees "grow" in the centre on the bottom line of the buttons */
DrawSprite(tree_sprites[i].sprite, tree_sprites[i].pal, (r.left + r.right) / 2 + WD_FRAMERECT_LEFT, r.bottom - 7);
default:
/* Other widgets don't have custom drawing */
break;
}
}

void OnClick(Point pt, int widget, int click_count) override
{
switch (widget) {
case WID_BT_TYPE_11: case WID_BT_TYPE_12: case WID_BT_TYPE_13: case WID_BT_TYPE_14:
case WID_BT_TYPE_21: case WID_BT_TYPE_22: case WID_BT_TYPE_23: case WID_BT_TYPE_24:
case WID_BT_TYPE_31: case WID_BT_TYPE_32: case WID_BT_TYPE_33: case WID_BT_TYPE_34:
if (widget - WID_BT_TYPE_11 >= this->count) break;

if (HandlePlacePushButton(this, widget, SPR_CURSOR_TREE, HT_RECT)) {
this->tree_to_plant = (TreeType)(this->base + widget - WID_BT_TYPE_11);
}
const int index = GB(widget, 16, 16);

switch (GB(widget, 0, 16)) {
case WID_BT_TYPE_SPRITE:
if (index >= this->count) break;
this->SetButtons(index);
break;

case WID_BT_TYPE_RANDOM: // tree of random type.
if (HandlePlacePushButton(this, WID_BT_TYPE_RANDOM, SPR_CURSOR_TREE, HT_RECT)) {
this->tree_to_plant = TREE_INVALID;
}
this->SetButtons(TREE_INVALID);
break;

case WID_BT_MANY_RANDOM: // place trees randomly over the landscape
Expand All @@ -149,8 +200,8 @@ class BuildTreesWindow : public Window
void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override
{
if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) {
DoCommandP(end_tile, this->tree_to_plant, start_tile,
CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE));
TreeType tree_type = (this->tree_to_plant == TREE_INVALID) ? TREE_INVALID : (TreeType)(this->tree_to_plant + this->base);
DoCommandP(end_tile, tree_type, start_tile, CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE));
}
}

Expand All @@ -165,7 +216,7 @@ class BuildTreesWindow : public Window

void OnPlaceObjectAbort() override
{
this->RaiseButtons();
this->SetButtons(-1);
}
};

Expand All @@ -181,46 +232,8 @@ static const NWidgetPart _nested_build_trees_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(NWID_SPACER), SetMinimalSize(2, 0),
NWidget(NWID_VERTICAL),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_11), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_12), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_13), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_14), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 1),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_21), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_22), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_23), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_24), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 1),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_31), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_32), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_33), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_34), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP),
EndContainer(),
NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BT_TYPE_MATRIX), SetPIP(0, 1, 0),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_SPRITE), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(),
EndContainer(),
NWidget(NWID_SPACER), SetMinimalSize(0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_TYPE_RANDOM), SetMinimalSize(139, 12), SetDataTip(STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TOOLTIP),
Expand Down
14 changes: 2 additions & 12 deletions src/widgets/tree_widget.h
Expand Up @@ -12,18 +12,8 @@

/** Widgets of the #BuildTreesWindow class. */
enum BuildTreesWidgets {
WID_BT_TYPE_11, ///< Tree 1st column 1st row.
WID_BT_TYPE_12, ///< Tree 1st column 2nd row.
WID_BT_TYPE_13, ///< Tree 1st column 3rd row.
WID_BT_TYPE_14, ///< Tree 1st column 4th row.
WID_BT_TYPE_21, ///< Tree 2st column 1st row.
WID_BT_TYPE_22, ///< Tree 2st column 2nd row.
WID_BT_TYPE_23, ///< Tree 2st column 3rd row.
WID_BT_TYPE_24, ///< Tree 2st column 4th row.
WID_BT_TYPE_31, ///< Tree 3st column 1st row.
WID_BT_TYPE_32, ///< Tree 3st column 2nd row.
WID_BT_TYPE_33, ///< Tree 3st column 3rd row.
WID_BT_TYPE_34, ///< Tree 3st column 4th row.
WID_BT_TYPE_MATRIX, ///< Tree type selection matrix.
WID_BT_TYPE_SPRITE, ///< Tree type selection sprite/button inside matrix.
WID_BT_TYPE_RANDOM, ///< Button to build random type of tree.
WID_BT_MANY_RANDOM, ///< Button to build many random trees.
};
Expand Down

0 comments on commit 6bbea3c

Please sign in to comment.