00001
00002
00005 #include "stdafx.h"
00006 #include "company_gui.h"
00007 #include "company_func.h"
00008 #include "signs_base.h"
00009 #include "signs_func.h"
00010 #include "debug.h"
00011 #include "command_func.h"
00012 #include "strings_func.h"
00013 #include "window_func.h"
00014 #include "map_func.h"
00015 #include "gfx_func.h"
00016 #include "viewport_func.h"
00017 #include "querystring_gui.h"
00018 #include "sortlist_type.h"
00019 #include "string_func.h"
00020
00021 #include "table/strings.h"
00022
00023 struct SignList {
00024 typedef GUIList<const Sign *> GUISignList;
00025
00026 static const Sign *last_sign;
00027 GUISignList signs;
00028
00029 void BuildSignsList()
00030 {
00031 if (!this->signs.NeedRebuild()) return;
00032
00033 DEBUG(misc, 3, "Building sign list");
00034
00035 this->signs.Clear();
00036
00037 const Sign *si;
00038 FOR_ALL_SIGNS(si) *this->signs.Append() = si;
00039
00040 this->signs.Compact();
00041 this->signs.RebuildDone();
00042 }
00043
00045 static int CDECL SignNameSorter(const Sign * const *a, const Sign * const *b)
00046 {
00047 static char buf_cache[64];
00048 char buf[64];
00049
00050 SetDParam(0, (*a)->index);
00051 GetString(buf, STR_SIGN_NAME, lastof(buf));
00052
00053 if (*b != last_sign) {
00054 last_sign = *b;
00055 SetDParam(0, (*b)->index);
00056 GetString(buf_cache, STR_SIGN_NAME, lastof(buf_cache));
00057 }
00058
00059 return strcasecmp(buf, buf_cache);
00060 }
00061
00062 void SortSignsList()
00063 {
00064 if (!this->signs.Sort(&SignNameSorter)) return;
00065
00066
00067 this->last_sign = NULL;
00068 }
00069 };
00070
00071 const Sign *SignList::last_sign = NULL;
00072
00073 struct SignListWindow : Window, SignList {
00074 SignListWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00075 {
00076 this->vscroll.cap = 12;
00077 this->resize.step_height = 10;
00078 this->resize.height = this->height - 10 * 7;
00079
00080 this->signs.ForceRebuild();
00081 this->signs.NeedResort();
00082
00083 this->FindWindowPlacementAndResize(desc);
00084 }
00085
00086 virtual void OnPaint()
00087 {
00088 BuildSignsList();
00089 SortSignsList();
00090
00091 SetVScrollCount(this, this->signs.Length());
00092
00093 SetDParam(0, this->vscroll.count);
00094 this->DrawWidgets();
00095
00096
00097 int y = 16;
00098 if (this->vscroll.count == 0) {
00099 DrawString(2, y, STR_304A_NONE, TC_FROMSTRING);
00100 return;
00101 }
00102
00103
00104 for (uint16 i = this->vscroll.pos; i < this->vscroll.cap + this->vscroll.pos && i < this->vscroll.count; i++) {
00105 const Sign *si = this->signs[i];
00106
00107 if (si->owner != OWNER_NONE) DrawCompanyIcon(si->owner, 4, y + 1);
00108
00109 SetDParam(0, si->index);
00110 DrawString(22, y, STR_SIGN_NAME, TC_YELLOW);
00111 y += 10;
00112 }
00113 }
00114
00115 virtual void OnClick(Point pt, int widget)
00116 {
00117 if (widget == 3) {
00118 uint32 id_v = (pt.y - 15) / 10;
00119
00120 if (id_v >= this->vscroll.cap) return;
00121 id_v += this->vscroll.pos;
00122 if (id_v >= this->vscroll.count) return;
00123
00124 const Sign *si = this->signs[id_v];
00125 ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
00126 }
00127 }
00128
00129 virtual void OnResize(Point new_size, Point delta)
00130 {
00131 this->vscroll.cap += delta.y / 10;
00132 }
00133
00134 virtual void OnInvalidateData(int data)
00135 {
00136 if (data == 0) {
00137 this->signs.ForceRebuild();
00138 } else {
00139 this->signs.ForceResort();
00140 }
00141 }
00142 };
00143
00144 static const Widget _sign_list_widget[] = {
00145 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00146 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_GREY, 11, 345, 0, 13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
00147 { WWT_STICKYBOX, RESIZE_LR, COLOUR_GREY, 346, 357, 0, 13, 0x0, STR_STICKY_BUTTON},
00148 { WWT_PANEL, RESIZE_RB, COLOUR_GREY, 0, 345, 14, 137, 0x0, STR_NULL},
00149 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_GREY, 346, 357, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00150 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_GREY, 346, 357, 126, 137, 0x0, STR_RESIZE_BUTTON},
00151 { WIDGETS_END},
00152 };
00153
00154 static const WindowDesc _sign_list_desc = {
00155 WDP_AUTO, WDP_AUTO, 358, 138, 358, 138,
00156 WC_SIGN_LIST, WC_NONE,
00157 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00158 _sign_list_widget,
00159 };
00160
00161
00162 void ShowSignList()
00163 {
00164 AllocateWindowDescFront<SignListWindow>(&_sign_list_desc, 0);
00165 }
00166
00173 static bool RenameSign(SignID index, const char *text)
00174 {
00175 bool remove = StrEmpty(text);
00176 DoCommandP(0, index, 0, CMD_RENAME_SIGN | (StrEmpty(text) ? CMD_MSG(STR_CAN_T_DELETE_SIGN) : CMD_MSG(STR_280C_CAN_T_CHANGE_SIGN_NAME)), NULL, text);
00177 return remove;
00178 }
00179
00180 enum QueryEditSignWidgets {
00181 QUERY_EDIT_SIGN_WIDGET_TEXT = 3,
00182 QUERY_EDIT_SIGN_WIDGET_OK,
00183 QUERY_EDIT_SIGN_WIDGET_CANCEL,
00184 QUERY_EDIT_SIGN_WIDGET_DELETE,
00185 QUERY_EDIT_SIGN_WIDGET_PREVIOUS = QUERY_EDIT_SIGN_WIDGET_DELETE + 2,
00186 QUERY_EDIT_SIGN_WIDGET_NEXT,
00187 };
00188
00189 struct SignWindow : QueryStringBaseWindow, SignList {
00190 SignID cur_sign;
00191
00192 SignWindow(const WindowDesc *desc, const Sign *si) : QueryStringBaseWindow(MAX_LENGTH_SIGN_NAME_BYTES, desc)
00193 {
00194 this->caption = STR_280B_EDIT_SIGN_TEXT;
00195 this->afilter = CS_ALPHANUMERAL;
00196 this->LowerWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
00197
00198 UpdateSignEditWindow(si);
00199 this->SetFocusedWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
00200 this->FindWindowPlacementAndResize(desc);
00201 }
00202
00203 void UpdateSignEditWindow(const Sign *si)
00204 {
00205 char *last_of = &this->edit_str_buf[this->edit_str_size - 1];
00206
00207
00208 if (si->name != NULL) {
00209 SetDParam(0, si->index);
00210 GetString(this->edit_str_buf, STR_SIGN_NAME, last_of);
00211 } else {
00212 GetString(this->edit_str_buf, STR_EMPTY, last_of);
00213 }
00214 *last_of = '\0';
00215
00216 this->cur_sign = si->index;
00217 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, MAX_LENGTH_SIGN_NAME_PIXELS);
00218
00219 this->InvalidateWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
00220 this->SetFocusedWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
00221 }
00222
00228 const Sign *PrevNextSign(bool next)
00229 {
00230
00231 this->signs.ForceRebuild();
00232 this->signs.NeedResort();
00233 this->BuildSignsList();
00234 this->SortSignsList();
00235
00236
00237
00238
00239 uint end = this->signs.Length() - (next ? 1 : 0);
00240 for (uint i = next ? 0 : 1; i < end; i++) {
00241 if (this->cur_sign == this->signs[i]->index) {
00242
00243 return this->signs[i + (next ? 1 : -1)];
00244 }
00245 }
00246
00247 return this->signs[next ? 0 : this->signs.Length() - 1];
00248 }
00249
00250 virtual void OnPaint()
00251 {
00252 SetDParam(0, this->caption);
00253 this->DrawWidgets();
00254 this->DrawEditBox(QUERY_EDIT_SIGN_WIDGET_TEXT);
00255 }
00256
00257 virtual void OnClick(Point pt, int widget)
00258 {
00259 switch (widget) {
00260 case QUERY_EDIT_SIGN_WIDGET_PREVIOUS:
00261 case QUERY_EDIT_SIGN_WIDGET_NEXT: {
00262 const Sign *si = this->PrevNextSign(widget == QUERY_EDIT_SIGN_WIDGET_NEXT);
00263
00264
00265 this->signs.ForceRebuild();
00266 this->signs.NeedResort();
00267 this->BuildSignsList();
00268 this->SortSignsList();
00269
00270
00271 ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
00272 UpdateSignEditWindow(si);
00273 break;
00274 }
00275
00276 case QUERY_EDIT_SIGN_WIDGET_DELETE:
00277
00278 RenameSign(this->cur_sign, "");
00279
00280 break;
00281
00282 case QUERY_EDIT_SIGN_WIDGET_OK:
00283 if (RenameSign(this->cur_sign, this->text.buf)) break;
00284
00285
00286 case QUERY_EDIT_SIGN_WIDGET_CANCEL:
00287 delete this;
00288 break;
00289 }
00290 }
00291
00292 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00293 {
00294 EventState state = ES_NOT_HANDLED;
00295 switch (this->HandleEditBoxKey(QUERY_EDIT_SIGN_WIDGET_TEXT, key, keycode, state)) {
00296 default: break;
00297
00298 case HEBR_CONFIRM:
00299 if (RenameSign(this->cur_sign, this->text.buf)) break;
00300
00301
00302 case HEBR_CANCEL:
00303 delete this;
00304 break;
00305 }
00306 return state;
00307 }
00308
00309 virtual void OnMouseLoop()
00310 {
00311 this->HandleEditBox(QUERY_EDIT_SIGN_WIDGET_TEXT);
00312 }
00313
00314 virtual void OnOpenOSKWindow(int wid)
00315 {
00316 ShowOnScreenKeyboard(this, wid, QUERY_EDIT_SIGN_WIDGET_CANCEL, QUERY_EDIT_SIGN_WIDGET_OK);
00317 }
00318 };
00319
00320 static const Widget _query_sign_edit_widgets[] = {
00321 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00322 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 259, 0, 13, STR_012D, STR_NULL },
00323 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 259, 14, 29, STR_NULL, STR_NULL },
00324 { WWT_EDITBOX, RESIZE_NONE, COLOUR_GREY, 2, 257, 16, 27, STR_SIGN_OSKTITLE, STR_NULL },
00325 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 0, 60, 30, 41, STR_012F_OK, STR_NULL },
00326 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 61, 120, 30, 41, STR_012E_CANCEL, STR_NULL },
00327 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 121, 180, 30, 41, STR_0290_DELETE, STR_NULL },
00328 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 181, 237, 30, 41, STR_NULL, STR_NULL },
00329 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 238, 248, 30, 41, STR_6819, STR_PREVIOUS_SIGN_TOOLTIP },
00330 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 249, 259, 30, 41, STR_681A, STR_NEXT_SIGN_TOOLTIP },
00331 { WIDGETS_END },
00332 };
00333
00334 static const WindowDesc _query_sign_edit_desc = {
00335 190, 170, 260, 42, 260, 42,
00336 WC_QUERY_STRING, WC_NONE,
00337 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_CONSTRUCTION,
00338 _query_sign_edit_widgets,
00339 };
00340
00341 void HandleClickOnSign(const Sign *si)
00342 {
00343 if (_ctrl_pressed && si->owner == _local_company) {
00344 RenameSign(si->index, NULL);
00345 return;
00346 }
00347 ShowRenameSignWindow(si);
00348 }
00349
00350 void ShowRenameSignWindow(const Sign *si)
00351 {
00352
00353 DeleteWindowById(WC_QUERY_STRING, 0);
00354
00355 new SignWindow(&_query_sign_edit_desc, si);
00356 }
00357
00358 void DeleteRenameSignWindow(SignID sign)
00359 {
00360 SignWindow *w = dynamic_cast<SignWindow *>(FindWindowById(WC_QUERY_STRING, 0));
00361
00362 if (w != NULL && w->cur_sign == sign) delete w;
00363 }