goal_gui.cpp

Go to the documentation of this file.
00001 /* $Id: goal_gui.cpp 23740 2012-01-03 21:32:51Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "industry.h"
00014 #include "town.h"
00015 #include "window_gui.h"
00016 #include "strings_func.h"
00017 #include "date_func.h"
00018 #include "viewport_func.h"
00019 #include "gui.h"
00020 #include "goal_base.h"
00021 #include "core/geometry_func.hpp"
00022 #include "company_func.h"
00023 #include "command_func.h"
00024 
00025 #include "widgets/goal_widget.h"
00026 
00027 #include "table/strings.h"
00028 
00029 struct GoalListWindow : Window {
00030   Scrollbar *vscroll;
00031 
00032   GoalListWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
00033   {
00034     this->CreateNestedTree(desc);
00035     this->vscroll = this->GetScrollbar(WID_GL_SCROLLBAR);
00036     this->FinishInitNested(desc, window_number);
00037     this->OnInvalidateData(0);
00038   }
00039 
00040   virtual void OnClick(Point pt, int widget, int click_count)
00041   {
00042     if (widget != WID_GL_PANEL) return;
00043 
00044     int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_PANEL, WD_FRAMERECT_TOP);
00045     int num = 0;
00046     const Goal *s;
00047     FOR_ALL_GOALS(s) {
00048       if (s->company == INVALID_COMPANY) {
00049         y--;
00050         if (y == 0) {
00051           this->HandleClick(s);
00052           return;
00053         }
00054         num++;
00055       }
00056     }
00057 
00058     if (num == 0) {
00059       y--; // "None"
00060       if (y < 0) return;
00061     }
00062 
00063     y -= 2; // "Company specific goals:"
00064     if (y < 0) return;
00065 
00066     FOR_ALL_GOALS(s) {
00067       if (s->company == _local_company) {
00068         y--;
00069         if (y == 0) {
00070           this->HandleClick(s);
00071           return;
00072         }
00073       }
00074     }
00075   }
00076 
00077   void HandleClick(const Goal *s)
00078   {
00079     /* determine dst coordinate for goal and try to scroll to it */
00080     TileIndex xy;
00081     switch (s->type) {
00082       case GT_NONE: return;
00083       case GT_COMPANY: return;
00084 
00085       case GT_TILE:
00086         if (!IsValidTile(s->dst)) return;
00087         xy = s->dst;
00088         break;
00089 
00090       case GT_INDUSTRY:
00091         if (!Industry::IsValidID(s->dst)) return;
00092         xy = Industry::Get(s->dst)->location.tile;
00093         break;
00094 
00095       case GT_TOWN:
00096         if (!Town::IsValidID(s->dst)) return;
00097         xy = Town::Get(s->dst)->xy;
00098         break;
00099 
00100       default: NOT_REACHED();
00101     }
00102 
00103     if (_ctrl_pressed) {
00104       ShowExtraViewPortWindow(xy);
00105     } else {
00106       ScrollMainWindowToTile(xy);
00107     }
00108   }
00109 
00114   uint CountLines()
00115   {
00116     /* Count number of (non) awarded goals */
00117     uint num_global = 0;
00118     uint num_company = 0;
00119     const Goal *s;
00120     FOR_ALL_GOALS(s) {
00121       if (s->company == INVALID_COMPANY) {
00122         num_global++;
00123       } else if (s->company == _local_company) {
00124         num_company++;
00125       }
00126     }
00127 
00128     /* Count the 'none' lines */
00129     if (num_global  == 0) num_global = 1;
00130     if (num_company == 0) num_company = 1;
00131 
00132     /* Global, company and an empty line before the accepted ones. */
00133     return 3 + num_global + num_company;
00134   }
00135 
00136   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00137   {
00138     if (widget != WID_GL_PANEL) return;
00139     Dimension d = maxdim(GetStringBoundingBox(STR_GOALS_GLOBAL_TITLE), GetStringBoundingBox(STR_GOALS_COMPANY_TITLE));
00140 
00141     resize->height = d.height;
00142 
00143     d.height *= 5;
00144     d.width += padding.width + WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT;
00145     d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00146     *size = maxdim(*size, d);
00147   }
00148 
00149   virtual void DrawWidget(const Rect &r, int widget) const
00150   {
00151     if (widget != WID_GL_PANEL) return;
00152 
00153     YearMonthDay ymd;
00154     ConvertDateToYMD(_date, &ymd);
00155 
00156     int right = r.right - WD_FRAMERECT_RIGHT;
00157     int y = r.top + WD_FRAMERECT_TOP;
00158     int x = r.left + WD_FRAMERECT_LEFT;
00159 
00160     int pos = -this->vscroll->GetPosition();
00161     const int cap = this->vscroll->GetCapacity();
00162 
00163     /* Section for drawing the global goals */
00164     if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_GLOBAL_TITLE);
00165     pos++;
00166 
00167     uint num = 0;
00168     const Goal *s;
00169     FOR_ALL_GOALS(s) {
00170       if (s->company == INVALID_COMPANY) {
00171         if (IsInsideMM(pos, 0, cap)) {
00172           /* Display the goal */
00173           SetDParamStr(0, s->text);
00174           DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_TEXT);
00175         }
00176         pos++;
00177         num++;
00178       }
00179     }
00180 
00181     if (num == 0) {
00182       if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_NONE);
00183       pos++;
00184     }
00185 
00186     /* Section for drawing the company goals */
00187     pos++;
00188     if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_COMPANY_TITLE);
00189     pos++;
00190     num = 0;
00191 
00192     FOR_ALL_GOALS(s) {
00193       if (s->company == _local_company) {
00194         if (IsInsideMM(pos, 0, cap)) {
00195           /* Display the goal */
00196           SetDParamStr(0, s->text);
00197           DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_TEXT);
00198         }
00199         pos++;
00200         num++;
00201       }
00202     }
00203 
00204     if (num == 0) {
00205       if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_NONE);
00206       pos++;
00207     }
00208   }
00209 
00210   virtual void OnResize()
00211   {
00212     this->vscroll->SetCapacityFromWidget(this, WID_GL_PANEL);
00213   }
00214 
00220   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00221   {
00222     if (!gui_scope) return;
00223     this->vscroll->SetCount(this->CountLines());
00224   }
00225 };
00226 
00227 static const NWidgetPart _nested_goals_list_widgets[] = {
00228   NWidget(NWID_HORIZONTAL),
00229     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00230     NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GOALS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00231     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00232     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00233   EndContainer(),
00234   NWidget(NWID_HORIZONTAL),
00235     NWidget(WWT_PANEL, COLOUR_BROWN, WID_GL_PANEL), SetDataTip(0x0, STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER), SetResize(1, 1), SetScrollbar(WID_GL_SCROLLBAR), EndContainer(),
00236     NWidget(NWID_VERTICAL),
00237       NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_GL_SCROLLBAR),
00238       NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00239     EndContainer(),
00240   EndContainer(),
00241 };
00242 
00243 static const WindowDesc _goals_list_desc(
00244   WDP_AUTO, 500, 127,
00245   WC_GOALS_LIST, WC_NONE,
00246   0,
00247   _nested_goals_list_widgets, lengthof(_nested_goals_list_widgets)
00248 );
00249 
00250 void ShowGoalsList()
00251 {
00252   AllocateWindowDescFront<GoalListWindow>(&_goals_list_desc, 0);
00253 }
00254 
00255 
00256 
00257 struct GoalQuestionWindow : Window {
00258   char *question;
00259   int buttons;
00260   int button[3];
00261 
00262   GoalQuestionWindow(const WindowDesc *desc, WindowNumber window_number, uint32 button_mask, const char *question) : Window()
00263   {
00264     this->question = strdup(question);
00265 
00266     /* Figure out which buttons we have to enable */
00267     int bit;
00268     int n = 0;
00269     FOR_EACH_SET_BIT(bit, button_mask) {
00270       if (bit >= GOAL_QUESTION_BUTTON_COUNT) break;
00271       this->button[n++] = bit;
00272       if (n == 3) break;
00273     }
00274     this->buttons = n;
00275     assert(this->buttons > 0 && this->buttons < 4);
00276 
00277     this->CreateNestedTree(desc);
00278     this->GetWidget<NWidgetStacked>(WID_GQ_BUTTONS)->SetDisplayedPlane(this->buttons - 1);
00279     this->FinishInitNested(desc, window_number);
00280   }
00281 
00282   ~GoalQuestionWindow()
00283   {
00284     free(this->question);
00285   }
00286 
00287   virtual void SetStringParameters(int widget) const
00288   {
00289     switch (widget) {
00290       case WID_GQ_BUTTON_1:
00291         SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[0]);
00292         break;
00293 
00294       case WID_GQ_BUTTON_2:
00295         SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[1]);
00296         break;
00297 
00298       case WID_GQ_BUTTON_3:
00299         SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[2]);
00300         break;
00301     }
00302   }
00303 
00304   virtual void OnClick(Point pt, int widget, int click_count)
00305   {
00306     switch (widget) {
00307       case WID_GQ_BUTTON_1:
00308         DoCommandP(0, this->window_number, this->button[0], CMD_GOAL_QUESTION_ANSWER);
00309         delete this;
00310         break;
00311 
00312       case WID_GQ_BUTTON_2:
00313         DoCommandP(0, this->window_number, this->button[1], CMD_GOAL_QUESTION_ANSWER);
00314         delete this;
00315         break;
00316 
00317       case WID_GQ_BUTTON_3:
00318         DoCommandP(0, this->window_number, this->button[2], CMD_GOAL_QUESTION_ANSWER);
00319         delete this;
00320         break;
00321     }
00322   }
00323 
00324   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00325   {
00326     if (widget != WID_GQ_QUESTION) return;
00327 
00328     SetDParamStr(0, this->question);
00329     size->height = GetStringHeight(STR_JUST_RAW_STRING, size->width) + WD_PAR_VSEP_WIDE;
00330   }
00331 
00332   virtual void DrawWidget(const Rect &r, int widget) const
00333   {
00334     if (widget != WID_GQ_QUESTION) return;
00335 
00336     SetDParamStr(0, this->question);
00337     DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK, SA_TOP | SA_HOR_CENTER);
00338   }
00339 };
00340 
00341 static const NWidgetPart _nested_goal_question_widgets[] = {
00342   NWidget(NWID_HORIZONTAL),
00343     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
00344     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_GOAL_QUESTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00345   EndContainer(),
00346   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
00347     NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GQ_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0),
00348     NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GQ_BUTTONS),
00349       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85),
00350         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
00351       EndContainer(),
00352       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(65, 10, 65),
00353         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
00354         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
00355       EndContainer(),
00356       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(25, 10, 25),
00357         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
00358         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
00359         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_3), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
00360       EndContainer(),
00361     EndContainer(),
00362     NWidget(NWID_SPACER), SetMinimalSize(0, 8),
00363   EndContainer(),
00364 };
00365 
00366 static const WindowDesc _goal_question_list_desc(
00367   WDP_CENTER, 0, 0,
00368   WC_GOAL_QUESTION, WC_NONE,
00369   WDF_CONSTRUCTION,
00370   _nested_goal_question_widgets, lengthof(_nested_goal_question_widgets)
00371 );
00372 
00373 
00374 void ShowGoalQuestion(uint16 id, uint32 button_mask, const char *question)
00375 {
00376   new GoalQuestionWindow(&_goal_question_list_desc, id, button_mask, question);
00377 }