00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "company_gui.h"
00014 #include "company_func.h"
00015 #include "signs_base.h"
00016 #include "signs_func.h"
00017 #include "debug.h"
00018 #include "command_func.h"
00019 #include "strings_func.h"
00020 #include "window_func.h"
00021 #include "map_func.h"
00022 #include "gfx_func.h"
00023 #include "viewport_func.h"
00024 #include "querystring_gui.h"
00025 #include "sortlist_type.h"
00026 #include "string_func.h"
00027
00028 #include "table/strings.h"
00029 #include "table/sprites.h"
00030
00031 struct SignList {
00032 typedef GUIList<const Sign *> GUISignList;
00033
00034 static const Sign *last_sign;
00035 GUISignList signs;
00036
00037 void BuildSignsList()
00038 {
00039 if (!this->signs.NeedRebuild()) return;
00040
00041 DEBUG(misc, 3, "Building sign list");
00042
00043 this->signs.Clear();
00044
00045 const Sign *si;
00046 FOR_ALL_SIGNS(si) *this->signs.Append() = si;
00047
00048 this->signs.Compact();
00049 this->signs.RebuildDone();
00050 }
00051
00053 static int CDECL SignNameSorter(const Sign * const *a, const Sign * const *b)
00054 {
00055 static char buf_cache[64];
00056 char buf[64];
00057
00058 SetDParam(0, (*a)->index);
00059 GetString(buf, STR_SIGN_NAME, lastof(buf));
00060
00061 if (*b != last_sign) {
00062 last_sign = *b;
00063 SetDParam(0, (*b)->index);
00064 GetString(buf_cache, STR_SIGN_NAME, lastof(buf_cache));
00065 }
00066
00067 return strcasecmp(buf, buf_cache);
00068 }
00069
00070 void SortSignsList()
00071 {
00072 if (!this->signs.Sort(&SignNameSorter)) return;
00073
00074
00075 this->last_sign = NULL;
00076 }
00077 };
00078
00079 const Sign *SignList::last_sign = NULL;
00080
00082 enum SignListWidgets {
00083 SLW_CAPTION,
00084 SLW_LIST,
00085 SLW_SCROLLBAR,
00086 };
00087
00088 struct SignListWindow : Window, SignList {
00089 int text_offset;
00090
00091 SignListWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
00092 {
00093 this->InitNested(desc, window_number);
00094
00095
00096 this->signs.ForceRebuild();
00097 this->signs.ForceResort();
00098 this->BuildSignsList();
00099 this->SortSignsList();
00100 this->vscroll.SetCount(this->signs.Length());
00101 }
00102
00103 virtual void OnPaint()
00104 {
00105 this->DrawWidgets();
00106 }
00107
00108 virtual void DrawWidget(const Rect &r, int widget) const
00109 {
00110 switch (widget) {
00111 case SLW_LIST: {
00112 uint y = r.top + WD_FRAMERECT_TOP;
00113
00114 if (this->vscroll.GetCount() == 0) {
00115 DrawString(r.left + WD_FRAMETEXT_LEFT, r.right, y, STR_STATION_LIST_NONE);
00116 return;
00117 }
00118
00119 bool rtl = _dynlang.text_dir == TD_RTL;
00120 int sprite_offset_y = (FONT_HEIGHT_NORMAL - 10) / 2 + 1;
00121 uint icon_left = 4 + (rtl ? r.right - this->text_offset : r.left);
00122 uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : this->text_offset);
00123 uint text_right = r.right - (rtl ? this->text_offset : WD_FRAMERECT_RIGHT);
00124
00125
00126 for (uint16 i = this->vscroll.GetPosition(); this->vscroll.IsVisible(i) && i < this->vscroll.GetCount(); i++) {
00127 const Sign *si = this->signs[i];
00128
00129 if (si->owner != OWNER_NONE) DrawCompanyIcon(si->owner, icon_left, y + sprite_offset_y);
00130
00131 SetDParam(0, si->index);
00132 DrawString(text_left, text_right, y, STR_SIGN_NAME, TC_YELLOW);
00133 y += this->resize.step_height;
00134 }
00135 break;
00136 }
00137 }
00138 }
00139
00140 virtual void SetStringParameters(int widget) const
00141 {
00142 if (widget == SLW_CAPTION) SetDParam(0, this->vscroll.GetCount());
00143 }
00144
00145 virtual void OnClick(Point pt, int widget)
00146 {
00147 if (widget == SLW_LIST) {
00148 uint id_v = (pt.y - this->GetWidget<NWidgetBase>(SLW_LIST)->pos_y - WD_FRAMERECT_TOP) / this->resize.step_height;
00149
00150 if (id_v >= this->vscroll.GetCapacity()) return;
00151 id_v += this->vscroll.GetPosition();
00152 if (id_v >= this->vscroll.GetCount()) return;
00153
00154 const Sign *si = this->signs[id_v];
00155 ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
00156 }
00157 }
00158
00159 virtual void OnResize()
00160 {
00161 this->vscroll.SetCapacityFromWidget(this, SLW_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
00162 }
00163
00164 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00165 {
00166 switch (widget) {
00167 case SLW_LIST: {
00168 Dimension spr_dim = GetSpriteSize(SPR_COMPANY_ICON);
00169 this->text_offset = WD_FRAMETEXT_LEFT + spr_dim.width + 2;
00170 resize->height = max<uint>(FONT_HEIGHT_NORMAL, GetSpriteSize(SPR_COMPANY_ICON).height);
00171 Dimension d = {this->text_offset + MAX_LENGTH_SIGN_NAME_PIXELS + WD_FRAMETEXT_RIGHT, WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM};
00172 *size = maxdim(*size, d);
00173 } break;
00174
00175 case SLW_CAPTION:
00176 SetDParam(0, max<size_t>(1000, Sign::GetPoolSize()));
00177 *size = GetStringBoundingBox(STR_SIGN_LIST_CAPTION);
00178 size->height += padding.height;
00179 size->width += padding.width;
00180 break;
00181 }
00182 }
00183
00184 virtual void OnInvalidateData(int data)
00185 {
00186 if (data == 0) {
00187 this->signs.ForceRebuild();
00188 this->BuildSignsList();
00189 this->SetWidgetDirty(SLW_CAPTION);
00190 this->vscroll.SetCount(this->signs.Length());
00191 } else {
00192 this->signs.ForceResort();
00193 }
00194
00195 this->SortSignsList();
00196 }
00197 };
00198
00199 static const NWidgetPart _nested_sign_list_widgets[] = {
00200 NWidget(NWID_HORIZONTAL),
00201 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00202 NWidget(WWT_CAPTION, COLOUR_GREY, SLW_CAPTION), SetDataTip(STR_SIGN_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00203 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00204 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00205 EndContainer(),
00206 NWidget(NWID_HORIZONTAL),
00207 NWidget(WWT_PANEL, COLOUR_GREY, SLW_LIST), SetMinimalSize(WD_FRAMETEXT_LEFT + 16 + MAX_LENGTH_SIGN_NAME_PIXELS + WD_FRAMETEXT_RIGHT, 50),
00208 SetResize(1, 10), SetFill(1, 0), EndContainer(),
00209 NWidget(NWID_VERTICAL),
00210 NWidget(WWT_SCROLLBAR, COLOUR_GREY, SLW_SCROLLBAR),
00211 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00212 EndContainer(),
00213 EndContainer(),
00214 };
00215
00216 static const WindowDesc _sign_list_desc(
00217 WDP_AUTO, 358, 138,
00218 WC_SIGN_LIST, WC_NONE,
00219 0,
00220 _nested_sign_list_widgets, lengthof(_nested_sign_list_widgets)
00221 );
00222
00223
00224 void ShowSignList()
00225 {
00226 AllocateWindowDescFront<SignListWindow>(&_sign_list_desc, 0);
00227 }
00228
00235 static bool RenameSign(SignID index, const char *text)
00236 {
00237 bool remove = StrEmpty(text);
00238 DoCommandP(0, index, 0, CMD_RENAME_SIGN | (StrEmpty(text) ? CMD_MSG(STR_ERROR_CAN_T_DELETE_SIGN) : CMD_MSG(STR_ERROR_CAN_T_CHANGE_SIGN_NAME)), NULL, text);
00239 return remove;
00240 }
00241
00243 enum QueryEditSignWidgets {
00244 QUERY_EDIT_SIGN_WIDGET_CAPTION,
00245 QUERY_EDIT_SIGN_WIDGET_TEXT,
00246 QUERY_EDIT_SIGN_WIDGET_OK,
00247 QUERY_EDIT_SIGN_WIDGET_CANCEL,
00248 QUERY_EDIT_SIGN_WIDGET_DELETE,
00249 QUERY_EDIT_SIGN_WIDGET_PREVIOUS,
00250 QUERY_EDIT_SIGN_WIDGET_NEXT,
00251 };
00252
00253 struct SignWindow : QueryStringBaseWindow, SignList {
00254 SignID cur_sign;
00255
00256 SignWindow(const WindowDesc *desc, const Sign *si) : QueryStringBaseWindow(MAX_LENGTH_SIGN_NAME_BYTES)
00257 {
00258 this->caption = STR_EDIT_SIGN_CAPTION;
00259 this->afilter = CS_ALPHANUMERAL;
00260
00261 this->InitNested(desc);
00262
00263 this->LowerWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
00264 UpdateSignEditWindow(si);
00265 this->SetFocusedWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
00266 }
00267
00268 void UpdateSignEditWindow(const Sign *si)
00269 {
00270 char *last_of = &this->edit_str_buf[this->edit_str_size - 1];
00271
00272
00273 if (si->name != NULL) {
00274 SetDParam(0, si->index);
00275 GetString(this->edit_str_buf, STR_SIGN_NAME, last_of);
00276 } else {
00277 GetString(this->edit_str_buf, STR_EMPTY, last_of);
00278 }
00279 *last_of = '\0';
00280
00281 this->cur_sign = si->index;
00282 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, MAX_LENGTH_SIGN_NAME_PIXELS);
00283
00284 this->SetWidgetDirty(QUERY_EDIT_SIGN_WIDGET_TEXT);
00285 this->SetFocusedWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
00286 }
00287
00293 const Sign *PrevNextSign(bool next)
00294 {
00295
00296 this->signs.ForceRebuild();
00297 this->signs.NeedResort();
00298 this->BuildSignsList();
00299 this->SortSignsList();
00300
00301
00302
00303
00304 uint end = this->signs.Length() - (next ? 1 : 0);
00305 for (uint i = next ? 0 : 1; i < end; i++) {
00306 if (this->cur_sign == this->signs[i]->index) {
00307
00308 return this->signs[i + (next ? 1 : -1)];
00309 }
00310 }
00311
00312 return this->signs[next ? 0 : this->signs.Length() - 1];
00313 }
00314
00315 virtual void SetStringParameters(int widget) const
00316 {
00317 switch (widget) {
00318 case QUERY_EDIT_SIGN_WIDGET_CAPTION:
00319 SetDParam(0, this->caption);
00320 break;
00321 }
00322 }
00323
00324 virtual void OnPaint()
00325 {
00326 this->DrawWidgets();
00327 if (!this->IsShaded()) this->DrawEditBox(QUERY_EDIT_SIGN_WIDGET_TEXT);
00328 }
00329
00330 virtual void OnClick(Point pt, int widget)
00331 {
00332 switch (widget) {
00333 case QUERY_EDIT_SIGN_WIDGET_PREVIOUS:
00334 case QUERY_EDIT_SIGN_WIDGET_NEXT: {
00335 const Sign *si = this->PrevNextSign(widget == QUERY_EDIT_SIGN_WIDGET_NEXT);
00336
00337
00338 this->signs.ForceRebuild();
00339 this->signs.NeedResort();
00340 this->BuildSignsList();
00341 this->SortSignsList();
00342
00343
00344 ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
00345 UpdateSignEditWindow(si);
00346 break;
00347 }
00348
00349 case QUERY_EDIT_SIGN_WIDGET_DELETE:
00350
00351 RenameSign(this->cur_sign, "");
00352
00353 break;
00354
00355 case QUERY_EDIT_SIGN_WIDGET_OK:
00356 if (RenameSign(this->cur_sign, this->text.buf)) break;
00357
00358
00359 case QUERY_EDIT_SIGN_WIDGET_CANCEL:
00360 delete this;
00361 break;
00362 }
00363 }
00364
00365 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00366 {
00367 EventState state = ES_NOT_HANDLED;
00368 switch (this->HandleEditBoxKey(QUERY_EDIT_SIGN_WIDGET_TEXT, key, keycode, state)) {
00369 default: break;
00370
00371 case HEBR_CONFIRM:
00372 if (RenameSign(this->cur_sign, this->text.buf)) break;
00373
00374
00375 case HEBR_CANCEL:
00376 delete this;
00377 break;
00378 }
00379 return state;
00380 }
00381
00382 virtual void OnMouseLoop()
00383 {
00384 this->HandleEditBox(QUERY_EDIT_SIGN_WIDGET_TEXT);
00385 }
00386
00387 virtual void OnOpenOSKWindow(int wid)
00388 {
00389 ShowOnScreenKeyboard(this, wid, QUERY_EDIT_SIGN_WIDGET_CANCEL, QUERY_EDIT_SIGN_WIDGET_OK);
00390 }
00391 };
00392
00393 static const NWidgetPart _nested_query_sign_edit_widgets[] = {
00394 NWidget(NWID_HORIZONTAL),
00395 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00396 NWidget(WWT_CAPTION, COLOUR_GREY, QUERY_EDIT_SIGN_WIDGET_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00397 EndContainer(),
00398 NWidget(WWT_PANEL, COLOUR_GREY),
00399 NWidget(WWT_EDITBOX, COLOUR_GREY, QUERY_EDIT_SIGN_WIDGET_TEXT), SetMinimalSize(256, 12), SetDataTip(STR_EDIT_SIGN_SIGN_OSKTITLE, STR_NULL), SetPadding(2, 2, 2, 2),
00400 EndContainer(),
00401 NWidget(NWID_HORIZONTAL),
00402 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, QUERY_EDIT_SIGN_WIDGET_OK), SetMinimalSize(61, 12), SetDataTip(STR_BUTTON_OK, STR_NULL),
00403 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, QUERY_EDIT_SIGN_WIDGET_CANCEL), SetMinimalSize(60, 12), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
00404 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, QUERY_EDIT_SIGN_WIDGET_DELETE), SetMinimalSize(60, 12), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_NULL),
00405 NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(),
00406 NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, QUERY_EDIT_SIGN_WIDGET_PREVIOUS), SetMinimalSize(11, 12), SetDataTip(AWV_DECREASE, STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP),
00407 NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, QUERY_EDIT_SIGN_WIDGET_NEXT), SetMinimalSize(11, 12), SetDataTip(AWV_INCREASE, STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP),
00408 EndContainer(),
00409 };
00410
00411 static const WindowDesc _query_sign_edit_desc(
00412 WDP_AUTO, 0, 0,
00413 WC_QUERY_STRING, WC_NONE,
00414 WDF_CONSTRUCTION | WDF_UNCLICK_BUTTONS,
00415 _nested_query_sign_edit_widgets, lengthof(_nested_query_sign_edit_widgets)
00416 );
00417
00418 void HandleClickOnSign(const Sign *si)
00419 {
00420 if (_ctrl_pressed && si->owner == _local_company) {
00421 RenameSign(si->index, NULL);
00422 return;
00423 }
00424 ShowRenameSignWindow(si);
00425 }
00426
00427 void ShowRenameSignWindow(const Sign *si)
00428 {
00429
00430 DeleteWindowById(WC_QUERY_STRING, 0);
00431
00432 new SignWindow(&_query_sign_edit_desc, si);
00433 }
00434
00435 void DeleteRenameSignWindow(SignID sign)
00436 {
00437 SignWindow *w = dynamic_cast<SignWindow *>(FindWindowById(WC_QUERY_STRING, 0));
00438
00439 if (w != NULL && w->cur_sign == sign) delete w;
00440 }