Index: lang/english.txt =================================================================== --- lang/english.txt (revision 7236) +++ lang/english.txt (working copy) @@ -3109,4 +3109,9 @@ STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Length: {NUM}{}Height difference: {NUM} m STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Area: {NUM} x {NUM}{}Height difference: {NUM} m +############ 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}%) + ######## Index: smallmap_gui.c =================================================================== --- smallmap_gui.c (revision 7236) +++ smallmap_gui.c (working copy) @@ -37,12 +37,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; @@ -325,18 +333,21 @@ * @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(Pixel *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, GetSmallMapPixels *proc) +static void DrawSmallMapStuff(Pixel *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, GetSmallMapPixels *proc, int zoom) { Pixel *dst_ptr_end = _screen.dst_ptr + _screen.width * _screen.height - _screen.width; do { + uint x = xc * SMALLMAP_BASE_ZOOM / zoom; + uint y = yc * SMALLMAP_BASE_ZOOM / zoom; // check if the tile (xc,yc) is within the map range - if (xc < MapMaxX() && yc < MapMaxY()) { + 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 += pitch, --reps != 0); @@ -591,6 +602,7 @@ int tile_x; int tile_y; ViewPort *vp; + int zoom = WP(w, smallmap_d).zoom; old_dpi = _cur_dpi; _cur_dpi = dpi; @@ -667,7 +679,7 @@ reps = (dpi->height - y + 1) / 2; if (reps > 0) { // assert(ptr >= dpi->dst_ptr); - 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: @@ -695,8 +707,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; @@ -739,8 +751,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; @@ -766,10 +778,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; @@ -789,10 +801,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); @@ -800,6 +813,8 @@ static void SmallMapWindowProc(Window *w, WindowEvent *e) { + int zoom = WP(w, smallmap_d).zoom; + switch (e->event) { case WE_PAINT: { const uint16 *tbl; @@ -835,6 +850,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: @@ -853,10 +870,9 @@ */ _left_button_clicked = false; - pt = RemapCoords(WP(w,smallmap_d).scroll_x, WP(w,smallmap_d).scroll_y, 0); - WP(w2, vp_d).scrollpos_x = pt.x + ((_cursor.pos.x - w->left + 2) << 4) - (w2->viewport->virtual_width >> 1); - WP(w2, vp_d).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).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).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; @@ -888,6 +904,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(SMALLMAP_MIN_ZOOM, WP(w, smallmap_d).zoom / 2); + SndPlayFx(SND_15_BEEP); + SetWindowDirty(w); + } + break; } break; @@ -913,6 +945,8 @@ int hy; int hvx; int hvy; + int maxx; + int maxy; _cursor.fix_at = true; @@ -946,16 +980,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; } @@ -965,6 +1001,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(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; } } @@ -988,6 +1059,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: window.h =================================================================== --- window.h (revision 7236) +++ window.h (working copy) @@ -449,6 +449,8 @@ int32 scroll_x; int32 scroll_y; int32 subscroll; + int zoom; + int zoom_target; } smallmap_d; assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(smallmap_d));