Index: src/lang/english.txt =================================================================== --- src/lang/english.txt (revision 10450) +++ src/lang/english.txt (working copy) @@ -3293,6 +3293,11 @@ STR_DATE_SHORT :{STRING} {NUM} STR_DATE_LONG :{STRING} {STRING} {NUM} +############ range for smallmap-specific start +STR_ZOOM_IN_SMALLMAP :{BLACK}Zoom in +STR_ZOOM_OUT_SMALLMAP :{BLACK}Zoom out +STR_SMALLMAP_ZOOMDISPLAY :{TINYFONT}{WHITE}Zoom: {COMMA}%) + ######## STR_FEEDER_CARGO_VALUE :{BLACK}Transfer Credits: {LTBLUE}{CURRENCY} Index: src/smallmap_gui.cpp =================================================================== --- src/smallmap_gui.cpp (revision 10450) +++ src/smallmap_gui.cpp (working copy) @@ -41,12 +41,20 @@ { WWT_IMGBTN, RESIZE_LRTB, 13, 424, 445, 280, 301, SPR_IMG_COMPANY_GENERAL, STR_0196_SHOW_LAND_OWNERS_ON_MAP}, { WWT_IMGBTN, RESIZE_LRTB, 13, 358, 379, 258, 279, SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER}, { WWT_IMGBTN, RESIZE_LRTB, 13, 358, 379, 280, 301, SPR_IMG_TOWN, STR_0197_TOGGLE_TOWN_NAMES_ON_OFF}, -{ WWT_PANEL, RESIZE_RTB, 13, 0, 357, 258, 301, 0x0, STR_NULL}, +{ WWT_IMGBTN, RESIZE_LRTB, 13, 336, 357, 258, 279, SPR_IMG_ZOOMIN, STR_ZOOM_IN_SMALLMAP}, +{ WWT_IMGBTN, RESIZE_LRTB, 13, 336, 357, 280, 301, SPR_IMG_ZOOMOUT, STR_ZOOM_OUT_SMALLMAP}, +{ WWT_PANEL, RESIZE_RTB, 13, 0, 335, 258, 301, 0x0, STR_NULL}, { WWT_PANEL, RESIZE_RTB, 13, 0, 433, 302, 313, 0x0, STR_NULL}, { WWT_RESIZEBOX, RESIZE_LRTB, 13, 434, 445, 302, 313, 0x0, STR_RESIZE_BUTTON}, { WIDGETS_END}, }; +enum { + SMALLMAP_MAX_ZOOM = 800, + SMALLMAP_BASE_ZOOM = 100, + SMALLMAP_MIN_ZOOM = 10 +}; + static int _smallmap_type; static bool _smallmap_show_towns = true; @@ -281,19 +289,24 @@ * @param reps Number of lines to draw * @param mask ? * @param proc Pointer to the colour function + * @param zoom the zoom factor (times SMALLMAP_BASE_ZOOM), i.e. SMALLMAP_BASE_ZOOM means no zooming with respect to original * @see GetSmallMapPixels(TileIndex) */ -static void DrawSmallMapStuff(void *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, GetSmallMapPixels *proc) +static void DrawSmallMapStuff(void *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, GetSmallMapPixels *proc, int zoom) { Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter(); void *dst_ptr_end = blitter->MoveTo(_screen.dst_ptr, _screen.width, _screen.height - 1); do { - /* check if the tile (xc,yc) is within the map range */ - if (xc < MapMaxX() && yc < MapMaxY()) { + uint x = xc * SMALLMAP_BASE_ZOOM / zoom; + uint y = yc * SMALLMAP_BASE_ZOOM / zoom; + + /* check if the tile (x, y) is within the map range */ + + if (x < MapMaxX() && y < MapMaxY()) { /* check if the dst pointer points to a pixel inside the screen buffer */ if (dst > _screen.dst_ptr && dst < dst_ptr_end) - WRITE_PIXELS_OR(dst, proc(TileXY(xc, yc)) & mask); + WRITE_PIXELS_OR(dst, proc(TileXY(x, y)) & mask); } /* switch to next tile in the column */ } while (xc++, yc++, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0); @@ -523,6 +536,7 @@ int tile_x; int tile_y; ViewPort *vp; + int zoom = WP(w, smallmap_d).zoom; old_dpi = _cur_dpi; _cur_dpi = dpi; @@ -598,7 +612,7 @@ /* number of lines */ reps = (dpi->height - y + 1) / 2; if (reps > 0) { - DrawSmallMapStuff(ptr, tile_x, tile_y, dpi->pitch * 2, reps, mask, _smallmap_draw_procs[type]); + DrawSmallMapStuff(ptr, tile_x, tile_y, dpi->pitch * 2, reps, mask, _smallmap_draw_procs[type], zoom); } skip_column: @@ -626,8 +640,8 @@ (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0) { /* Remap into flat coordinates. */ Point pt = RemapCoords( - v->x_pos / TILE_SIZE - WP(w,smallmap_d).scroll_x / TILE_SIZE, // divide each one separately because (a-b)/c != a/c-b/c in integer world - v->y_pos / TILE_SIZE - WP(w,smallmap_d).scroll_y / TILE_SIZE, // dtto + v->x_pos * zoom / SMALLMAP_BASE_ZOOM / TILE_SIZE - WP(w,smallmap_d).scroll_x / TILE_SIZE, // divide each one separately because (a-b)/c != a/c-b/c in integer world + v->y_pos * zoom / SMALLMAP_BASE_ZOOM / TILE_SIZE - WP(w,smallmap_d).scroll_y / TILE_SIZE, // ditto 0); x = pt.x; y = pt.y; @@ -669,8 +683,8 @@ FOR_ALL_TOWNS(t) { /* Remap the town coordinate */ Point pt = RemapCoords( - (int)(TileX(t->xy) * TILE_SIZE - WP(w, smallmap_d).scroll_x) / TILE_SIZE, - (int)(TileY(t->xy) * TILE_SIZE - WP(w, smallmap_d).scroll_y) / TILE_SIZE, + (int)(TileX(t->xy) * TILE_SIZE * zoom / SMALLMAP_BASE_ZOOM - WP(w, smallmap_d).scroll_x) / TILE_SIZE, + (int)(TileY(t->xy) * TILE_SIZE * zoom / SMALLMAP_BASE_ZOOM - WP(w, smallmap_d).scroll_y) / TILE_SIZE, 0); x = pt.x - WP(w,smallmap_d).subscroll + 3 - (t->sign.width_2 >> 1); y = pt.y; @@ -696,10 +710,10 @@ pt = RemapCoords(WP(w, smallmap_d).scroll_x, WP(w, smallmap_d).scroll_y, 0); - x = vp->virtual_left - pt.x; - y = vp->virtual_top - pt.y; - x2 = (x + vp->virtual_width) / TILE_SIZE; - y2 = (y + vp->virtual_height) / TILE_SIZE; + x = vp->virtual_left * zoom / SMALLMAP_BASE_ZOOM - pt.x; + y = vp->virtual_top * zoom / SMALLMAP_BASE_ZOOM - pt.y; + x2 = (x + vp->virtual_width * zoom / SMALLMAP_BASE_ZOOM) / TILE_SIZE; + y2 = (y + vp->virtual_height * zoom / SMALLMAP_BASE_ZOOM) / TILE_SIZE; x /= TILE_SIZE; y /= TILE_SIZE; @@ -719,10 +733,11 @@ { int x, y; ViewPort *vp; + int zoom = WP(w, smallmap_d).zoom; vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; - x = ((vp->virtual_width - (w->widget[4].right - w->widget[4].left) * TILE_SIZE) / 2 + vp->virtual_left) / 4; - y = ((vp->virtual_height - (w->widget[4].bottom - w->widget[4].top ) * TILE_SIZE) / 2 + vp->virtual_top ) / 2 - TILE_SIZE * 2; + x = ((vp->virtual_width * zoom / SMALLMAP_BASE_ZOOM - (w->widget[4].right - w->widget[4].left) * TILE_SIZE) / 2 + vp->virtual_left * zoom / SMALLMAP_BASE_ZOOM) / 4; + y = ((vp->virtual_height * zoom / SMALLMAP_BASE_ZOOM - (w->widget[4].bottom - w->widget[4].top ) * TILE_SIZE) / 2 + vp->virtual_top * zoom / SMALLMAP_BASE_ZOOM) / 2 - TILE_SIZE * 2; WP(w, smallmap_d).scroll_x = (y - x) & ~0xF; WP(w, smallmap_d).scroll_y = (x + y) & ~0xF; SetWindowDirty(w); @@ -730,6 +745,8 @@ static void SmallMapWindowProc(Window *w, WindowEvent *e) { + int zoom = WP(w, smallmap_d).zoom; + switch (e->event) { case WE_PAINT: { const LegendAndColour *tbl; @@ -774,6 +791,8 @@ return; DrawSmallMap(&new_dpi, w, _smallmap_type, _smallmap_show_towns); + SetDParam(0, zoom); + DrawString(4, w->height - 64 - 2, STR_SMALLMAP_ZOOMDISPLAY, 12); } break; case WE_CLICK: @@ -792,9 +811,9 @@ */ _left_button_clicked = false; - pt = RemapCoords(WP(w,smallmap_d).scroll_x, WP(w,smallmap_d).scroll_y, 0); - WP(w2, vp_d).dest_scrollpos_x = pt.x + ((_cursor.pos.x - w->left + 2) << 4) - (w2->viewport->virtual_width >> 1); - WP(w2, vp_d).dest_scrollpos_y = pt.y + ((_cursor.pos.y - w->top - 16) << 4) - (w2->viewport->virtual_height >> 1); + pt = RemapCoords(WP(w, smallmap_d).scroll_x, WP(w, smallmap_d).scroll_y, 0); + WP(w2, vp_d).dest_scrollpos_x = pt.x * SMALLMAP_BASE_ZOOM / zoom + ((_cursor.pos.x - w->left + 2) << 4) * SMALLMAP_BASE_ZOOM / zoom - (w2->viewport->virtual_width >> 1); + WP(w2, vp_d).dest_scrollpos_y = pt.y * SMALLMAP_BASE_ZOOM / zoom + ((_cursor.pos.y - w->top - 16) << 4) * SMALLMAP_BASE_ZOOM / zoom - (w2->viewport->virtual_height >> 1); SetWindowDirty(w); } break; @@ -827,6 +846,22 @@ SetWindowDirty(w); SndPlayFx(SND_15_BEEP); break; + + case 13: // Zoom in + if (zoom < SMALLMAP_MAX_ZOOM) { + WP(w, smallmap_d).zoom_target = min(SMALLMAP_MAX_ZOOM, WP(w, smallmap_d).zoom * 2); + SndPlayFx(SND_15_BEEP); + SetWindowDirty(w); + } + break; + + case 14: // Zoom out + if (zoom > SMALLMAP_MIN_ZOOM) { + WP(w, smallmap_d).zoom_target = max((int)SMALLMAP_MIN_ZOOM, WP(w, smallmap_d).zoom / 2); + SndPlayFx(SND_15_BEEP); + SetWindowDirty(w); + } + break; } break; @@ -852,6 +887,8 @@ int hy; int hvx; int hvy; + int maxx; + int maxy; _cursor.fix_at = true; @@ -885,16 +922,18 @@ x = -hvx; sub = 0; } - if (x > (int)MapMaxX() * TILE_SIZE - hvx) { - x = MapMaxX() * TILE_SIZE - hvx; + maxx = (int)MapMaxX() * TILE_SIZE * zoom / SMALLMAP_BASE_ZOOM - hvx; + if (x > maxx) { + x = maxx; sub = 0; } if (y < -hvy) { y = -hvy; sub = 0; } - if (y > (int)MapMaxY() * TILE_SIZE - hvy) { - y = MapMaxY() * TILE_SIZE - hvy; + maxy = (int)MapMaxY() * TILE_SIZE * zoom / SMALLMAP_BASE_ZOOM - hvy; + if (y > maxy) { + y = maxy; sub = 0; } @@ -904,6 +943,41 @@ SetWindowDirty(w); } break; + + case WE_MOUSEWHEEL: + if (e->we.wheel.wheel < 0 && zoom < SMALLMAP_MAX_ZOOM) { + WP(w, smallmap_d).zoom_target = min(SMALLMAP_MAX_ZOOM, WP(w, smallmap_d).zoom * (-2 * e->we.wheel.wheel)); + } else if (e->we.wheel.wheel > 0 && zoom > SMALLMAP_MIN_ZOOM) { + WP(w, smallmap_d).zoom_target = max((int)SMALLMAP_MIN_ZOOM, WP(w, smallmap_d).zoom / ( 2 * e->we.wheel.wheel)); + } else { + break; + } + SetWindowDirty(w); + break; + + case WE_TICK: + /* zoom smoothly :) */ + if (zoom != WP(w, smallmap_d).zoom_target) { + int diff = WP(w, smallmap_d).zoom_target - zoom; + int diff_abs = myabs(diff); + + if (diff_abs < zoom / 10 || diff_abs < 5) { + zoom = WP(w, smallmap_d).zoom_target; + } else { + zoom += diff / 5; + } + + SetWindowWidgetDisabledState(w, 13, zoom == SMALLMAP_MAX_ZOOM); + SetWindowWidgetDisabledState(w, 14, zoom == SMALLMAP_MIN_ZOOM); + WP(w, smallmap_d).zoom = zoom; + + /* + * TODO: do not zoom on the center of the map in the main viewport, + * but zoom on the center of the smallmap 'viewport' + */ + SmallMapCenterOnCurrentPos(w); // Shouldn't be here, only for testing + } + break; } } @@ -927,6 +1001,9 @@ w->resize.width = 350; w->resize.height = 250; + WP(w, smallmap_d).zoom = SMALLMAP_BASE_ZOOM; + WP(w, smallmap_d).zoom_target = SMALLMAP_BASE_ZOOM; + SmallMapCenterOnCurrentPos(w); } Index: src/window.h =================================================================== --- src/window.h (revision 10450) +++ src/window.h (working copy) @@ -383,6 +383,8 @@ int32 scroll_x; int32 scroll_y; int32 subscroll; + int zoom; + int zoom_target; }; assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(smallmap_d));