virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == MHW_BACKGROUND) { this->line_height = FONT_HEIGHT_NORMAL + 2; resize->height = this->line_height; SetDParam(0, ConvertYMDToDate(ORIGINAL_MAX_YEAR, 12, 30)); this->date_width = GetStringBoundingBox(STR_SHORT_DATE).width; size->height = 4 * resize->height + this->top_spacing + this->bottom_spacing; // At least 4 lines are visible. size->width = max(200u, size->width); // At least 200 pixels wide. } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_LI_BACKGROUND) return; size->height = WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM; for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { if (StrEmpty(this->landinfo_data[i])) break; uint width = GetStringBoundingBox(this->landinfo_data[i]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; size->width = max(size->width, width); size->height += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; if (i == 0) size->height += 4; } if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { uint width = GetStringBoundingBox(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; size->width = max(size->width, min(300u, width)); SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); size->height += GetStringHeight(STR_JUST_RAW_STRING, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { StringID str = STR_NULL; switch (widget) { case WID_N_CAPTION: { /* Caption is not a real caption (so that the window cannot be moved) * thus it doesn't get the default sizing of a caption. */ Dimension d2 = GetStringBoundingBox(STR_NEWS_MESSAGE_CAPTION); d2.height += WD_CAPTIONTEXT_TOP + WD_CAPTIONTEXT_BOTTOM; *size = maxdim(*size, d2); return; } case WID_N_MGR_FACE: *size = maxdim(*size, GetSpriteSize(SPR_GRADIENT)); break; case WID_N_MESSAGE: CopyInDParam(0, this->ni->params, lengthof(this->ni->params)); str = this->ni->string_id; break; case WID_N_COMPANY_MSG: str = this->GetCompanyMessageString(); break; case WID_N_VEH_NAME: case WID_N_VEH_TITLE: str = this->GetNewVehicleMessageString(widget); break; case WID_N_VEH_INFO: { assert(this->ni->reftype1 == NR_ENGINE); EngineID engine = this->ni->ref1; str = GetEngineInfoString(engine); break; } default: return; // Do nothing } /* Update minimal size with length of the multi-line string. */ Dimension d = *size; d.width = (d.width >= padding.width) ? d.width - padding.width : 0; d.height = (d.height >= padding.height) ? d.height - padding.height : 0; d = GetStringMultiLineBoundingBox(str, d); d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_MTS_PLAYLIST: { Dimension d = {0, 0}; for (int i = 0; i < 6; i++) { SetDParam(0, STR_MUSIC_PLAYLIST_ALL + i); d = maxdim(d, GetStringBoundingBox(STR_PLAYLIST_PROGRAM)); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_MTS_LIST_LEFT: case WID_MTS_LIST_RIGHT: { Dimension d = {0, 0}; for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { const char *song_name = GetSongName(i); if (StrEmpty(song_name)) continue; SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, GetSongName(i)); d = maxdim(d, GetStringBoundingBox(STR_PLAYLIST_TRACK_NAME)); } resize->height = GetMinSizing(NWST_STEP, d.height); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height = 7 * resize->height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); break; } } }
/** * Compute tiny_step_height and column_size * @return Total width required for the group list. */ uint ComputeGroupInfoSize() { this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype)); /* We consider the max average length of characters to be the one of "a" */ this->column_size[VGC_NAME].width = max(GetCharacterWidth(FS_NORMAL, 97) * (MAX_LENGTH_GROUP_NAME_CHARS - 4), this->column_size[VGC_NAME].width); this->tiny_step_height = max(11U, this->column_size[VGC_NAME].height); this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROTECT].height); this->column_size[VGC_AUTOREPLACE] = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height); this->column_size[VGC_PROFIT].width = 0; this->column_size[VGC_PROFIT].height = 0; static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT}; for (uint i = 0; i < lengthof(profit_sprites); i++) { Dimension d = GetSpriteSize(profit_sprites[i]); this->column_size[VGC_PROFIT] = maxdim(this->column_size[VGC_PROFIT], d); } this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROFIT].height); SetDParamMaxValue(0, GroupStatistics::Get(this->vli.company, ALL_GROUP, this->vli.vtype).num_vehicle, 3, FS_SMALL); this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_TINY_COMMA); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_NUMBER].height); this->tiny_step_height += WD_MATRIX_TOP; this->tiny_step_height = GetMinSizing(NWST_STEP, this->tiny_step_height); return WD_FRAMERECT_LEFT + 8 + this->column_size[VGC_NAME].width + 2 + this->column_size[VGC_PROTECT].width + 2 + this->column_size[VGC_AUTOREPLACE].width + 2 + this->column_size[VGC_PROFIT].width + 2 + this->column_size[VGC_NUMBER].width + 2 + WD_FRAMERECT_RIGHT; }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case MTSW_PLAYLIST: { Dimension d = {0, 0}; for (int i = 0; i < 6; i++) { SetDParam(0, STR_MUSIC_PLAYLIST_ALL + i); d = maxdim(d, GetStringBoundingBox(STR_PLAYLIST_PROGRAM)); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case MTSW_LIST_LEFT: case MTSW_LIST_RIGHT: { Dimension d = {0, 0}; for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { const char *song_name = GetSongName(i); if (StrEmpty(song_name)) continue; SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, GetSongName(i)); Dimension d2 = GetStringBoundingBox(STR_PLAYLIST_TRACK_NAME); d.width = max(d.width, d2.width); d.height += d2.height; } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } } }
/** * Engine drawing loop * @param type Type of vehicle (VEH_*) * @param l The left most location of the list * @param r The right most location of the list * @param y The top most location of the list * @param eng_list What engines to draw * @param min where to start in the list * @param max where in the list to end * @param selected_id what engine to highlight as selected, if any * @param show_count Whether to show the amount of engines or not * @param selected_group the group to list the engines of */ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group) { static const int sprite_y_offsets[] = { -1, -1, -2, -2 }; /* Obligatory sanity checks! */ assert(max <= eng_list->Length()); bool rtl = _current_text_dir == TD_RTL; int step_size = GetEngineListHeight(type); int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left; int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right; int sprite_width = sprite_left + sprite_right; int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1; int sprite_y_offset = sprite_y_offsets[type] + step_size / 2; Dimension replace_icon = {0, 0}; int count_width = 0; if (show_count) { replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); SetDParamMaxDigits(0, 3); count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width; } int text_left = l + (rtl ? WD_FRAMERECT_LEFT + replace_icon.width + 8 + count_width : sprite_width + WD_FRAMETEXT_LEFT); int text_right = r - (rtl ? sprite_width + WD_FRAMETEXT_RIGHT : WD_FRAMERECT_RIGHT + replace_icon.width + 8 + count_width); int replace_icon_left = rtl ? l + WD_FRAMERECT_LEFT : r - WD_FRAMERECT_RIGHT - replace_icon.width; int count_left = l; int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8; int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2; int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1; int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1; for (; min < max; min++, y += step_size) { const EngineID engine = (*eng_list)[min]; /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); SetDParam(0, engine); DrawString(text_left, text_right, y + normal_text_y_offset, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK, SA_STRIP | (rtl ? SA_RIGHT : SA_LEFT)); DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); if (show_count) { SetDParam(0, num_engines); DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, y + replace_icon_y_offset); } } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { Dimension d; switch (widget) { /* Left and right should have same sizing. */ case WID_S_LEFT: case WID_S_RIGHT: { SetDParamMaxValue(0, MAX_YEAR * DAYS_IN_YEAR); d = GetStringBoundingBox(STR_WHITE_DATE_LONG); int64 max_money = UINT32_MAX; const Company *c; FOR_ALL_COMPANIES(c) max_money = max<int64>(c->money, max_money); SetDParam(0, 100LL * max_money); d = maxdim(d, GetStringBoundingBox(STR_COMPANY_MONEY)); break; } case WID_S_MIDDLE: d = GetStringBoundingBox(STR_STATUSBAR_AUTOSAVE); d = maxdim(d, GetStringBoundingBox(STR_STATUSBAR_PAUSED)); if (Company::IsValidID(_local_company)) { SetDParam(0, _local_company); d = maxdim(d, GetStringBoundingBox(STR_STATUSBAR_COMPANY_NAME)); } break; default: return; } d.width += padding.width; d.height += padding.height; *size = maxdim(d, *size); }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_A_SCROLLING_TEXT) return; this->line_height = FONT_HEIGHT_NORMAL; Dimension d; d.height = this->line_height * num_visible_lines; d.width = 0; for (uint i = 0; i < lengthof(_credits); i++) { d.width = max(d.width, GetStringBoundingBox(_credits[i]).width); } *size = maxdim(*size, d); }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_MH_BACKGROUND) { this->line_height = FONT_HEIGHT_NORMAL + 2; resize->height = this->line_height; /* Months are off-by-one, so it's actually 8. Not using * month 12 because the 1 is usually less wide. */ SetDParam(0, ConvertYMDToDate(ORIGINAL_MAX_YEAR, 7, 30)); this->date_width = GetStringBoundingBox(STR_SHORT_DATE).width; size->height = 4 * resize->height + this->top_spacing + this->bottom_spacing; // At least 4 lines are visible. size->width = max(200u, size->width); // At least 200 pixels wide. } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SGI_TRANSLATION: { SetDParam(0, _current_language->missing); int height = GetStringHeight(STR_INTRO_TRANSLATION, size->width); if (height > 3 * FONT_HEIGHT_NORMAL) { /* Don't let the window become too high. */ Dimension textdim = GetStringBoundingBox(STR_INTRO_TRANSLATION); textdim.height *= 3; textdim.width -= textdim.width / 2; *size = maxdim(*size, textdim); } else { size->height = height + padding.height; } break; } } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != CW_PANEL) return; uint width = 0; for (int i = 0; i != lengthof(_cheats_ui); i++) { const CheatEntry *ce = &_cheats_ui[i]; switch (ce->type) { case SLE_BOOL: SetDParam(0, STR_CONFIG_SETTING_ON); width = max(width, GetStringBoundingBox(ce->str).width); SetDParam(0, STR_CONFIG_SETTING_OFF); width = max(width, GetStringBoundingBox(ce->str).width); break; default: switch (ce->str) { /* Display date for change date cheat */ case STR_CHEAT_CHANGE_DATE: SetDParam(0, ConvertYMDToDate(MAX_YEAR, 11, 31)); width = max(width, GetStringBoundingBox(ce->str).width); break; /* Draw coloured flag for change company cheat */ case STR_CHEAT_CHANGE_COMPANY: SetDParam(0, 15); width = max(width, GetStringBoundingBox(ce->str).width + 10 + 10); break; /* Set correct string for switch climate cheat */ case STR_CHEAT_SWITCH_CLIMATE: for (StringID i = STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE; i <= STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE; i++) { SetDParam(0, i); width = max(width, GetStringBoundingBox(ce->str).width); } break; default: SetDParam(0, INT64_MAX); width = max(width, GetStringBoundingBox(ce->str).width); break; } break; } } size->width = width + 50 /* stuff on the left */ + 10 /* extra spacing on right */; this->header_height = GetStringHeight(STR_CHEATS_WARNING, size->width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT) + WD_PAR_VSEP_WIDE; size->height = this->header_height + WD_FRAMERECT_TOP + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_BOTTOM + (FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL) * lengthof(_cheats_ui); }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SIL_LIST: { Dimension spr_dim = GetSpriteSize(SPR_COMPANY_ICON); this->text_offset = WD_FRAMETEXT_LEFT + spr_dim.width + 2; // 2 pixels space between icon and the sign text. resize->height = max<uint>(FONT_HEIGHT_NORMAL, spr_dim.height); Dimension d = {this->text_offset + WD_FRAMETEXT_RIGHT, WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM}; *size = maxdim(*size, d); break; } case WID_SIL_CAPTION: SetDParamMaxValue(0, Sign::GetPoolSize(), 3); *size = GetStringBoundingBox(STR_SIGN_LIST_CAPTION); size->height += padding.height; size->width += padding.width; break; } }
static bool DrawScrollingStatusText(const NewsItem *ni, int scroll_pos, int left, int right, int top, int bottom) { CopyInDParam(0, ni->params, lengthof(ni->params)); StringID str = ni->string_id; char buf[512]; GetString(buf, str, lastof(buf)); const char *s = buf; char buffer[256]; char *d = buffer; const char *last = lastof(buffer); for (;;) { WChar c = Utf8Consume(&s); if (c == 0) { break; } else if (c == '\n') { if (d + 4 >= last) break; d[0] = d[1] = d[2] = d[3] = ' '; d += 4; } else if (IsPrintable(c)) { if (d + Utf8CharLen(c) >= last) break; d += Utf8Encode(d, c); } } *d = '\0'; DrawPixelInfo tmp_dpi; if (!FillDrawPixelInfo(&tmp_dpi, left, top, right - left, bottom)) return true; int width = GetStringBoundingBox(buffer).width; int pos = (_current_text_dir == TD_RTL) ? (scroll_pos - width) : (right - scroll_pos - left); DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; DrawString(pos, INT16_MAX, 0, buffer, TC_LIGHT_BLUE, SA_LEFT | SA_FORCE); _cur_dpi = old_dpi; return (_current_text_dir == TD_RTL) ? (pos < right - left) : (pos + width > 0); }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SL_BACKGROUND: size->height = 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; break; case WID_SL_DRIVES_DIRECTORIES_LIST: resize->height = FONT_HEIGHT_NORMAL; size->height = resize->height * 10 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; break; case WID_SL_SORT_BYNAME: case WID_SL_SORT_BYDATE: { Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data); d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { /* We cache the button size. This is safe as no reinit can happen here. */ if (this->button_size.width == 0) { this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT)); this->button_size.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; this->button_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; } switch (widget) { case WID_BAFD_QUESTION: /* The question is twice as wide as the buttons, and determine the height based on the width. */ size->width = this->button_size.width * 2; size->height = GetStringHeight(STR_MISSING_GRAPHICS_SET_MESSAGE, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT) + WD_FRAMETEXT_BOTTOM + WD_FRAMETEXT_TOP; break; case WID_BAFD_YES: case WID_BAFD_NO: *size = this->button_size; break; } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_BO_CLASS_LIST: { for (uint i = 0; i < ObjectClass::GetClassCount(); i++) { ObjectClass *objclass = ObjectClass::Get((ObjectClassID)i); if (objclass->GetUISpecCount() == 0) continue; size->width = max(size->width, GetStringBoundingBox(objclass->name).width); } size->width += padding.width; this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->height = this->line_height; size->height = 5 * this->line_height; break; } case WID_BO_OBJECT_NAME: case WID_BO_OBJECT_SIZE: /* We do not want the window to resize when selecting objects; better clip texts */ size->width = 0; break; case WID_BO_OBJECT_MATRIX: { /* Get the right amount of buttons based on the current spec. */ const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); if (spec != NULL) { if (spec->views >= 2) size->width += resize->width; if (spec->views >= 4) size->height += resize->height; } resize->width = 0; resize->height = 0; break; } case WID_BO_OBJECT_SPRITE: { bool two_wide = false; // Whether there will be two widgets next to each other in the matrix or not. int height[2] = {0, 0}; // The height for the different views; in this case views 1/2 and 4. /* Get the height and view information. */ for (int i = 0; i < NUM_OBJECTS; i++) { const ObjectSpec *spec = ObjectSpec::Get(i); if (!spec->IsEverAvailable()) continue; two_wide |= spec->views >= 2; height[spec->views / 4] = max<int>(ObjectSpec::Get(i)->height, height[spec->views / 4]); } /* Determine the pixel heights. */ for (size_t i = 0; i < lengthof(height); i++) { height[i] *= ScaleGUITrad(TILE_HEIGHT); height[i] += ScaleGUITrad(TILE_PIXELS) + 2 * OBJECT_MARGIN; } /* Now determine the size of the minimum widgets. When there are two columns, then * we want these columns to be slightly less wide. When there are two rows, then * determine the size of the widgets based on the maximum size for a single row * of widgets, or just the twice the widget height of the two row ones. */ size->height = max(height[0], height[1] * 2 + 2); if (two_wide) { size->width = (3 * ScaleGUITrad(TILE_PIXELS) + 2 * OBJECT_MARGIN) * 2 + 2; } else { size->width = 4 * ScaleGUITrad(TILE_PIXELS) + 2 * OBJECT_MARGIN; } /* Get the right size for the single widget based on the current spec. */ const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); if (spec != NULL) { if (spec->views >= 2) size->width = size->width / 2 - 1; if (spec->views >= 4) size->height = size->height / 2 - 1; } break; } case WID_BO_INFO: size->height = this->info_height; break; case WID_BO_SELECT_MATRIX: fill->height = 1; resize->height = 1; break; case WID_BO_SELECT_IMAGE: size->width = ScaleGUITrad(64) + 2; size->height = ScaleGUITrad(58) + 2; break; default: break; } }
/** Update pixel width of the text. */ void Textbuf::UpdateWidth() { this->pixels = GetStringBoundingBox(this->buf, FS_NORMAL).width; }
uint DropDownListCharStringItem::Width() const { return GetStringBoundingBox(this->string).width; }
uint DropDownListStringItem::Width() const { char buffer[512]; GetString(buffer, this->String(), lastof(buffer)); return GetStringBoundingBox(buffer).width; }
virtual void DrawWidget(const Rect &r, int widget) const { if (widget != CW_PANEL) return; int y = r.top + WD_FRAMERECT_TOP + this->header_height; DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, y, STR_CHEATS_WARNING, TC_FROMSTRING, SA_CENTER); bool rtl = _current_text_dir == TD_RTL; uint box_left = rtl ? r.right - 12 : r.left + 5; uint button_left = rtl ? r.right - 40 : r.left + 20; uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT: 50); uint text_right = r.right - (rtl ? 50 : WD_FRAMERECT_RIGHT); for (int i = 0; i != lengthof(_cheats_ui); i++) { const CheatEntry *ce = &_cheats_ui[i]; DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, box_left, y + 2); switch (ce->type) { case SLE_BOOL: { bool on = (*(bool*)ce->variable); DrawFrameRect(button_left, y + 1, button_left + 20 - 1, y + FONT_HEIGHT_NORMAL - 1, on ? COLOUR_GREEN : COLOUR_RED, on ? FR_LOWERED : FR_NONE); SetDParam(0, on ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); break; } default: { int32 val = (int32)ReadValue(ce->variable, ce->type); char buf[512]; /* Draw [<][>] boxes for settings of an integer-type */ DrawArrowButtons(button_left, y, COLOUR_YELLOW, clicked - (i * 2), true, true); switch (ce->str) { /* Display date for change date cheat */ case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break; /* Draw coloured flag for change company cheat */ case STR_CHEAT_CHANGE_COMPANY: { SetDParam(0, val + 1); GetString(buf, STR_CHEAT_CHANGE_COMPANY, lastof(buf)); uint offset = 10 + GetStringBoundingBox(buf).width; DrawCompanyIcon(_local_company, rtl ? text_right - offset - 10 : text_left + offset, y + 2); break; } /* Set correct string for switch climate cheat */ case STR_CHEAT_SWITCH_CLIMATE: val += STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE; /* FALL THROUGH */ default: SetDParam(0, val); } break; } } DrawString(text_left, text_right, y + 1, ce->str); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; } }
void DeparturesWindow<Twaypoint>::DrawDeparturesListItems(const Rect &r) const { int left = r.left + WD_MATRIX_LEFT; int right = r.right - WD_MATRIX_RIGHT; bool rtl = _current_text_dir == TD_RTL; bool ltr = !rtl; int text_offset = WD_FRAMERECT_RIGHT; int text_left = left + (rtl ? 0 : text_offset); int text_right = right - (rtl ? text_offset : 0); int y = r.top + 1; uint max_departures = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->departures->Length() + this->arrivals->Length()); if (max_departures > _settings_client.gui.max_departures) { max_departures = _settings_client.gui.max_departures; } byte small_font_size = _settings_client.gui.departure_larger_font ? FONT_HEIGHT_NORMAL : FONT_HEIGHT_SMALL; /* Draw the black background. */ GfxFillRect(r.left + 1, r.top, r.right - 1, r.bottom, PC_BLACK); /* Nothing selected? Then display the information text. */ bool none_selected[2] = {true, true}; for (uint i = 0; i < 4; ++i) { if (this->show_types[i]) { none_selected[0] = false; break; } } for (uint i = 0; i < 2; ++i) { if (this->departure_types[i]) { none_selected[1] = false; break; } } if (none_selected[0] || none_selected[1]) { DrawString(text_left, text_right, y + 1, STR_DEPARTURES_NONE_SELECTED); return; } /* No scheduled departures? Then display the information text. */ if (max_departures == 0) { DrawString(text_left, text_right, y + 1, STR_DEPARTURES_EMPTY); return; } /* Find the maximum possible width of the departure time and "Expt <time>" fields. */ int time_width = cached_date_width; if (!_settings_client.gui.departure_show_both) { time_width += (departure_types[0] && departure_types[1] ? cached_date_arrow_width : 0); } /* Vehicle type icon */ int type_width = _settings_client.gui.departure_show_vehicle_type ? (GetStringBoundingBox(STR_DEPARTURES_TYPE_PLANE)).width : 0; /* Find the maximum width of the status field */ int status_width = cached_status_width; /* Find the width of the "Calling at:" field. */ int calling_at_width = (GetStringBoundingBox(_settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT)).width; /* Find the maximum company name width. */ int toc_width = 0; /* Find the maximum group name width. */ int group_width = 0; /* Find the maximum vehicle name width. */ int veh_width = 0; if (_settings_client.gui.departure_show_vehicle || _settings_client.gui.departure_show_company || _settings_client.gui.departure_show_group) { for (uint i = 0; i < 4; ++i) { VehicleList vehicles; /* MAX_COMPANIES is probably the wrong thing to put here, but it works. GenerateVehicleSortList doesn't check the company when the type of list is VL_STATION_LIST (r20801). */ if (!GenerateVehicleSortList(&vehicles, VehicleListIdentifier(VL_STATION_LIST, (VehicleType)(VEH_TRAIN + i), MAX_COMPANIES, station).Pack())) { /* Something went wrong: panic! */ continue; } for (const Vehicle **v = vehicles.Begin(); v != vehicles.End(); v++) { SetDParam(0, (uint64)((*v)->index)); int width = (GetStringBoundingBox(STR_DEPARTURES_VEH)).width; if (_settings_client.gui.departure_show_vehicle && width > veh_width) veh_width = width; if ((*v)->group_id != INVALID_GROUP && (*v)->group_id != DEFAULT_GROUP) { SetDParam(0, (uint64)((*v)->group_id)); width = (GetStringBoundingBox(STR_DEPARTURES_GROUP)).width; if (_settings_client.gui.departure_show_group && width > group_width) group_width = width; } SetDParam(0, (uint64)((*v)->owner)); width = (GetStringBoundingBox(STR_DEPARTURES_TOC)).width; if (_settings_client.gui.departure_show_company && width > toc_width) toc_width = width; } } } uint departure = 0; uint arrival = 0; /* Draw each departure. */ for (uint i = 0; i < max_departures; ++i) { const Departure *d; if (arrival == this->arrivals->Length()) { d = (*(this->departures))[departure++]; } else if (departure == this->departures->Length()) { d = (*(this->arrivals))[arrival++]; } else { d = (*(this->departures))[departure]; const Departure *a = (*(this->arrivals))[arrival]; if (a->scheduled_date < d->scheduled_date) { d = a; arrival++; } else { departure++; } } if (i < this->vscroll->GetPosition()) { continue; } /* If for some reason the departure is too far in the future or is at a negative time, skip it. */ if ((d->scheduled_date / DAY_TICKS) > (_date + _settings_client.gui.max_departure_time) || d->scheduled_date < 0) { continue; } if (d->terminus == INVALID_STATION) continue; StringID time_str = (departure_types[0] && departure_types[1]) ? (d->type == D_DEPARTURE ? STR_DEPARTURES_TIME_DEP : STR_DEPARTURES_TIME_ARR) : STR_DEPARTURES_TIME; if (_settings_client.gui.departure_show_both) time_str = STR_DEPARTURES_TIME_BOTH; /* Time */ SetDParam(0, d->scheduled_date); SetDParam(1, d->scheduled_date - d->order->wait_time); ltr ? DrawString( text_left, text_left + time_width, y + 1, time_str) : DrawString(text_right - time_width, text_right, y + 1, time_str); /* Vehicle type icon, with thanks to sph */ if (_settings_client.gui.departure_show_vehicle_type) { StringID type = STR_DEPARTURES_TYPE_TRAIN; int offset = (_settings_client.gui.departure_show_vehicle_color ? 1 : 0); switch (d->vehicle->type) { case VEH_TRAIN: type = STR_DEPARTURES_TYPE_TRAIN; break; case VEH_ROAD: type = IsCargoInClass(d->vehicle->cargo_type, CC_PASSENGERS) ? STR_DEPARTURES_TYPE_BUS : STR_DEPARTURES_TYPE_LORRY; break; case VEH_SHIP: type = STR_DEPARTURES_TYPE_SHIP; break; case VEH_AIRCRAFT: type = STR_DEPARTURES_TYPE_PLANE; break; default: break; } type += offset; DrawString(text_left + time_width + 3, text_left + time_width + type_width + 3, y, type); } /* The icons to show with the destination and via stations. */ StringID icon = STR_DEPARTURES_STATION_NONE; StringID icon_via = STR_DEPARTURES_STATION_NONE; if (_settings_client.gui.departure_destination_type) { Station *t = Station::Get(d->terminus.station); if (t->facilities & FACIL_DOCK && t->facilities & FACIL_AIRPORT && d->vehicle->type != VEH_SHIP && d->vehicle->type != VEH_AIRCRAFT) { icon = STR_DEPARTURES_STATION_PORTAIRPORT; } else if (t->facilities & FACIL_DOCK && d->vehicle->type != VEH_SHIP) { icon = STR_DEPARTURES_STATION_PORT; } else if (t->facilities & FACIL_AIRPORT && d->vehicle->type != VEH_AIRCRAFT) { icon = STR_DEPARTURES_STATION_AIRPORT; } } if (_settings_client.gui.departure_destination_type && d->via != INVALID_STATION) { Station *t = Station::Get(d->via); if (t->facilities & FACIL_DOCK && t->facilities & FACIL_AIRPORT && d->vehicle->type != VEH_SHIP && d->vehicle->type != VEH_AIRCRAFT) { icon_via = STR_DEPARTURES_STATION_PORTAIRPORT; } else if (t->facilities & FACIL_DOCK && d->vehicle->type != VEH_SHIP) { icon_via = STR_DEPARTURES_STATION_PORT; } else if (t->facilities & FACIL_AIRPORT && d->vehicle->type != VEH_AIRCRAFT) { icon_via = STR_DEPARTURES_STATION_AIRPORT; } } /* Destination */ if (d->via == INVALID_STATION) { /* Only show the terminus. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS); } else { /* Show the terminus and the via station. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); SetDParam(2, d->via); SetDParam(3, icon_via); int text_width = (GetStringBoundingBox(STR_DEPARTURES_TERMINUS_VIA_STATION)).width; if (text_width < text_right - status_width - (toc_width + veh_width + group_width + 2) - 2 - (text_left + time_width + type_width + 6)) { /* They will both fit, so show them both. */ SetDParam(0, d->terminus.station); SetDParam(1, icon); SetDParam(2, d->via); SetDParam(3, icon_via); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION); } else { /* They won't both fit, so switch between showing the terminus and the via station approximately every 4 seconds. */ if (this->tick_count & (1 << 7)) { SetDParam(0, d->via); SetDParam(1, icon_via); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_VIA) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_VIA); } else { SetDParam(0, d->terminus.station); SetDParam(1, icon); ltr ? DrawString( text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA) : DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2, text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA); } } } /* Status */ { int status_left = ltr ? text_right - status_width - 2 - (toc_width + veh_width + group_width + 2) : text_left + (toc_width + veh_width + group_width + 2) + 7; int status_right = ltr ? text_right - (toc_width + veh_width + group_width + 2) + 2 : text_left + status_width + 2 + (toc_width + veh_width + group_width + 7); if (d->status == D_ARRIVED) { /* The vehicle has arrived. */ DrawString(status_left, status_right, y + 1, STR_DEPARTURES_ARRIVED); } else if(d->status == D_CANCELLED) { /* The vehicle has been cancelled. */ DrawString(status_left, status_right, y + 1, STR_DEPARTURES_CANCELLED); } else{ if (d->lateness <= DAY_TICKS && d->scheduled_date > ((_date * DAY_TICKS) + _date_fract)) { /* We have no evidence that the vehicle is late, so assume it is on time. */ DrawString(status_left, status_right, y + 1, STR_DEPARTURES_ON_TIME); } else { if ((d->scheduled_date + d->lateness) < ((_date * DAY_TICKS) + _date_fract)) { /* The vehicle was expected to have arrived by now, even if we knew it was going to be late. */ /* We assume that the train stays at least a day at a station so it won't accidentally be marked as delayed for a fraction of a day. */ DrawString(status_left, status_right, y + 1, STR_DEPARTURES_DELAYED); } else { /* The vehicle is expected to be late and is not yet due to arrive. */ SetDParam(0, d->scheduled_date + d->lateness); DrawString(status_left, status_right, y + 1, STR_DEPARTURES_EXPECTED); } } } } /* Vehicle name */ if (_settings_client.gui.departure_show_vehicle) { SetDParam(0, (uint64)(d->vehicle->index)); ltr ? DrawString(text_right - (toc_width + veh_width + group_width + 2), text_right - toc_width - group_width - 2, y + 1, STR_DEPARTURES_VEH) : DrawString( text_left + toc_width + group_width + 2, text_left + (toc_width + veh_width + group_width + 2), y + 1, STR_DEPARTURES_VEH); } /* Group name */ if (_settings_client.gui.departure_show_group && d->vehicle->group_id != INVALID_GROUP && d->vehicle->group_id != DEFAULT_GROUP) { SetDParam(0, (uint64)(d->vehicle->group_id)); ltr ? DrawString(text_right - (toc_width + group_width + 2), text_right - toc_width - 2, y + 1, STR_DEPARTURES_GROUP) : DrawString( text_left + toc_width + 2, text_left + (toc_width + group_width + 2), y + 1, STR_DEPARTURES_GROUP); } /* Operating company */ if (_settings_client.gui.departure_show_company) { SetDParam(0, (uint64)(d->vehicle->owner)); ltr ? DrawString(text_right - toc_width, text_right, y + 1, STR_DEPARTURES_TOC, TC_FROMSTRING, SA_RIGHT) : DrawString( text_left, text_left + toc_width, y + 1, STR_DEPARTURES_TOC, TC_FROMSTRING, SA_LEFT); } int bottom_y = y + this->entry_height - small_font_size - (_settings_client.gui.departure_larger_font ? 1 : 3); /* Calling at */ ltr ? DrawString( text_left, text_left + calling_at_width, bottom_y, _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT) : DrawString(text_right - calling_at_width, text_right, bottom_y, _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT); /* List of stations */ /* RTL languages can be handled in the language file, e.g. by having the following: */ /* STR_DEPARTURES_CALLING_AT_STATION :{STATION}, {RAW_STRING} */ /* STR_DEPARTURES_CALLING_AT_LAST_STATION :{STATION} & {RAW_STRING}*/ char buffer[512], scratch[512]; if (d->calling_at.Length() != 0) { SetDParam(0, (uint64)(*d->calling_at.Get(0)).station); GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch)); StationID continuesTo = INVALID_STATION; if (d->calling_at.Get(0)->station == d->terminus.station && d->calling_at.Length() > 1) { continuesTo = d->calling_at.Get(d->calling_at.Length() - 1)->station; } else if (d->calling_at.Length() > 1) { /* There's more than one stop. */ uint i; /* For all but the last station, write out ", <station>". */ for (i = 1; i < d->calling_at.Length() - 1; ++i) { StationID s = d->calling_at.Get(i)->station; if (s == d->terminus.station) { continuesTo = d->calling_at.Get(d->calling_at.Length() - 1)->station; break; } SetDParam(0, (uint64)scratch); SetDParam(1, (uint64)s); GetString(buffer, STR_DEPARTURES_CALLING_AT_STATION, lastof(buffer)); strncpy(scratch, buffer, sizeof(scratch)); } /* Finally, finish off with " and <station>". */ SetDParam(0, (uint64)scratch); SetDParam(1, (uint64)d->calling_at.Get(i)->station); GetString(buffer, STR_DEPARTURES_CALLING_AT_LAST_STATION, lastof(buffer)); strncpy(scratch, buffer, sizeof(scratch)); } SetDParam(0, (uint64)scratch); StringID string; if (continuesTo == INVALID_STATION) { string = _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LIST_LARGE : STR_DEPARTURES_CALLING_AT_LIST; } else { SetDParam(1, continuesTo); string = _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS_LARGE : STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS; } GetString(buffer, string, lastof(buffer)); } else { buffer[0] = 0; //SetDParam(0, d->terminus); //GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch)); } int list_width = (GetStringBoundingBox(buffer, _settings_client.gui.departure_larger_font ? FS_NORMAL : FS_SMALL)).width; /* Draw the whole list if it will fit. Otherwise scroll it. */ if (list_width < text_right - (text_left + calling_at_width + 2)) { ltr ? DrawString(text_left + calling_at_width + 2, text_right, bottom_y, buffer) : DrawString( text_left, text_right - calling_at_width - 2, bottom_y, buffer); } else { DrawPixelInfo tmp_dpi; if (ltr ? !FillDrawPixelInfo(&tmp_dpi, text_left + calling_at_width + 2, bottom_y, text_right - (text_left + calling_at_width + 2), small_font_size + 3) : !FillDrawPixelInfo(&tmp_dpi, text_left , bottom_y, text_right - (text_left + calling_at_width + 2), small_font_size + 3)) { y += this->entry_height; continue; } DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; /* The scrolling text starts out of view at the right of the screen and finishes when it is out of view at the left of the screen. */ int pos = ltr ? text_right - (this->tick_count % (list_width + text_right - text_left)) : text_left + (this->tick_count % (list_width + text_right - text_left)); ltr ? DrawString( pos, INT16_MAX, 0, buffer, TC_FROMSTRING, SA_LEFT | SA_FORCE) : DrawString(-INT16_MAX, pos, 0, buffer, TC_FROMSTRING, SA_RIGHT | SA_FORCE); _cur_dpi = old_dpi; } y += this->entry_height; } }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case BAIRW_CLASS_DROPDOWN: { Dimension d = {0, 0}; for (uint i = 0; i < AirportClass::GetCount(); i++) { SetDParam(0, AirportClass::GetName((AirportClassID)i)); d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case BAIRW_AIRPORT_LIST: { for (int i = 0; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; size->width = ::max(size->width, GetStringBoundingBox(as->name).width); } this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = this->vscroll->GetCapacity() * this->line_height; break; } case BAIRW_AIRPORT_SPRITE: for (int i = 0; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; for (byte layout = 0; layout < as->num_table; layout++) { SpriteID sprite = GetCustomAirportSprite(as, layout); if (sprite != 0) { Dimension d = GetSpriteSize(sprite); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(d, *size); } } } break; case BAIRW_EXTRA_TEXT: for (int i = NEW_AIRPORT_OFFSET; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; for (byte layout = 0; layout < as->num_table; layout++) { StringID string = GetAirportTextCallback(as, layout, CBID_AIRPORT_ADDITIONAL_TEXT); if (string == STR_UNDEFINED) continue; /* STR_BLACK_STRING is used to start the string with {BLACK} */ SetDParam(0, string); Dimension d = GetStringMultiLineBoundingBox(STR_BLACK_STRING, *size); *size = maxdim(d, *size); } } break; default: break; } }
virtual void DrawWidget(const Rect &r, int widget) const { const Vehicle *v = this->vehicle; int selected = this->sel_index; switch (widget) { case WID_VT_TIMETABLE_PANEL: { int y = r.top + WD_FRAMERECT_TOP; int i = this->vscroll->GetPosition(); VehicleOrderID order_id = (i + 1) / 2; bool final_order = false; bool rtl = _current_text_dir == TD_RTL; SetDParamMaxValue(0, v->GetNumOrders(), 2); int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3; int middle = rtl ? r.right - WD_FRAMERECT_RIGHT - index_column_width : r.left + WD_FRAMERECT_LEFT + index_column_width; const Order *order = v->GetOrder(order_id); while (order != NULL) { /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; if (i % 2 == 0) { DrawOrderString(v, order, order_id, y, i == selected, true, r.left + WD_FRAMERECT_LEFT, middle, r.right - WD_FRAMERECT_RIGHT); order_id++; if (order_id >= v->GetNumOrders()) { order = v->GetOrder(0); final_order = true; } else { order = order->next; } } else { StringID string; TextColour colour = (i == selected) ? TC_WHITE : TC_BLACK; if (order->IsType(OT_CONDITIONAL)) { string = STR_TIMETABLE_NO_TRAVEL; } else if (order->IsType(OT_IMPLICIT)) { string = STR_TIMETABLE_NOT_TIMETABLEABLE; colour = ((i == selected) ? TC_SILVER : TC_GREY) | TC_NO_SHADE; } else if (order->travel_time == 0) { string = order->max_speed != UINT16_MAX ? STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED : STR_TIMETABLE_TRAVEL_NOT_TIMETABLED; } else { SetTimetableParams(0, 1, order->travel_time); string = order->max_speed != UINT16_MAX ? STR_TIMETABLE_TRAVEL_FOR_SPEED : STR_TIMETABLE_TRAVEL_FOR; } SetDParam(2, order->max_speed); DrawString(rtl ? r.left + WD_FRAMERECT_LEFT : middle, rtl ? middle : r.right - WD_FRAMERECT_LEFT, y, string, colour); if (final_order) break; } i++; y += FONT_HEIGHT_NORMAL; } break; } case WID_VT_ARRIVAL_DEPARTURE_PANEL: { /* Arrival and departure times are handled in an all-or-nothing approach, * i.e. are only shown if we can calculate all times. * Excluding order lists with only one order makes some things easier. */ Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0; if (total_time <= 0 || v->GetNumOrders() <= 1 || !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) break; TimetableArrivalDeparture *arr_dep = AllocaM(TimetableArrivalDeparture, v->GetNumOrders()); const VehicleOrderID cur_order = v->cur_real_order_index % v->GetNumOrders(); VehicleOrderID earlyID = BuildArrivalDepartureList(v, arr_dep) ? cur_order : (VehicleOrderID)INVALID_VEH_ORDER_ID; int y = r.top + WD_FRAMERECT_TOP; bool show_late = this->show_expected && v->lateness_counter > DAY_TICKS; Ticks offset = show_late ? 0 : -v->lateness_counter; bool rtl = _current_text_dir == TD_RTL; int abbr_left = rtl ? r.right - WD_FRAMERECT_RIGHT - this->deparr_abbr_width : r.left + WD_FRAMERECT_LEFT; int abbr_right = rtl ? r.right - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT + this->deparr_abbr_width; int time_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_RIGHT - this->deparr_time_width; int time_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->deparr_time_width : r.right - WD_FRAMERECT_RIGHT; for (int i = this->vscroll->GetPosition(); i / 2 < v->GetNumOrders(); ++i) { // note: i is also incremented in the loop /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; if (i % 2 == 0) { if (arr_dep[i / 2].arrival != INVALID_TICKS) { DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_ARRIVAL_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK); if (this->show_expected && i / 2 == earlyID) { SetArrivalDepartParams(0, 1, arr_dep[i / 2].arrival); DrawString(time_left, time_right, y, STR_GREEN_STRING, i == selected ? TC_WHITE : TC_BLACK); } else { SetArrivalDepartParams(0, 1, arr_dep[i / 2].arrival + offset); DrawString(time_left, time_right, y, show_late ? STR_RED_STRING : STR_JUST_STRING, i == selected ? TC_WHITE : TC_BLACK); } } } else { if (arr_dep[i / 2].departure != INVALID_TICKS) { DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_DEPARTURE_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK); SetArrivalDepartParams(0, 1, arr_dep[i/2].departure + offset); DrawString(time_left, time_right, y, show_late ? STR_RED_STRING : STR_JUST_STRING, i == selected ? TC_WHITE : TC_BLACK); } } y += FONT_HEIGHT_NORMAL; } break; } case WID_VT_SUMMARY_PANEL: { int y = r.top + WD_FRAMERECT_TOP; Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0; if (total_time != 0) { SetTimetableParams(0, 1, total_time); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->orders.list->IsCompleteTimetable() ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE); } y += FONT_HEIGHT_NORMAL; if (v->timetable_start != 0) { /* We are running towards the first station so we can start the * timetable at the given time. */ SetDParam(0, STR_JUST_DATE_TINY); SetDParam(1, v->timetable_start); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_START_AT); } else if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) { /* We aren't running on a timetable yet, so how can we be "on time" * when we aren't even "on service"/"on duty"? */ DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_NOT_STARTED); } else if (v->lateness_counter == 0 || (!_settings_client.gui.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_ON_TIME); } else { SetTimetableParams(0, 1, abs(v->lateness_counter)); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE); } break; } } }
virtual void OnInit() { this->dim_message_opt.width = 0; this->dim_message_opt.height = 0; for (const StringID *str = message_opt; *str != INVALID_STRING_ID; str++) this->dim_message_opt = maxdim(this->dim_message_opt, GetStringBoundingBox(*str)); }