virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { Dimension d = {0, 0}; switch (widget) { default: return; case WID_SD_DAY: for (uint i = 0; i < 31; i++) { d = maxdim(d, GetStringBoundingBox(STR_ORDINAL_NUMBER_1ST + i)); } break; case WID_SD_MONTH: for (uint i = 0; i < 12; i++) { d = maxdim(d, GetStringBoundingBox(STR_MONTH_JAN + i)); } break; case WID_SD_YEAR: SetDParamMaxValue(0, this->max_year); d = maxdim(d, GetStringBoundingBox(STR_JUST_INT)); break; } d.width += padding.width; d.height += padding.height; *size = d; }
/** * 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)); this->column_size[VGC_NAME].width = max(170u, this->column_size[VGC_NAME].width); this->tiny_step_height = 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; return WD_FRAMERECT_LEFT + 8 + this->column_size[VGC_NAME].width + 8 + 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) { Dimension d; switch (widget) { case WID_S_LEFT: SetDParamMaxValue(0, MAX_YEAR * DAYS_IN_YEAR); d = GetStringBoundingBox(STR_WHITE_DATE_LONG); break; case WID_S_RIGHT: { 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 = GetStringBoundingBox(STR_COMPANY_MONEY); 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) { switch (widget) { case WID_VT_ARRIVAL_DEPARTURE_PANEL: SetDParamMaxValue(0, MAX_YEAR * DAYS_IN_YEAR); this->deparr_time_width = GetStringBoundingBox(STR_JUST_DATE_TINY).width; this->deparr_abbr_width = max(GetStringBoundingBox(STR_TIMETABLE_ARRIVAL_ABBREVIATION).width, GetStringBoundingBox(STR_TIMETABLE_DEPARTURE_ABBREVIATION).width); size->width = WD_FRAMERECT_LEFT + this->deparr_abbr_width + 10 + this->deparr_time_width + WD_FRAMERECT_RIGHT; /* FALL THROUGH */ case WID_VT_ARRIVAL_DEPARTURE_SELECTION: case WID_VT_TIMETABLE_PANEL: resize->height = FONT_HEIGHT_NORMAL; size->height = WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM; break; case WID_VT_SUMMARY_PANEL: size->height = WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; break; } }
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; } }
/** * 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) { 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 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; } } }