Index: lang/english.txt =================================================================== --- lang/english.txt (revision 3597) +++ lang/english.txt (working copy) @@ -410,6 +410,9 @@ STR_0196_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Show land owners on map STR_0197_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Toggle town names on/off on map STR_0198_PROFIT_THIS_YEAR_LAST_YEAR :{TINYFONT}{BLACK}Profit this year: {CURRENCY} (last year: {CURRENCY}) +STR_RECENTRE_SMALLMAP :{BLACK}Recenter the view +STR_ZOOM_IN_SMALLMAP :{BLACK}zoom in +STR_ZOOM_OUT_SMALLMAP :{BLACK}zoom out ############ range for service numbers starts STR_AGE :{COMMA} year{P "" s} ({COMMA}) Index: smallmap_gui.c =================================================================== --- smallmap_gui.c (revision 3597) +++ smallmap_gui.c (working copy) @@ -19,6 +19,7 @@ #include "town.h" #include "sound.h" #include "variables.h" +#include "debug.h" static const Widget _smallmap_widgets[] = { { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, @@ -32,9 +33,11 @@ { WWT_IMGBTN, RESIZE_LRTB, 13, 380, 401, 280, 301, SPR_IMG_SHOW_ROUTES, STR_0194_SHOW_TRANSPORT_ROUTES_ON}, { WWT_IMGBTN, RESIZE_LRTB, 13, 402, 423, 280, 301, SPR_IMG_PLANTTREES, STR_0195_SHOW_VEGETATION_ON_MAP}, { 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, 0x0, STR_NULL}, +{ WWT_PANEL, RESIZE_LRTB, 13, 358, 379, 258, 279, 683, STR_RECENTRE_SMALLMAP}, { WWT_IMGBTN, RESIZE_LRTB, 13, 358, 379, 280, 301, SPR_IMG_TOWN, STR_0197_TOGGLE_TOWN_NAMES_ON_OFF}, -{ WWT_IMGBTN, RESIZE_RTB, 13, 0, 357, 258, 301, 0x0, STR_NULL}, +{ WWT_PANEL, RESIZE_LRTB, 13, 336, 357, 258, 279, 0x2DF, STR_ZOOM_IN_SMALLMAP}, +{ WWT_PANEL, RESIZE_LRTB, 13, 336, 357, 280, 301, 0x2E0, STR_ZOOM_OUT_SMALLMAP}, +{ WWT_IMGBTN, 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}, @@ -42,6 +45,7 @@ static int _smallmap_type; static bool _smallmap_show_towns = true; +void SmallMapRecentre(void); #define MK(a,b) a, b #define MKEND() 0xFFFF @@ -324,16 +328,16 @@ * @param proc Pointer to the colour function * @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, double smallmap_zoom) { Pixel *dst_ptr_end = _screen.dst_ptr + _screen.width * _screen.height - _screen.width; do { // check if the tile (xc,yc) is within the map range - if (xc < MapMaxX() && yc < MapMaxY()) { + if (xc * smallmap_zoom < MapMaxX() && yc * smallmap_zoom < 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(xc * smallmap_zoom, yc * smallmap_zoom)) & mask); } // switch to next tile in the column } while (xc++, yc++, dst += pitch, --reps != 0); @@ -587,6 +591,7 @@ int tile_x; int tile_y; ViewPort *vp; + double smallmap_zoom=WP(w,smallmap_d).zoom; old_dpi = _cur_dpi; _cur_dpi = dpi; @@ -663,7 +668,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], smallmap_zoom); } skip_column: @@ -691,40 +696,50 @@ (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0) { // Remap into flat coordinates. Point pt = RemapCoords( - (v->x_pos - WP(w,smallmap_d).scroll_x) / 16, - (v->y_pos - WP(w,smallmap_d).scroll_y) / 16, + ((v->x_pos / smallmap_zoom) - WP(w, smallmap_d).scroll_x) / 16, + ((v->y_pos / smallmap_zoom) - WP(w, smallmap_d).scroll_y) / 16, 0); x = pt.x; y = pt.y; - // Check if y is out of bounds? - y -= dpi->top; - if (!IS_INT_INSIDE(y, 0, dpi->height)) continue; - - // Default is to draw both pixels. - skip = false; - - // Offset X coordinate - x -= WP(w,smallmap_d).subscroll + 3 + dpi->left; - - if (x < 0) { - // if x+1 is 0, that means we're on the very left edge, - // and should thus only draw a single pixel - if (++x != 0) continue; - skip = true; - } else if (x >= dpi->width - 1) { - // Check if we're at the very right edge, and if so draw only a single pixel - if (x != dpi->width - 1) continue; - skip = true; + if ((smallmap_zoom<0.125 && (v->type==VEH_Train || v->type==VEH_Road || v->type==VEH_Ship)) || v->type==VEH_Aircraft){ + /* draw the vehicle if near enough*/ + int image = v->cur_image; + uint32 ormod = SPRITE_PALETTE(PLAYER_SPRITE_COLOR(v->owner)); + if (v->vehstatus & VS_CRASHED) + ormod = PALETTE_CRASH; + DrawSprite(image | ormod, x, y); + } else { + /* far away, just draw that ugly pixel */ + // Check if y is out of bounds? + y -= dpi->top; + if (!IS_INT_INSIDE(y, 0, dpi->height)) continue; + + // Default is to draw both pixels. + skip = false; + + // Offset X coordinate + x -= WP(w,smallmap_d).subscroll + 3 + dpi->left; + + if (x < 0) { + // if x+1 is 0, that means we're on the very left edge, + // and should thus only draw a single pixel + if (++x != 0) continue; + skip = true; + } else if (x >= dpi->width - 1) { + // Check if we're at the very right edge, and if so draw only a single pixel + if (x != dpi->width - 1) continue; + skip = true; + } + + // Calculate pointer to pixel and the color + ptr = dpi->dst_ptr + y * dpi->pitch + x; + color = (type == 1) ? _vehicle_type_colors[v->type-0x10] : 0xF; + + // And draw either one or two pixels depending on clipping + ptr[0] = color; + if (!skip) ptr[1] = color; } - - // Calculate pointer to pixel and the color - ptr = dpi->dst_ptr + y * dpi->pitch + x; - color = (type == 1) ? _vehicle_type_colors[v->type-0x10] : 0xF; - - // And draw either one or two pixels depending on clipping - ptr[0] = color; - if (!skip) ptr[1] = color; } } } @@ -736,9 +751,9 @@ if (t->xy != 0) { // Remap the town coordinate Point pt = RemapCoords( - (int)(TileX(t->xy) * 16 - WP(w, smallmap_d).scroll_x) / 16, - (int)(TileY(t->xy) * 16 - WP(w, smallmap_d).scroll_y) / 16, - 0); + (int)((TileX(t->xy) / smallmap_zoom) * 16 - WP(w, smallmap_d).scroll_x) / 16, + (int)((TileY(t->xy) / smallmap_zoom) * 16 - WP(w, smallmap_d).scroll_y) / 16, + 0); x = pt.x - WP(w,smallmap_d).subscroll + 3 - (t->sign.width_2 >> 1); y = pt.y; @@ -763,11 +778,11 @@ vp = FindWindowById(WC_MAIN_WINDOW,0)->viewport; pt = RemapCoords(WP(w, smallmap_d).scroll_x, WP(w, smallmap_d).scroll_y, 0); + x = (vp->virtual_left / smallmap_zoom) - pt.x; + y = (vp->virtual_top / smallmap_zoom) - pt.y; + x2 = (x + (vp->virtual_width / smallmap_zoom)) / 16; + y2 = (y + (vp->virtual_height / smallmap_zoom)) / 16; - x = vp->virtual_left - pt.x; - y = vp->virtual_top - pt.y; - x2 = (x + vp->virtual_width) / 16; - y2 = (y + vp->virtual_height) / 16; x /= 16; y /= 16; @@ -783,8 +798,83 @@ _cur_dpi = old_dpi; } +void SmallMapRecentre(void) +{ + int x,y; + Window *w; + ViewPort *vp; + + /* recentre the map */ + w = FindWindowById(WC_SMALLMAP, 0); + double smallmap_zoom=WP(w,smallmap_d).zoom; + vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; + + x = ((((vp->virtual_width / smallmap_zoom) - (220*32)) / 2) + (vp->virtual_left / smallmap_zoom)) / 4; + y = (((((vp->virtual_height / smallmap_zoom) - (120*32)) / 2) + (vp->virtual_top / smallmap_zoom)) / 2) - 32; + + WP(w,smallmap_d).scroll_x = (y-x) & ~0xF; + WP(w,smallmap_d).scroll_y = (x+y) & ~0xF; + WP(w,smallmap_d).subscroll = 0; + + /* handle disabled states of buttons */ + CLRBIT(w->disabled_state, 13); + CLRBIT(w->disabled_state, 14); + + if (smallmap_zoom <= 0) { + SETBIT(w->disabled_state, 13); + }if (smallmap_zoom >= 32) { + SETBIT(w->disabled_state, 14); + } +} + +void ScrollSmallmap(int mx, int my) +{ + int hx, hy; + int hvx, hvy; + int x, y, sub; + + Window *w = FindWindowById(WC_SMALLMAP, 0); + double smallmap_zoom=WP(w,smallmap_d).zoom; + + x = WP(w,smallmap_d).scroll_x; + y = WP(w,smallmap_d).scroll_y; + + sub = WP(w,smallmap_d).subscroll + mx; + + x -= (sub >> 2) << 4; + y += (sub >> 2) << 4; + sub &= 3; + + x += (my >> 1) << 4; + y += (my >> 1) << 4; + + if (my & 1) { + x += 16; + sub += 2; + if (sub > 3) { + sub -= 4; + x -= 16; + y += 16; + } + } + + hx = (w->widget[4].right - w->widget[4].left) / 2; + hy = (w->widget[4].bottom - w->widget[4].top ) / 2; + hvx = hx * -4 + hy * 8; + hvy = hx * 4 + hy * 8; + if (x < -hvx) { x = -hvx; sub = 0; } + if (x > (int)((MapMaxX() * 16) / smallmap_zoom) - hvx) { x = ((MapMaxX() * 16) / smallmap_zoom) - hvx; sub = 0; } + if (y < -hvy) { y = -hvy; sub = 0; } + if (y > (int)((MapMaxY() * 16) / smallmap_zoom) - hvy) { y = ((MapMaxY() * 16) / smallmap_zoom) - hvy; sub = 0; } + + WP(w,smallmap_d).scroll_x = x; + WP(w,smallmap_d).scroll_y = y; + WP(w,smallmap_d).subscroll = sub; +} + static void SmallMapWindowProc(Window *w, WindowEvent *e) { + double smallmap_zoom=WP(w,smallmap_d).zoom; switch (e->event) { case WE_PAINT: { const uint16 *tbl; @@ -833,8 +923,9 @@ w2 = FindWindowById(WC_MAIN_WINDOW, 0); 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); + WP(w2,vp_d).scrollpos_x = (pt.x * smallmap_zoom) + (((_cursor.pos.x - w->left + 2) << 4) * smallmap_zoom) - (w2->viewport->virtual_width >> 1); + WP(w2,vp_d).scrollpos_y = (pt.y * smallmap_zoom) + (((_cursor.pos.y - w->top - 16) << 4) * smallmap_zoom) - (w2->viewport->virtual_height >> 1); + } break; case 5: /* Show land contours */ @@ -851,13 +942,38 @@ SndPlayFx(SND_15_BEEP); break; + case 11: /* centre location */ + SmallMapRecentre(); + SetWindowDirty(w); + SndPlayFx(SND_15_BEEP); + break; + case 12: /* toggle town names */ w->click_state ^= (1 << 12); _smallmap_show_towns = (w->click_state >> 12) & 1; SetWindowDirty(w); SndPlayFx(SND_15_BEEP); break; - } + + case 13: /* zoom in */ + DEBUG(misc,10)("zoom-level: %f",(float)smallmap_zoom); + if (smallmap_zoom > 0.04) // can zoom in up to 5 times + WP(w,smallmap_d).zoom /= 2; + SmallMapRecentre(); + SetWindowDirty(w); + SndPlayFx(SND_15_BEEP); + break; + + case 14: /* zoom out */ + DEBUG(misc,10)("zoom-level: %f",(float)smallmap_zoom); + if (smallmap_zoom < 32) + WP(w,smallmap_d).zoom *= 2; + + SmallMapRecentre(); + SetWindowDirty(w); + SndPlayFx(SND_15_BEEP); + break; + } break; case WE_RCLICK: @@ -873,6 +989,38 @@ /* update the window every now and then */ if ((++w->vscroll.pos & 0x1F) == 0) SetWindowDirty(w); break; + + case WE_SCROLL: + /* DEBUG(misc,1)("GOT SCROLL-EVENT: %i,%i",e->scroll.delta.x,e->scroll.delta.y); */ + _cursor.fix_at = true; + ScrollSmallmap(e->scroll.delta.x,e->scroll.delta.y); + SetWindowDirty(w); + break; + + case WE_MOUSEWHEEL: + /* DEBUG(misc,10)("GOT WHEEL-EVENT: %i",e->wheel.wheel); */ + if ((e->wheel.wheel<0) && (smallmap_zoom > 0.04)){ /* can zoom in up to 5 times */ + WP(w,smallmap_d).zoom /= 2; + } else if ((e->wheel.wheel>0) && (smallmap_zoom < 32)) { + WP(w,smallmap_d).zoom *= 2; + } else { + return; + } + SmallMapRecentre(); + SetWindowDirty(w); + break; + + case WE_TICK: + SetWindowDirty(w); + break; + + case WE_MOUSEOVER: + //do nothing + break; + + default: + DEBUG(misc,10)("got unhandled event :%i",e->event); + break; } } @@ -895,11 +1043,12 @@ w->click_state = ((1<<5) << _smallmap_type) | (_smallmap_show_towns << 12); w->resize.width = 350; w->resize.height = 250; - + WP(w,smallmap_d).zoom = 1; + double smallmap_zoom = WP(w,smallmap_d).zoom; vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; - x = ((vp->virtual_width - 220 * 32) / 2 + vp->virtual_left) / 4; - y = ((vp->virtual_height - 120 * 32) / 2 + vp->virtual_top ) / 2 - 32; + x = ((((vp->virtual_width / smallmap_zoom) - (220*32)) / 2) + vp->virtual_left) / (4 * smallmap_zoom); + y = (((((vp->virtual_height / smallmap_zoom) - (120*32)) / 2) + vp->virtual_top) / (2 * smallmap_zoom)) - 32; WP(w,smallmap_d).scroll_x = (y - x) & ~0xF; WP(w,smallmap_d).scroll_y = (x + y) & ~0xF; WP(w,smallmap_d).subscroll = 0; Index: window.c =================================================================== --- window.c (revision 3597) +++ window.c (working copy) @@ -119,9 +119,15 @@ { const Widget *wi1, *wi2; Scrollbar *sb; - + if (widget < 0) return; + /* send WE_MOUSEWHEEL event to window */ + WindowEvent e; + e.event = WE_MOUSEWHEEL; + e.wheel.wheel=wheel; + w->wndproc(w, &e); + wi1 = &w->widget[widget]; wi2 = &w->widget[widget + 1]; @@ -1177,66 +1183,14 @@ WP(w,vp_d).scrollpos_y += dy << vp->zoom; } else { - int x; - int y; - int sub; - int hx; - int hy; - int hvx; - int hvy; - - _cursor.fix_at = true; - - x = WP(w,smallmap_d).scroll_x; - y = WP(w,smallmap_d).scroll_y; - - sub = WP(w,smallmap_d).subscroll + dx; - - x -= (sub >> 2) << 4; - y += (sub >> 2) << 4; - sub &= 3; - - x += (dy >> 1) << 4; - y += (dy >> 1) << 4; - - if (dy & 1) { - x += 16; - sub += 2; - if (sub > 3) { - sub -= 4; - x -= 16; - y += 16; - } - } - - hx = (w->widget[4].right - w->widget[4].left) / 2; - hy = (w->widget[4].bottom - w->widget[4].top ) / 2; - hvx = hx * -4 + hy * 8; - hvy = hx * 4 + hy * 8; - if (x < -hvx) { - x = -hvx; - sub = 0; - } - if (x > (int)MapMaxX() * 16 - hvx) { - x = MapMaxX() * 16 - hvx; - sub = 0; - } - if (y < -hvy) { - y = -hvy; - sub = 0; - } - if (y > (int)MapMaxY() * 16 - hvy) { - y = MapMaxY() * 16 - hvy; - sub = 0; - } - - WP(w,smallmap_d).scroll_x = x; - WP(w,smallmap_d).scroll_y = y; - WP(w,smallmap_d).subscroll = sub; - - SetWindowDirty(w); + /* create a scroll-event and send it to the client */ + WindowEvent we; + we.event = WE_SCROLL; + we.scroll.delta.x = _cursor.delta.x; + we.scroll.delta.y = _cursor.delta.y; + /* DEBUG(misc,3)("GOT SCROLL EVENT, passing to client!,%i,%i,%i",e.event,e.scroll.deltax,e.scroll.deltay); */ + w->wndproc(w, &we); } - _cursor.delta.x = 0; _cursor.delta.y = 0; return false; @@ -1440,6 +1394,7 @@ } else { if (mousewheel) DispatchMouseWheelEvent(w, GetWidgetFromPos(w, x - w->left, y - w->top), mousewheel); + switch (click) { case 1: DispatchLeftClickEvent(w, x - w->left, y - w->top); break; Index: window.h =================================================================== --- window.h (revision 3597) +++ window.h (working copy) @@ -134,6 +134,16 @@ uint wparam; // additional message-specific information uint lparam; // additional message-specific information } message; + + struct { + byte event; + Point delta; // cursor delta information + } scroll; + + struct { + byte event; + int wheel; // scrollwheel change + } wheel; }; enum WindowKeyCodes { @@ -376,8 +386,9 @@ int32 scroll_x; int32 scroll_y; int32 subscroll; + double zoom; } smallmap_d; -assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(traindetails_d)); +assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(smallmap_d)); typedef struct { uint32 face; @@ -497,7 +508,9 @@ WE_MOUSEOVER = 20, WE_ON_EDIT_TEXT_CANCEL = 21, WE_RESIZE = 22, - WE_MESSAGE = 23 + WE_MESSAGE = 23, + WE_SCROLL=24, + WE_MOUSEWHEEL=25 };