Index: dock_gui.c =================================================================== --- dock_gui.c (revision 6036) +++ dock_gui.c (working copy) @@ -179,7 +179,7 @@ case SLOPE_NE: tile_to += TileDiffXY( 1, 0); break; default: break; } - VpSetPresizeRange(tile_from, tile_to); + VpSetPresizeRange(tile_from, tile_to, false); } break; case WE_DESTROY: Index: lang/english.txt =================================================================== --- lang/english.txt (revision 6036) +++ lang/english.txt (working copy) @@ -2969,4 +2969,12 @@ STR_LARGE_AIRPORTS :{BLACK}Large airports STR_HUB_AIRPORTS :{BLACK}Hub airports STR_HELIPORTS :{BLACK}Helicopter airports + +############ Tooltip measurment + +STR_MEASURE_LENGTH :{BLACK}Length: {NUM} +STR_MEASURE_AREA :{BLACK}Area: {NUM} x {NUM} +STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Length: {NUM}{}Height difference: {NUM} m +STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Area: {NUM} x {NUM}{}Height difference: {NUM} m + ######## Index: misc_gui.c =================================================================== --- misc_gui.c (revision 6036) +++ misc_gui.c (working copy) @@ -36,6 +36,8 @@ FiosItem *_fios_list; int _saveload_mode; +#include + extern void GenerateLandscape(byte mode); extern void SwitchMode(int new_mode); @@ -637,34 +639,98 @@ static void TooltipsWndProc(Window *w, WindowEvent *e) { switch (e->event) { - case WE_PAINT: + case WE_PAINT: { + uint arg; GfxFillRect(0, 0, w->width - 1, w->height - 1, 0); GfxFillRect(1, 1, w->width - 2, w->height - 2, 0x44); + for (arg = 0; arg < WP(w,tooltips_d).params; arg++) { + SetDParam(arg, WP(w,tooltips_d).param[arg]); + } DrawStringMultiCenter((w->width >> 1), (w->height >> 1) - 5, WP(w,tooltips_d).string_id, 197); break; + } case WE_MOUSELOOP: - if (!_right_button_down) DeleteWindow(w); + if (WP(w,tooltips_d).params == 0) { + if (!_right_button_down) DeleteWindow(w); + } else { + if (!_left_button_down || !_shift_pressed) DeleteWindow(w); + } + break; } } -void GuiShowTooltips(StringID string_id) +/** +* Shows a tooltip +* @param string_id String to be displayed +* @param params (optional) up to 5 pieces of additional information that may be added to tooltip +*/ +void GuiShowTooltips(StringID string_id, ...) { + va_list va; char buffer[512]; Window *w; int right,bottom; - int x,y; + int x = -1; + int y = -1; + uint32 param[5]; + uint params = 0; + const char *string; if (string_id == 0) return; w = FindWindowById(WC_TOOLTIPS, 0); if (w != NULL) { - if (WP(w,tooltips_d).string_id == string_id) - return; + if (WP(w,tooltips_d).string_id == string_id) { + x = w->left; + y = w->top; + } DeleteWindow(w); } + va_start(va, string_id); + for (string = GetStringPtr(string_id); *string != '\0'; string++) { + switch ((byte)*string) { + case 0x84: + case 0x8B: + case 0x8E: + case 0x8F: + param[params] = va_arg(va, int); + SetDParam(params, param[params]); + params++; + break; + + case 0x85: + switch ((byte)*string++) { + case 3: + case 12: + case 16: + case 17: + case 18: + case 19: + case 20: + param[params] = va_arg(va, int); + SetDParam(params, param[params]); + params++; + break; + + default: + break; + } + + default: + break; + } + + if (params == lengthof(param)) break; + } + va_end(va); + + if (params != 0) //it's not a standard tooltip - it's a measurement + if (!_shift_pressed) + return; + GetString(buffer, string_id); right = GetStringWidth(buffer) + 4; @@ -674,8 +740,13 @@ bottom += ((right - 4) / 176) * 10; right = 200; } + if (string_id == STR_MEASURE_LENGTH_HEIGHTDIFF || string_id == STR_MEASURE_AREA_HEIGHTDIFF) { + bottom += 10; //we need an extra line for these strings. + } y = _cursor.pos.y + 30; + if (params != 0) //it's not a standard tooltip - it's a measurement, move it away so it won't obstruct dragging + y += 15; if (y < 22) y = 22; if (y > (_screen.height - 44) && (y-=52) > (_screen.height - 44)) @@ -686,10 +757,18 @@ if (x > (_screen.width - right)) x = _screen.width - right; w = AllocateWindow(x, y, right, bottom, TooltipsWndProc, WC_TOOLTIPS, _tooltips_widgets); + WP(w,tooltips_d).string_id = string_id; - w->flags4 &= ~WF_WHITE_BORDER_MASK; + if (x == -1 || y == -1) w->flags4 &= ~WF_WHITE_BORDER_MASK; w->widget[0].right = right; w->widget[0].bottom = bottom; + + WP(w,tooltips_d).param[0] = param[0]; + WP(w,tooltips_d).param[1] = param[1]; + WP(w,tooltips_d).param[2] = param[2]; + WP(w,tooltips_d).param[3] = param[3]; + WP(w,tooltips_d).param[4] = param[4]; + WP(w,tooltips_d).params = params; } Index: network_client.c =================================================================== --- network_client.c (revision 6036) +++ network_client.c (working copy) @@ -2,6 +2,7 @@ #include "stdafx.h" #include "debug.h" +#include "openttd.h" #include "string.h" #include "strings.h" #include "network_data.h" Index: network_server.c =================================================================== --- network_server.c (revision 6036) +++ network_server.c (working copy) @@ -2,6 +2,7 @@ #include "stdafx.h" #include "debug.h" +#include "openttd.h" #include "string.h" #include "strings.h" #include "network_data.h" Index: openttd.c =================================================================== --- openttd.c (revision 6036) +++ openttd.c (working copy) @@ -6,13 +6,13 @@ #include "debug.h" #include "driver.h" #include "saveload.h" -#include "strings.h" #include "map.h" #include "tile.h" #include "void_map.h" #define VARDEF #include "openttd.h" +#include "strings.h" #include "bridge_map.h" #include "functions.h" #include "mixer.h" Index: rail_gui.c =================================================================== --- rail_gui.c (revision 6036) +++ rail_gui.c (working copy) @@ -490,7 +490,7 @@ TileIndex tile = e->place.tile; DoCommand(tile, 0, 0, DC_AUTO, CMD_BUILD_TUNNEL); - VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); + VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile, true); } break; case WE_DESTROY: Index: road_gui.c =================================================================== --- road_gui.c (revision 6036) +++ road_gui.c (working copy) @@ -272,7 +272,7 @@ TileIndex tile = e->place.tile; DoCommand(tile, 0x200, 0, DC_AUTO, CMD_BUILD_TUNNEL); - VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); + VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile, true); break; } Index: strings.c =================================================================== --- strings.c (revision 6036) +++ strings.c (working copy) @@ -159,7 +159,7 @@ // the indices will be reused. static int _bind_index; -static const char *GetStringPtr(StringID string) +const char *GetStringPtr(StringID string) { return _langpack_offs[_langtab_start[string >> 11] + (string & 0x7FF)]; } Index: strings.h =================================================================== --- strings.h (revision 6036) +++ strings.h (working copy) @@ -11,6 +11,7 @@ return buf; } +const char *GetStringPtr(StringID string); char *GetString(char *buffr, uint16 string); char *GetStringWithArgs(char *buffr, uint string, const int32 *argv); Index: variables.h =================================================================== --- variables.h (revision 6036) +++ variables.h (working copy) @@ -283,7 +283,7 @@ VARDEF uint32 _pressed_key; // Low 8 bits = ASCII, High 16 bits = keycode VARDEF bool _ctrl_pressed; // Is Ctrl pressed? -VARDEF bool _shift_pressed; // Is Alt pressed? +VARDEF bool _shift_pressed; // Is Shift pressed? VARDEF byte _dirkeys; // 1=left, 2=up, 4=right, 8=down VARDEF bool _fullscreen; Index: viewport.c =================================================================== --- viewport.c (revision 6036) +++ viewport.c (working copy) @@ -1923,13 +1923,36 @@ _thd.sizelimit = limit; } -void VpSetPresizeRange(uint from, uint to) +/** +* Highlights all tiles between set two tiles. Used in dock and tunnel placement +* @param from TileIndex of the first tile to highlight +* @param to TileIndex of the last tile to highlight +* @param measure set to true to display measurement (tunnels) or false not to do so (docks) +* I added the measure param because we don't want to see length=2 when placing a dock. +* However, this may be deleted (/remove the bracket/ either because you think it's useless or) when we have new docks of other sizes +*/ +void VpSetPresizeRange(uint from, uint to, bool measure) { + int display_x; + int display_y; _thd.selend.x = TileX(to) * TILE_SIZE; _thd.selend.y = TileY(to) * TILE_SIZE; _thd.selstart.x = TileX(from) * TILE_SIZE; _thd.selstart.y = TileY(from) * TILE_SIZE; _thd.next_drawstyle = HT_RECT; + + //show length of tunnel/dock + if (measure) { + display_x = abs(TileX(to) - TileX(from)) + 1; + display_y = abs(TileY(to) - TileY(from)) + 1; + if (display_x > 1 || display_y > 1) { //show measurement only if there is any length + if (display_x > display_y) { + GuiShowTooltips(STR_MEASURE_LENGTH, display_x); + } else { + GuiShowTooltips(STR_MEASURE_LENGTH, display_y); + } + } + } } static void VpStartPreSizing(void) @@ -1972,6 +1995,16 @@ return 0; // avoids compiler warnings } +/** +* Calculates height difference between one tile (ax; ay) and the second one (bx; by) +* minimap_height_level multiplies the result to suit the standard given by minimap - each slope is 50 meters high +* @return height difference between two tiles. Tile measurement tool utilizes this value in its tooltips +*/ +static int CalcHeightdiff(int ax, int ay, int bx, int by) +{ + int minimap_height_level = 50; + return (GetTileMaxZ(TileVirtXY(ax, ay)) * minimap_height_level / TILE_HEIGHT) - (GetTileMaxZ(TileVirtXY(bx, by)) * minimap_height_level / TILE_HEIGHT); // <-- minimap shows height in meters, let's do the same +} // while dragging static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y, int method) @@ -1979,6 +2012,13 @@ int d; byte b=6; uint w,h; + int display_x; //length in x, converted to tile format + int display_y; //length in y, converted to tile format + int distance; //length ready to be put in the toolbox + int heightdiff; //difference in height of two tiles: + int sx; //start tile coordinates + int sy; //end tile coordinates + bool diagonal = false; int dx = thd->selstart.x - (thd->selend.x&~0xF); int dy = thd->selstart.y - (thd->selend.y&~0xF); @@ -2016,6 +2056,9 @@ b = HT_LINE | HT_DIR_Y; x = thd->selstart.x; } else { // complicated direction + //problem: code below treats ANY 2x1 as complicated... Hence "distance += 1;" 87 lines below + diagonal = true; + d = w - h; thd->selend.x = thd->selend.x & ~0xF; thd->selend.y = thd->selend.y & ~0xF; @@ -2077,13 +2120,57 @@ thd->selend.x = x; thd->selend.y = y; thd->next_drawstyle = b; + + sx = _thd.selstart.x; + sy = _thd.selstart.y; + + heightdiff = CalcHeightdiff(x, y, sx, sy); + + if (sx <= x) //player drags to the west (left) + display_x = x - sx + TILE_SIZE; + else //player drags to the east (right) + display_x = sx - x + 2*TILE_SIZE; // 2*TILE_SIZE will result in showing proper distance + + if (sy <= y) //player drags to the south (down) + display_y = y - sy + TILE_SIZE; + else //player drags to the north (up) + display_y = sy - y + 2*TILE_SIZE; // 2*TILE_SIZE will result in showing proper distance + + display_x /= TILE_SIZE; //convert to distance in tiles + display_y /= TILE_SIZE; //convert to distance in tiles + + if (diagonal) { + distance = DistanceManhattan(TileVirtXY(sx, sy), TileVirtXY(x, y)); + distance += 2; //add 2 to show proper measurement + distance /= 2; //divide, because we count one diagonal piece of rail like half of normal piece of rail + if (((sy - y == 1 || y - sy == 1) && x == sx) || ((sx - x == 1 || x - sx == 1) && y == sy)) { //2x1 + distance += 1; //Unfortunatelly, all 2x1s will be 2, sorry for incovinence. But anyway, who measures that short distances? + } + } else { //player is dragging in X or Y axis (NW, NE, SW, SE) + distance = (myabs(sy - y) < myabs(sx - x)) ? display_x : display_y; + } + + heightdiff == 0 + ? GuiShowTooltips(STR_MEASURE_LENGTH, distance) + : GuiShowTooltips(STR_MEASURE_LENGTH_HEIGHTDIFF, distance, heightdiff); } // while dragging +/** +* Selects tiles while dragging +* @param x X coordinate of end of selection +* @param y Y coordinate of end of selection +* @param method modifies the way tiles are selected. Possible methods are: +* VPM_X_OR_Y = 0, VPM_FIX_X = 1, VPM_FIX_Y = 2, VPM_RAILDIRS = 3, +* VPM_X_AND_Y = 4, VPM_X_AND_Y_LIMITED = 5, VPM_SIGNALDIRS = 6 +*/ void VpSelectTilesWithMethod(int x, int y, int method) { int sx; int sy; + int display_x; + int display_y; + int heightdiff; if (x == -1) { _thd.selend.x = -1; @@ -2106,31 +2193,70 @@ sx = _thd.selstart.x; sy = _thd.selstart.y; + if (sx <= x) //player drags to the west (left) + display_x = x - sx + TILE_SIZE; + else //player drags to the east (right) + display_x = sx - x + 2*TILE_SIZE; // +2*TILE_SIZE will result in showing proper distance + + if (sy <= y) //player drags to the south (down) + display_y = y - sy + TILE_SIZE; + else //player drags to the north (up) + display_y = sy - y + 2*TILE_SIZE; // +2*TILE_SIZE will result in showing proper distance + + display_x /= TILE_SIZE; //convert to distance in tiles + display_y /= TILE_SIZE; //convert to distance in tiles + + if (_thd.next_drawstyle == HT_POINT) { + display_x = 666; + display_y -= 1; + } + switch (method) { case VPM_FIX_X: - x = sx; + x = sx; + heightdiff = CalcHeightdiff(x, y, sx, sy); + heightdiff == 0 + ? GuiShowTooltips(STR_MEASURE_LENGTH, display_y) + : GuiShowTooltips(STR_MEASURE_LENGTH_HEIGHTDIFF, display_y, heightdiff); break; - case VPM_FIX_Y: y = sy; - break; - + heightdiff = CalcHeightdiff(x, y, sx, sy); + heightdiff == 0 + ? GuiShowTooltips(STR_MEASURE_LENGTH, display_x) + : GuiShowTooltips(STR_MEASURE_LENGTH_HEIGHTDIFF, display_x, heightdiff); + break; case VPM_X_OR_Y: if (myabs(sy - y) < myabs(sx - x)) { y = sy; + heightdiff = CalcHeightdiff(x, y, sx, sy); + heightdiff == 0 + ? GuiShowTooltips(STR_MEASURE_LENGTH, display_x) + : GuiShowTooltips(STR_MEASURE_LENGTH_HEIGHTDIFF, display_x, heightdiff); } else { x = sx; + heightdiff = CalcHeightdiff(x, y, sx, sy); + heightdiff == 0 + ? GuiShowTooltips(STR_MEASURE_LENGTH, display_y) + : GuiShowTooltips(STR_MEASURE_LENGTH_HEIGHTDIFF, display_y, heightdiff); } break; - case VPM_X_AND_Y: + heightdiff = CalcHeightdiff(x, y, sx, sy); + heightdiff == 0 + ? GuiShowTooltips(STR_MEASURE_AREA, display_x, display_y) + : GuiShowTooltips(STR_MEASURE_AREA_HEIGHTDIFF, display_x, display_y, heightdiff); break; - // limit the selected area to a 10x10 rect. case VPM_X_AND_Y_LIMITED: { - int limit = (_thd.sizelimit - 1) * 16; + int limit = (_thd.sizelimit - 1) * TILE_SIZE; x = sx + clamp(x - sx, -limit, limit); y = sy + clamp(y - sy, -limit, limit); + + heightdiff = CalcHeightdiff(x, y, sx, sy); + heightdiff == 0 + ? GuiShowTooltips(STR_MEASURE_AREA, clamp(display_x, -limit, limit), clamp(display_y, -limit, limit)) + : GuiShowTooltips(STR_MEASURE_AREA_HEIGHTDIFF, clamp(display_x, -limit, limit), clamp(display_y, -limit, limit), heightdiff); break; } } Index: viewport.h =================================================================== --- viewport.h (revision 6036) +++ viewport.h (working copy) @@ -43,7 +43,7 @@ void SetTileSelectBigSize(int ox, int oy, int sx, int sy); void VpStartPlaceSizing(TileIndex tile, int user); -void VpSetPresizeRange(uint from, uint to); +void VpSetPresizeRange(uint from, uint to, bool measure); void VpSetPlaceSizingLimit(int limit); Vehicle *CheckMouseOverVehicle(void); Index: window.c =================================================================== --- window.c (revision 6036) +++ window.c (working copy) @@ -484,6 +484,8 @@ CallWindowEventNP(w, WE_CREATE); + if (cls == WC_TOOLTIPS) StartWindowDrag(w); + return w; } Index: window.h =================================================================== --- window.h (revision 6036) +++ window.h (working copy) @@ -351,6 +351,8 @@ typedef struct { StringID string_id; + uint params; + uint32 param[5]; } tooltips_d; assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(tooltips_d)); @@ -608,7 +610,7 @@ void UpdateWindows(void); void InvalidateWidget(const Window *w, byte widget_index); -void GuiShowTooltips(StringID string_id); +void GuiShowTooltips(StringID string_id, ...); void UnclickWindowButtons(Window *w); void UnclickSomeWindowButtons(Window *w, uint32 mask);