# goal_gui.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    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(WindowDesc *desc, WindowNumber window_number) : Window(desc)
    00033   {
    00034     this->CreateNestedTree();
    00035     this->vscroll = this->GetScrollbar(WID_GL_SCROLLBAR);
    00036     this->FinishInitNested(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_GOAL && widget != WID_GL_PROGRESS) return;
    00043
    00044     int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_GOAL, 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_GOAL && widget != WID_GL_PROGRESS) return;
    00139     Dimension d = maxdim(GetStringBoundingBox(STR_GOALS_GLOBAL_TITLE), GetStringBoundingBox(STR_GOALS_COMPANY_TITLE));
    00140
    00141     if (widget == WID_GL_PROGRESS) {
    00142       /* Get max progress width. */
    00143       d.width = 0;
    00144       Goal *s;
    00145       FOR_ALL_GOALS(s) {
    00146         if (s->progress != NULL) {
    00147           SetDParamStr(0, s->progress);
    00148           Dimension goal_d = GetStringBoundingBox(STR_GOALS_PROGRESS);
    00149
    00150           if (goal_d.width > d.width) {
    00151             d.width = goal_d.width;
    00152           }
    00153         }
    00154       }
    00155     }
    00156
    00157     resize->height = d.height;
    00158
    00159     d.height *= 5;
    00160     d.width += padding.width + WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT;
    00161     d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    00162     *size = maxdim(*size, d);
    00163   }
    00164
    00169   void DrawPartialGoalList(int widget, int &pos, const int cap, int x, int y, int right, bool global_section) const
    00170   {
    00171     if (widget == WID_GL_GOAL && IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, global_section ? STR_GOALS_GLOBAL_TITLE : STR_GOALS_COMPANY_TITLE);
    00172     pos++;
    00173
    00174     uint num = 0;
    00175     const Goal *s;
    00176     FOR_ALL_GOALS(s) {
    00177       if (global_section ? s->company == INVALID_COMPANY : s->company == _local_company && s->company != INVALID_COMPANY) {
    00178         if (IsInsideMM(pos, 0, cap)) {
    00179           switch (widget) {
    00180             case WID_GL_GOAL:
    00181               /* Display the goal. */
    00182               SetDParamStr(0, s->text);
    00183               DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_TEXT);
    00184               break;
    00185
    00186             case WID_GL_PROGRESS:
    00187               if (s->progress != NULL) {
    00188                 SetDParamStr(0, s->progress);
    00189                 DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, s->completed ? STR_GOALS_PROGRESS_COMPLETE : STR_GOALS_PROGRESS, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
    00190               }
    00191               break;
    00192           }
    00193         }
    00194         pos++;
    00195         num++;
    00196       }
    00197     }
    00198
    00199     if (widget == WID_GL_GOAL && num == 0) {
    00200       if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_NONE);
    00201       pos++;
    00202     }
    00203   }
    00204
    00205   virtual void DrawWidget(const Rect &r, int widget) const
    00206   {
    00207     if (widget != WID_GL_GOAL && widget != WID_GL_PROGRESS) return;
    00208
    00209     YearMonthDay ymd;
    00210     ConvertDateToYMD(_date, &ymd);
    00211
    00212     int right = r.right - WD_FRAMERECT_RIGHT;
    00213     int y = r.top + WD_FRAMERECT_TOP;
    00214     int x = r.left + WD_FRAMERECT_LEFT;
    00215
    00216     int pos = -this->vscroll->GetPosition();
    00217     const int cap = this->vscroll->GetCapacity();
    00218
    00219     /* Draw partial list with global goals */
    00220     DrawPartialGoalList(widget, pos, cap, x, y, right, true);
    00221
    00222     /* Draw partial list with company goals */
    00223     pos++;
    00224     DrawPartialGoalList(widget, pos, cap, x, y, right, false);
    00225   }
    00226
    00227   virtual void OnResize()
    00228   {
    00229     this->vscroll->SetCapacityFromWidget(this, WID_GL_GOAL);
    00230   }
    00231
    00237   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
    00238   {
    00239     if (!gui_scope) return;
    00240     this->vscroll->SetCount(this->CountLines());
    00241   }
    00242 };
    00243
    00244 static const NWidgetPart _nested_goals_list_widgets[] = {
    00245   NWidget(NWID_HORIZONTAL),
    00246     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
    00247     NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_GOALS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00248     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
    00249     NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
    00250     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
    00251   EndContainer(),
    00252   NWidget(NWID_HORIZONTAL), SetFill(1, 1),
    00253     NWidget(WWT_PANEL, COLOUR_BROWN), SetDataTip(0x0, STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER), SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_GL_SCROLLBAR),
    00254       NWidget(NWID_VERTICAL), SetPIP(WD_FRAMERECT_TOP, 4, WD_FRAMETEXT_BOTTOM),
    00255         NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    00256           NWidget(WWT_EMPTY, COLOUR_GREY, WID_GL_GOAL), SetResize(1, 1), SetMinimalTextLines(2, 0), SetFill(1, 0),
    00257           NWidget(WWT_EMPTY, COLOUR_GREY, WID_GL_PROGRESS), SetResize(0, 1), SetMinimalTextLines(2, 0), SetFill(0, 1),
    00258         EndContainer(),
    00259       EndContainer(),
    00260     EndContainer(),
    00261     NWidget(NWID_VERTICAL),
    00262       NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_GL_SCROLLBAR),
    00263       NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
    00264     EndContainer(),
    00265   EndContainer(),
    00266 };
    00267
    00268 static WindowDesc _goals_list_desc(
    00269   WDP_AUTO, "list_goals", 500, 127,
    00270   WC_GOALS_LIST, WC_NONE,
    00271   0,
    00272   _nested_goals_list_widgets, lengthof(_nested_goals_list_widgets)
    00273 );
    00274
    00275 void ShowGoalsList()
    00276 {
    00277   AllocateWindowDescFront<GoalListWindow>(&_goals_list_desc, 0);
    00278 }
    00279
    00280
    00281
    00282 struct GoalQuestionWindow : Window {
    00283   char *question;
    00284   int buttons;
    00285   int button[3];
    00286   byte type;
    00287
    00288   GoalQuestionWindow(WindowDesc *desc, WindowNumber window_number, byte type, uint32 button_mask, const char *question) : Window(desc), type(type)
    00289   {
    00290     assert(type < GOAL_QUESTION_TYPE_COUNT);
    00291     this->question = strdup(question);
    00292
    00293     /* Figure out which buttons we have to enable */
    00294     uint bit;
    00295     int n = 0;
    00296     FOR_EACH_SET_BIT(bit, button_mask) {
    00297       if (bit >= GOAL_QUESTION_BUTTON_COUNT) break;
    00298       this->button[n++] = bit;
    00299       if (n == 3) break;
    00300     }
    00301     this->buttons = n;
    00302     assert(this->buttons > 0 && this->buttons < 4);
    00303
    00304     this->CreateNestedTree();
    00305     this->GetWidget<NWidgetStacked>(WID_GQ_BUTTONS)->SetDisplayedPlane(this->buttons - 1);
    00306     this->FinishInitNested(window_number);
    00307   }
    00308
    00309   ~GoalQuestionWindow()
    00310   {
    00311     free(this->question);
    00312   }
    00313
    00314   virtual void SetStringParameters(int widget) const
    00315   {
    00316     switch (widget) {
    00317       case WID_GQ_CAPTION:
    00318         SetDParam(0, STR_GOAL_QUESTION_CAPTION_QUESTION + this->type);
    00319         break;
    00320
    00321       case WID_GQ_BUTTON_1:
    00322         SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[0]);
    00323         break;
    00324
    00325       case WID_GQ_BUTTON_2:
    00326         SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[1]);
    00327         break;
    00328
    00329       case WID_GQ_BUTTON_3:
    00330         SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[2]);
    00331         break;
    00332     }
    00333   }
    00334
    00335   virtual void OnClick(Point pt, int widget, int click_count)
    00336   {
    00337     switch (widget) {
    00338       case WID_GQ_BUTTON_1:
    00339         DoCommandP(0, this->window_number, this->button[0], CMD_GOAL_QUESTION_ANSWER);
    00340         delete this;
    00341         break;
    00342
    00343       case WID_GQ_BUTTON_2:
    00344         DoCommandP(0, this->window_number, this->button[1], CMD_GOAL_QUESTION_ANSWER);
    00345         delete this;
    00346         break;
    00347
    00348       case WID_GQ_BUTTON_3:
    00349         DoCommandP(0, this->window_number, this->button[2], CMD_GOAL_QUESTION_ANSWER);
    00350         delete this;
    00351         break;
    00352     }
    00353   }
    00354
    00355   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    00356   {
    00357     if (widget != WID_GQ_QUESTION) return;
    00358
    00359     SetDParamStr(0, this->question);
    00360     size->height = GetStringHeight(STR_JUST_RAW_STRING, size->width) + WD_PAR_VSEP_WIDE;
    00361   }
    00362
    00363   virtual void DrawWidget(const Rect &r, int widget) const
    00364   {
    00365     if (widget != WID_GQ_QUESTION) return;
    00366
    00367     SetDParamStr(0, this->question);
    00368     DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK, SA_TOP | SA_HOR_CENTER);
    00369   }
    00370 };
    00371
    00372 static const NWidgetPart _nested_goal_question_widgets[] = {
    00373   NWidget(NWID_HORIZONTAL),
    00374     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
    00375     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_GQ_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00376   EndContainer(),
    00377   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
    00378     NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GQ_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0),
    00379     NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GQ_BUTTONS),
    00380       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85),
    00381         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
    00382       EndContainer(),
    00383       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(65, 10, 65),
    00384         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
    00385         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
    00386       EndContainer(),
    00387       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(25, 10, 25),
    00388         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
    00389         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
    00390         NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_3), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0),
    00391       EndContainer(),
    00392     EndContainer(),
    00393     NWidget(NWID_SPACER), SetMinimalSize(0, 8),
    00394   EndContainer(),
    00395 };
    00396
    00397 static WindowDesc _goal_question_list_desc(
    00398   WDP_CENTER, NULL, 0, 0,
    00399   WC_GOAL_QUESTION, WC_NONE,
    00400   WDF_CONSTRUCTION,
    00401   _nested_goal_question_widgets, lengthof(_nested_goal_question_widgets)
    00402 );
    00403
    00404
    00405 void ShowGoalQuestion(uint16 id, byte type, uint32 button_mask, const char *question)
    00406 {
    00407   new GoalQuestionWindow(&_goal_question_list_desc, id, type, button_mask, question);
    00408 }