# HG changeset patch # User glx # Date 2008-05-11 19:47:10 # Node ID 66717b4ffbc5cb5095eb2adc30bc9e449203602c # Parent ee9cf6d822e693960838050a27384ab4b438079a (svn r13055) -Codechange: make a class of SmallMapWindow. diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -32,13 +32,6 @@ #include "table/strings.h" #include "table/sprites.h" -struct smallmap_d { - int32 scroll_x; - int32 scroll_y; - int32 subscroll; -}; -assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(smallmap_d)); - static const Widget _smallmap_widgets[] = { { WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CAPTION, RESIZE_RIGHT, 13, 11, 337, 0, 13, STR_00B0_MAP, STR_018C_WINDOW_TITLE_DRAG_THIS}, @@ -561,539 +554,536 @@ enum SmallMapWindowWidgets { SM_WIDGET_RESIZEBOX, }; -enum SmallMapType { - SMT_CONTOUR, - SMT_VEHICLES, - SMT_INDUSTRY, - SMT_OWNER = 5, -}; - -/** - * Draws the small map. - * - * Basically, the small map is draw column of pixels by column of pixels. The pixels - * are drawn directly into the screen buffer. The final map is drawn in multiple passes. - * The passes are: - *
  1. The colors of tiles in the different modes.
  2. - *
  3. Town names (optional)
- * - * @param dpi pointer to pixel to write onto - * @param w pointer to Window struct - * @param type type of map requested (vegetation, owners, routes, etc) - * @param show_towns true if the town names should be displayed, false if not. - */ -static void DrawSmallMap(DrawPixelInfo *dpi, Window *w, int type, bool show_towns) +class SmallMapWindow : public Window { - Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter(); - DrawPixelInfo *old_dpi; - int dx,dy, x, y, x2, y2; - void *ptr; - int tile_x; - int tile_y; - ViewPort *vp; + enum SmallMapType { + SMT_CONTOUR, + SMT_VEHICLES, + SMT_INDUSTRY, + SMT_OWNER = 5, + }; + + enum { + BASE_NB_PER_COLUMN = 6, + }; + + int32 scroll_x; + int32 scroll_y; + int32 subscroll; - old_dpi = _cur_dpi; - _cur_dpi = dpi; - - /* clear it */ - GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0); +public: + /** + * Draws the small map. + * + * Basically, the small map is draw column of pixels by column of pixels. The pixels + * are drawn directly into the screen buffer. The final map is drawn in multiple passes. + * The passes are: + *
  1. The colors of tiles in the different modes.
  2. + *
  3. Town names (optional)
+ * + * @param dpi pointer to pixel to write onto + * @param w pointer to Window struct + * @param type type of map requested (vegetation, owners, routes, etc) + * @param show_towns true if the town names should be displayed, false if not. + */ + void DrawSmallMap(DrawPixelInfo *dpi, int type, bool show_towns) + { + Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter(); + DrawPixelInfo *old_dpi; + int dx,dy, x, y, x2, y2; + void *ptr; + int tile_x; + int tile_y; + ViewPort *vp; - /* setup owner table */ - if (type == SMT_OWNER) { - const Player *p; + old_dpi = _cur_dpi; + _cur_dpi = dpi; + + /* clear it */ + GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0); + + /* setup owner table */ + if (type == SMT_OWNER) { + const Player *p; + + /* fill with some special colors */ + _owner_colors[OWNER_TOWN] = MKCOLOR(0xB4B4B4B4); + _owner_colors[OWNER_NONE] = MKCOLOR(0x54545454); + _owner_colors[OWNER_WATER] = MKCOLOR(0xCACACACA); + _owner_colors[OWNER_END] = MKCOLOR(0x20202020); /* industry */ - /* fill with some special colors */ - _owner_colors[OWNER_TOWN] = MKCOLOR(0xB4B4B4B4); - _owner_colors[OWNER_NONE] = MKCOLOR(0x54545454); - _owner_colors[OWNER_WATER] = MKCOLOR(0xCACACACA); - _owner_colors[OWNER_END] = MKCOLOR(0x20202020); /* industry */ + /* now fill with the player colors */ + FOR_ALL_PLAYERS(p) { + if (p->is_active) { + _owner_colors[p->index] = + _colour_gradient[p->player_color][5] * 0x01010101; + } + } + } + + tile_x = this->scroll_x / TILE_SIZE; + tile_y = this->scroll_y / TILE_SIZE; - /* now fill with the player colors */ - FOR_ALL_PLAYERS(p) { - if (p->is_active) { - _owner_colors[p->index] = - _colour_gradient[p->player_color][5] * 0x01010101; + dx = dpi->left + this->subscroll; + tile_x -= dx / 4; + tile_y += dx / 4; + dx &= 3; + + dy = dpi->top; + tile_x += dy / 2; + tile_y += dy / 2; + + if (dy & 1) { + tile_x++; + dx += 2; + if (dx > 3) { + dx -= 4; + tile_x--; + tile_y++; } } - } + + ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0); + x = - dx - 4; + y = 0; + + for (;;) { + uint32 mask = 0xFFFFFFFF; + int reps; + int t; - tile_x = WP(w, smallmap_d).scroll_x / TILE_SIZE; - tile_y = WP(w, smallmap_d).scroll_y / TILE_SIZE; + /* distance from left edge */ + if (x < 0) { + if (x < -3) goto skip_column; + /* mask to use at the left edge */ + mask = _smallmap_mask_left[x + 3]; + } + + /* distance from right edge */ + t = dpi->width - x; + if (t < 4) { + if (t <= 0) break; /* exit loop */ + /* mask to use at the right edge */ + mask &= _smallmap_mask_right[t - 1]; + } - dx = dpi->left + WP(w, smallmap_d).subscroll; - tile_x -= dx / 4; - tile_y += dx / 4; - dx &= 3; + /* 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]); + } - dy = dpi->top; - tile_x += dy / 2; - tile_y += dy / 2; + skip_column: + if (y == 0) { + tile_y++; + y++; + ptr = blitter->MoveTo(ptr, 0, 1); + } else { + tile_x--; + y--; + ptr = blitter->MoveTo(ptr, 0, -1); + } + ptr = blitter->MoveTo(ptr, 2, 0); + x += 2; + } + + /* draw vehicles? */ + if (type == SMT_CONTOUR || type == SMT_VEHICLES) { + Vehicle *v; + bool skip; + byte color; - if (dy & 1) { - tile_x++; - dx += 2; - if (dx > 3) { - dx -= 4; - tile_x--; - tile_y++; - } - } + FOR_ALL_VEHICLES(v) { + if (v->type != VEH_EFFECT && + (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0) { + /* Remap into flat coordinates. */ + Point pt = RemapCoords( + v->x_pos / TILE_SIZE - this->scroll_x / TILE_SIZE, // divide each one separately because (a-b)/c != a/c-b/c in integer world + v->y_pos / TILE_SIZE - this->scroll_y / TILE_SIZE, // dtto + 0); + x = pt.x; + y = pt.y; + + /* Check if y is out of bounds? */ + y -= dpi->top; + if (!IsInsideMM(y, 0, dpi->height)) continue; + + /* Default is to draw both pixels. */ + skip = false; + + /* Offset X coordinate */ + x -= this->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; + } - ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0); - x = - dx - 4; - y = 0; + /* Calculate pointer to pixel and the color */ + color = (type == SMT_VEHICLES) ? _vehicle_type_colors[v->type] : 0xF; + + /* And draw either one or two pixels depending on clipping */ + blitter->SetPixel(dpi->dst_ptr, x, y, color); + if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, color); + } + } + } + + if (show_towns) { + const Town *t; - for (;;) { - uint32 mask = 0xFFFFFFFF; - int reps; - int t; + FOR_ALL_TOWNS(t) { + /* Remap the town coordinate */ + Point pt = RemapCoords( + (int)(TileX(t->xy) * TILE_SIZE - this->scroll_x) / TILE_SIZE, + (int)(TileY(t->xy) * TILE_SIZE - this->scroll_y) / TILE_SIZE, + 0); + x = pt.x - this->subscroll + 3 - (t->sign.width_2 >> 1); + y = pt.y; - /* distance from left edge */ - if (x < 0) { - if (x < -3) goto skip_column; - /* mask to use at the left edge */ - mask = _smallmap_mask_left[x + 3]; + /* Check if the town sign is within bounds */ + if (x + t->sign.width_2 > dpi->left && + x < dpi->left + dpi->width && + y + 6 > dpi->top && + y < dpi->top + dpi->height) { + /* And draw it. */ + SetDParam(0, t->index); + DrawString(x, y, STR_2056, TC_WHITE); + } + } } - /* distance from right edge */ - t = dpi->width - x; - if (t < 4) { - if (t <= 0) break; /* exit loop */ - /* mask to use at the right edge */ - mask &= _smallmap_mask_right[t - 1]; + /* Draw map indicators */ + { + Point pt; + + /* Find main viewport. */ + vp = FindWindowById(WC_MAIN_WINDOW,0)->viewport; + + pt = RemapCoords(this->scroll_x, this->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 /= TILE_SIZE; + y /= TILE_SIZE; + + x -= this->subscroll; + x2 -= this->subscroll; + + DrawVertMapIndicator(x, y, x, y2); + DrawVertMapIndicator(x2, y, x2, y2); + + DrawHorizMapIndicator(x, y, x2, y); + DrawHorizMapIndicator(x, y2, x2, y2); + } + _cur_dpi = old_dpi; + } + + void SmallMapCenterOnCurrentPos() + { + int x, y; + ViewPort *vp; + vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; + + x = ((vp->virtual_width - (this->widget[SM_WIDGET_MAP].right - this->widget[SM_WIDGET_MAP].left) * TILE_SIZE) / 2 + vp->virtual_left) / 4; + y = ((vp->virtual_height - (this->widget[SM_WIDGET_MAP].bottom - this->widget[SM_WIDGET_MAP].top ) * TILE_SIZE) / 2 + vp->virtual_top ) / 2 - TILE_SIZE * 2; + this->scroll_x = (y - x) & ~0xF; + this->scroll_y = (x + y) & ~0xF; + this->SetDirty(); + } + + SmallMapWindow(const WindowDesc *desc, void *data, int window_number) : Window(desc, data, window_number) + { + /* Resize the window to fit industries list */ + if (_industries_per_column > BASE_NB_PER_COLUMN) { + uint diff = ((_industries_per_column - BASE_NB_PER_COLUMN) * BASE_NB_PER_COLUMN) + 1; + + this->height = this->height + diff; + + Widget *wi = &this->widget[SM_WIDGET_LEGEND]; // label panel + wi->bottom = wi->bottom + diff; + + wi = &this->widget[SM_WIDGET_BUTTONSPANEL]; // filler panel under smallmap buttons + wi->bottom = wi->bottom + diff - 1; + + /* Change widget position + * - footer panel + * - enable all industry + * - disable all industry + * - resize window button + */ + for (uint i = SM_WIDGET_BOTTOMPANEL; i <= SM_WIDGET_RESIZEBOX; i++) { + wi = &this->widget[i]; + wi->top = wi->top + diff; + wi->bottom = wi->bottom + diff; + } } - /* 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]); - } + this->LowerWidget(_smallmap_type + SMT_OWNER); + this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, _smallmap_show_towns); -skip_column: - if (y == 0) { - tile_y++; - y++; - ptr = blitter->MoveTo(ptr, 0, 1); - } else { - tile_x--; - y--; - ptr = blitter->MoveTo(ptr, 0, -1); - } - ptr = blitter->MoveTo(ptr, 2, 0); - x += 2; + this->SmallMapCenterOnCurrentPos(); + this->FindWindowPlacementAndResize(desc); } - /* draw vehicles? */ - if (type == SMT_CONTOUR || type == SMT_VEHICLES) { - Vehicle *v; - bool skip; - byte color; + virtual void OnPaint() + { + const LegendAndColour *tbl; + int x, y, y_org; + uint diff; + DrawPixelInfo new_dpi; + + /* Hide Enable all/Disable all buttons if is not industry type small map*/ + this->SetWidgetHiddenState(SM_WIDGET_ENABLEINDUSTRIES, _smallmap_type != SMT_INDUSTRY); + this->SetWidgetHiddenState(SM_WIDGET_DISABLEINDUSTRIES, _smallmap_type != SMT_INDUSTRY); - FOR_ALL_VEHICLES(v) { - if (v->type != VEH_EFFECT && - (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 - 0); - x = pt.x; - y = pt.y; + /* draw the window */ + SetDParam(0, STR_00E5_CONTOURS + _smallmap_type); + DrawWindowWidgets(this); + + tbl = _legend_table[_smallmap_type]; - /* Check if y is out of bounds? */ - y -= dpi->top; - if (!IsInsideMM(y, 0, dpi->height)) continue; + /* difference in window size */ + diff = (_industries_per_column > BASE_NB_PER_COLUMN) ? ((_industries_per_column - BASE_NB_PER_COLUMN) * BASE_NB_PER_COLUMN) + 1 : 0; + + x = 4; + y_org = this->height - 44 - 11 - diff; + y = y_org; - /* Default is to draw both pixels. */ - skip = false; - - /* Offset X coordinate */ - x -= WP(w, smallmap_d).subscroll + 3 + dpi->left; + for (;;) { + if (_smallmap_type == SMT_INDUSTRY) { + /* Industry name must be formated, since it's not in tiny font in the specs. + * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font.*/ + SetDParam(0, tbl->legend); + assert(tbl->type < NUM_INDUSTRYTYPES); + SetDParam(1, _industry_counts[tbl->type]); + if (!tbl->show_on_map) { + /* Simply draw the string, not the black border of the legend color. + * This will enforce the idea of the disabled item */ + DrawString(x + 11, y, STR_SMALLMAP_INDUSTRY, TC_GREY); + } else { + DrawString(x + 11, y, STR_SMALLMAP_INDUSTRY, TC_BLACK); + GfxFillRect(x, y + 1, x + 8, y + 5, 0); // outer border of the legend color + } + } else { + /* Anything that is not an industry is using normal process */ + GfxFillRect(x, y + 1, x + 8, y + 5, 0); + DrawString(x + 11, y, tbl->legend, TC_FROMSTRING); + } + GfxFillRect(x + 1, y + 2, x + 7, y + 4, tbl->colour); // legend color - 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; - } + tbl += 1; + y += 6; - /* Calculate pointer to pixel and the color */ - color = (type == SMT_VEHICLES) ? _vehicle_type_colors[v->type] : 0xF; - - /* And draw either one or two pixels depending on clipping */ - blitter->SetPixel(dpi->dst_ptr, x, y, color); - if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, color); + if (tbl->end) { // end of the list + break; + } else if (tbl->col_break) { + /* break asked, continue at top, 123 pixels (one "row") to the right */ + x += 123; + y = y_org; } } + + if (!FillDrawPixelInfo(&new_dpi, 3, 17, this->width - 28 + 22, this->height - 64 - 11 - diff)) return; + + this->DrawSmallMap(&new_dpi, _smallmap_type, _smallmap_show_towns); } - if (show_towns) { - const Town *t; + virtual void OnClick(Point pt, int widget) + { + switch (widget) { + case SM_WIDGET_MAP: { // Map window + /* + * XXX: scrolling with the left mouse button is done by subsequently + * clicking with the left mouse button; clicking once centers the + * large map at the selected point. So by unclicking the left mouse + * button here, it gets reclicked during the next inputloop, which + * would make it look like the mouse is being dragged, while it is + * actually being (virtually) clicked every inputloop. + */ + _left_button_clicked = false; + + Point pt = RemapCoords(this->scroll_x, this->scroll_y, 0); + Window *w = FindWindowById(WC_MAIN_WINDOW, 0); + w->viewport->dest_scrollpos_x = pt.x + ((_cursor.pos.x - this->left + 2) << 4) - (w->viewport->virtual_width >> 1); + w->viewport->dest_scrollpos_y = pt.y + ((_cursor.pos.y - this->top - 16) << 4) - (w->viewport->virtual_height >> 1); + + this->SetDirty(); + } break; + + case SM_WIDGET_CONTOUR: // Show land contours + case SM_WIDGET_VEHICLES: // Show vehicles + case SM_WIDGET_INDUSTRIES: // Show industries + case SM_WIDGET_ROUTES: // Show transport routes + case SM_WIDGET_VEGETATION: // Show vegetation + case SM_WIDGET_OWNERS: // Show land owners + this->RaiseWidget(_smallmap_type + SM_WIDGET_CONTOUR); + _smallmap_type = widget - SM_WIDGET_CONTOUR; + this->LowerWidget(_smallmap_type + SM_WIDGET_CONTOUR); + + this->SetDirty(); + SndPlayFx(SND_15_BEEP); + break; + + case SM_WIDGET_CENTERMAP: // Center the smallmap again + this->SmallMapCenterOnCurrentPos(); + + this->SetDirty(); + SndPlayFx(SND_15_BEEP); + break; + + case SM_WIDGET_TOGGLETOWNNAME: // Toggle town names + this->ToggleWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME); + _smallmap_show_towns = this->IsWidgetLowered(SM_WIDGET_TOGGLETOWNNAME); + + this->SetDirty(); + SndPlayFx(SND_15_BEEP); + break; - 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, - 0); - x = pt.x - WP(w, smallmap_d).subscroll + 3 - (t->sign.width_2 >> 1); - y = pt.y; + case SM_WIDGET_LEGEND: // Legend + /* if industry type small map*/ + if (_smallmap_type == SMT_INDUSTRY) { + /* if click on industries label, find right industry type and enable/disable it */ + Widget *wi = &this->widget[SM_WIDGET_LEGEND]; // label panel + uint column = (pt.x - 4) / 123; + uint line = (pt.y - wi->top - 2) / 6; + uint free = _smallmap_industry_count % 3; + + if (column <= 3) { + /* check if click is on industry label*/ + uint industry_pos = 0; + for (uint i = 0; i <= column; i++) { + uint diff = (free > 0) ? 1 : 0; + uint max_column_lines = _industries_per_column + diff; + + if (i < column) industry_pos = industry_pos + _industries_per_column + diff; - /* Check if the town sign is within bounds */ - if (x + t->sign.width_2 > dpi->left && - x < dpi->left + dpi->width && - y + 6 > dpi->top && - y < dpi->top + dpi->height) { - /* And draw it. */ - SetDParam(0, t->index); - DrawString(x, y, STR_2056, TC_WHITE); - } + if (i == column && line <= max_column_lines - 1) { + industry_pos = industry_pos + line; + _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map; + } + if( free > 0) free--; + } + } + /* Raise the two buttons "all", as we have done a specific choice */ + this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES); + this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES); + this->SetDirty(); + } + break; + + case SM_WIDGET_ENABLEINDUSTRIES: // Enable all industries + for (int i = 0; i != _smallmap_industry_count; i++) { + _legend_from_industries[i].show_on_map = true; + } + /* toggle appeareance indicating the choice */ + this->LowerWidget(SM_WIDGET_ENABLEINDUSTRIES); + this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES); + this->SetDirty(); + break; + + case SM_WIDGET_DISABLEINDUSTRIES: // disable all industries + for (int i = 0; i != _smallmap_industry_count; i++) { + _legend_from_industries[i].show_on_map = false; + } + /* toggle appeareance indicating the choice */ + this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES); + this->LowerWidget(SM_WIDGET_DISABLEINDUSTRIES); + this->SetDirty(); + break; } } - /* Draw map indicators */ + virtual void OnRightClick(Point pt, int widget) { - Point pt; - - /* Find main viewport. */ - 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 - pt.x; - y = vp->virtual_top - pt.y; - x2 = (x + vp->virtual_width) / TILE_SIZE; - y2 = (y + vp->virtual_height) / TILE_SIZE; - x /= TILE_SIZE; - y /= TILE_SIZE; - - x -= WP(w, smallmap_d).subscroll; - x2 -= WP(w, smallmap_d).subscroll; - - DrawVertMapIndicator(x, y, x, y2); - DrawVertMapIndicator(x2, y, x2, y2); - - DrawHorizMapIndicator(x, y, x2, y); - DrawHorizMapIndicator(x, y2, x2, y2); + if (widget == SM_WIDGET_MAP) { + if (_scrolling_viewport) return; + _scrolling_viewport = true; + _cursor.delta.x = 0; + _cursor.delta.y = 0; + } } - _cur_dpi = old_dpi; -} - -void SmallMapCenterOnCurrentPos(Window *w) -{ - int x, y; - ViewPort *vp; - vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; - x = ((vp->virtual_width - (w->widget[SM_WIDGET_MAP].right - w->widget[SM_WIDGET_MAP].left) * TILE_SIZE) / 2 + vp->virtual_left) / 4; - y = ((vp->virtual_height - (w->widget[SM_WIDGET_MAP].bottom - w->widget[SM_WIDGET_MAP].top ) * TILE_SIZE) / 2 + vp->virtual_top ) / 2 - TILE_SIZE * 2; - WP(w, smallmap_d).scroll_x = (y - x) & ~0xF; - WP(w, smallmap_d).scroll_y = (x + y) & ~0xF; - w->SetDirty(); -} - -enum { - BASE_NB_PER_COLUMN = 6, -}; - -static void SmallMapWindowProc(Window *w, WindowEvent *e) -{ - switch (e->event) { - case WE_PAINT: { - const LegendAndColour *tbl; - int x, y, y_org; - uint diff; - DrawPixelInfo new_dpi; - - /* Hide Enable all/Disable all buttons if is not industry type small map*/ - w->SetWidgetHiddenState(SM_WIDGET_ENABLEINDUSTRIES, _smallmap_type != SMT_INDUSTRY); - w->SetWidgetHiddenState(SM_WIDGET_DISABLEINDUSTRIES, _smallmap_type != SMT_INDUSTRY); - - /* draw the window */ - SetDParam(0, STR_00E5_CONTOURS + _smallmap_type); - DrawWindowWidgets(w); - - tbl = _legend_table[_smallmap_type]; - - /* difference in window size */ - diff = (_industries_per_column > BASE_NB_PER_COLUMN) ? ((_industries_per_column - BASE_NB_PER_COLUMN) * BASE_NB_PER_COLUMN) + 1 : 0; - - x = 4; - y_org = w->height - 44 - 11 - diff; - y = y_org; + virtual void OnTick() + { + /* update the window every now and then */ + if ((++this->vscroll.pos & 0x1F) == 0) this->SetDirty(); + } - for (;;) { + virtual void OnScroll(Point delta) + { + _cursor.fix_at = true; - if (_smallmap_type == SMT_INDUSTRY) { - /* Industry name must be formated, since it's not in tiny font in the specs. - * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font.*/ - SetDParam(0, tbl->legend); - assert(tbl->type < NUM_INDUSTRYTYPES); - SetDParam(1, _industry_counts[tbl->type]); - if (!tbl->show_on_map) { - /* Simply draw the string, not the black border of the legend color. - * This will enforce the idea of the disabled item */ - DrawString(x + 11, y, STR_SMALLMAP_INDUSTRY, TC_GREY); - } else { - DrawString(x + 11, y, STR_SMALLMAP_INDUSTRY, TC_BLACK); - GfxFillRect(x, y + 1, x + 8, y + 5, 0); // outer border of the legend color - } - } else { - /* Anything that is not an industry is using normal process */ - GfxFillRect(x, y + 1, x + 8, y + 5, 0); - DrawString(x + 11, y, tbl->legend, TC_FROMSTRING); - } - GfxFillRect(x + 1, y + 2, x + 7, y + 4, tbl->colour); // legend color - - tbl += 1; - y += 6; - - if (tbl->end) { // end of the list - break; - } else if (tbl->col_break) { - /* break asked, continue at top, 123 pixels (one "row") to the right */ - x += 123; - y = y_org; - } - } + int x = this->scroll_x; + int y = this->scroll_y; - if (!FillDrawPixelInfo(&new_dpi, 3, 17, w->width - 28 + 22, w->height - 64 - 11 - diff)) - return; - - DrawSmallMap(&new_dpi, w, _smallmap_type, _smallmap_show_towns); - } break; - - case WE_CLICK: - switch (e->we.click.widget) { - case SM_WIDGET_MAP: { // Map window - Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0); - Point pt; + int sub = this->subscroll + delta.x; - /* - * XXX: scrolling with the left mouse button is done by subsequently - * clicking with the left mouse button; clicking once centers the - * large map at the selected point. So by unclicking the left mouse - * button here, it gets reclicked during the next inputloop, which - * would make it look like the mouse is being dragged, while it is - * actually being (virtually) clicked every inputloop. - */ - _left_button_clicked = false; + x -= (sub >> 2) << 4; + y += (sub >> 2) << 4; + sub &= 3; - pt = RemapCoords(WP(w, smallmap_d).scroll_x, WP(w,smallmap_d).scroll_y, 0); - w2->viewport->dest_scrollpos_x = pt.x + ((_cursor.pos.x - w->left + 2) << 4) - (w2->viewport->virtual_width >> 1); - w2->viewport->dest_scrollpos_y = pt.y + ((_cursor.pos.y - w->top - 16) << 4) - (w2->viewport->virtual_height >> 1); - - w->SetDirty(); - } break; - - case SM_WIDGET_CONTOUR: // Show land contours - case SM_WIDGET_VEHICLES: // Show vehicles - case SM_WIDGET_INDUSTRIES: // Show industries - case SM_WIDGET_ROUTES: // Show transport routes - case SM_WIDGET_VEGETATION: // Show vegetation - case SM_WIDGET_OWNERS: // Show land owners - w->RaiseWidget(_smallmap_type + SM_WIDGET_CONTOUR); - _smallmap_type = e->we.click.widget - SM_WIDGET_CONTOUR; - w->LowerWidget(_smallmap_type + SM_WIDGET_CONTOUR); + x += (delta.y >> 1) << 4; + y += (delta.y >> 1) << 4; - w->SetDirty(); - SndPlayFx(SND_15_BEEP); - break; - - case SM_WIDGET_CENTERMAP: // Center the smallmap again - SmallMapCenterOnCurrentPos(w); - - w->SetDirty(); - SndPlayFx(SND_15_BEEP); - break; - - case SM_WIDGET_TOGGLETOWNNAME: // Toggle town names - w->ToggleWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME); - _smallmap_show_towns = w->IsWidgetLowered(SM_WIDGET_TOGGLETOWNNAME); - - w->SetDirty(); - SndPlayFx(SND_15_BEEP); - break; - - case SM_WIDGET_LEGEND: // Legend - /* if industry type small map*/ - if (_smallmap_type == SMT_INDUSTRY) { - /* if click on industries label, find right industry type and enable/disable it */ - Widget *wi = &w->widget[SM_WIDGET_LEGEND]; // label panel - uint column = (e->we.click.pt.x - 4) / 123; - uint line = (e->we.click.pt.y - wi->top - 2) / 6; - uint free = _smallmap_industry_count % 3; - - if (column <= 3) { - /* check if click is on industry label*/ - uint industry_pos = 0; - for (uint i = 0; i <= column; i++) { - uint diff = (free > 0) ? 1 : 0; - uint max_column_lines = _industries_per_column + diff; - - if (i < column) industry_pos = industry_pos + _industries_per_column + diff; - - if (i == column && line <= max_column_lines - 1) { - industry_pos = industry_pos + line; - _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map; - } - if( free > 0) free--; - } - } - /* Raise the two buttons "all", as we have done a specific choice */ - w->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES); - w->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES); - w->SetDirty(); - } - break; - - case SM_WIDGET_ENABLEINDUSTRIES: // Enable all industries - for (int i = 0; i != _smallmap_industry_count; i++) { - _legend_from_industries[i].show_on_map = true; - } - /* toggle appeareance indicating the choice */ - w->LowerWidget(SM_WIDGET_ENABLEINDUSTRIES); - w->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES); - w->SetDirty(); - break; - - case SM_WIDGET_DISABLEINDUSTRIES: // disable all industries - for (int i = 0; i != _smallmap_industry_count; i++) { - _legend_from_industries[i].show_on_map = false; - } - /* toggle appeareance indicating the choice */ - w->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES); - w->LowerWidget(SM_WIDGET_DISABLEINDUSTRIES); - w->SetDirty(); - break; - } - break; + if (delta.y & 1) { + x += TILE_SIZE; + sub += 2; + if (sub > 3) { + sub -= 4; + x -= TILE_SIZE; + y += TILE_SIZE; + } + } - case WE_RCLICK: - if (e->we.click.widget == SM_WIDGET_MAP) { - if (_scrolling_viewport) return; - _scrolling_viewport = true; - _cursor.delta.x = 0; - _cursor.delta.y = 0; - } - break; - - case WE_TICK: - /* update the window every now and then */ - if ((++w->vscroll.pos & 0x1F) == 0) w->SetDirty(); - break; - - case WE_SCROLL: { - 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 + e->we.scroll.delta.x; - - x -= (sub >> 2) << 4; - y += (sub >> 2) << 4; - sub &= 3; - - x += (e->we.scroll.delta.y >> 1) << 4; - y += (e->we.scroll.delta.y >> 1) << 4; + int hx = (this->widget[SM_WIDGET_MAP].right - this->widget[SM_WIDGET_MAP].left) / 2; + int hy = (this->widget[SM_WIDGET_MAP].bottom - this->widget[SM_WIDGET_MAP].top ) / 2; + int hvx = hx * -4 + hy * 8; + int hvy = hx * 4 + hy * 8; + if (x < -hvx) { + x = -hvx; + sub = 0; + } + if (x > (int)MapMaxX() * TILE_SIZE - hvx) { + x = MapMaxX() * TILE_SIZE - hvx; + sub = 0; + } + if (y < -hvy) { + y = -hvy; + sub = 0; + } + if (y > (int)MapMaxY() * TILE_SIZE - hvy) { + y = MapMaxY() * TILE_SIZE - hvy; + sub = 0; + } - if (e->we.scroll.delta.y & 1) { - x += TILE_SIZE; - sub += 2; - if (sub > 3) { - sub -= 4; - x -= TILE_SIZE; - y += TILE_SIZE; - } - } + this->scroll_x = x; + this->scroll_y = y; + this->subscroll = sub; - hx = (w->widget[SM_WIDGET_MAP].right - w->widget[SM_WIDGET_MAP].left) / 2; - hy = (w->widget[SM_WIDGET_MAP].bottom - w->widget[SM_WIDGET_MAP].top ) / 2; - hvx = hx * -4 + hy * 8; - hvy = hx * 4 + hy * 8; - if (x < -hvx) { - x = -hvx; - sub = 0; - } - if (x > (int)MapMaxX() * TILE_SIZE - hvx) { - x = MapMaxX() * TILE_SIZE - hvx; - sub = 0; - } - if (y < -hvy) { - y = -hvy; - sub = 0; - } - if (y > (int)MapMaxY() * TILE_SIZE - hvy) { - y = MapMaxY() * TILE_SIZE - hvy; - sub = 0; - } - - WP(w, smallmap_d).scroll_x = x; - WP(w, smallmap_d).scroll_y = y; - WP(w, smallmap_d).subscroll = sub; - - w->SetDirty(); - } break; + this->SetDirty(); } -} +}; static const WindowDesc _smallmap_desc = { WDP_AUTO, WDP_AUTO, 350, 214, 446, 314, WC_SMALLMAP, WC_NONE, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE, _smallmap_widgets, - SmallMapWindowProc + NULL }; void ShowSmallMap() { - Window *w; - - w = AllocateWindowDescFront(&_smallmap_desc, 0); - if (w == NULL) return; - - /* Resize the window to fit industries list */ - if (_industries_per_column > BASE_NB_PER_COLUMN) { - uint diff = ((_industries_per_column - BASE_NB_PER_COLUMN) * BASE_NB_PER_COLUMN) + 1; - - w->height = w->height + diff; - - Widget *wi = &w->widget[SM_WIDGET_LEGEND]; // label panel - wi->bottom = wi->bottom + diff; - - wi = &w->widget[SM_WIDGET_BUTTONSPANEL]; // filler panel under smallmap buttons - wi->bottom = wi->bottom + diff - 1; - - /* Change widget position - * - footer panel - * - enable all industry - * - disable all industry - * - resize window button - */ - for (uint i = SM_WIDGET_BOTTOMPANEL; i <= SM_WIDGET_RESIZEBOX; i++) { - wi = &w->widget[i]; - wi->top = wi->top + diff; - wi->bottom = wi->bottom + diff; - } - } - - w->LowerWidget(_smallmap_type + SMT_OWNER); - w->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, _smallmap_show_towns); - - SmallMapCenterOnCurrentPos(w); + AllocateWindowDescFront(&_smallmap_desc, 0); } /* Extra ViewPort Window Stuff */ @@ -1225,3 +1215,19 @@ void ShowExtraViewPortWindow(TileIndex t w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y; } } + +bool ScrollMainWindowTo(int x, int y, bool instant) +{ + bool res = ScrollWindowTo(x, y, FindWindowById(WC_MAIN_WINDOW, 0), instant); + + /* If a user scrolls to a tile (via what way what so ever) and already is on + * that tile (e.g.: pressed twice), move the smallmap to that location, + * so you directly see where you are on the smallmap. */ + + if (res) return res; + + SmallMapWindow *w = dynamic_cast(FindWindowById(WC_SMALLMAP, 0)); + if (w != NULL) w->SmallMapCenterOnCurrentPos(); + + return res; +} diff --git a/src/viewport.cpp b/src/viewport.cpp --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -144,8 +144,6 @@ TileHighlightData _thd; static TileInfo *_cur_ti; bool _draw_bounding_boxes = false; -extern void SmallMapCenterOnCurrentPos(Window *w); - static Point MapXYZToViewport(const ViewPort *vp, uint x, uint y, uint z) { Point p = RemapCoords(x, y, z); @@ -2079,27 +2077,6 @@ bool ScrollWindowTo(int x , int y, Windo return true; } - -bool ScrollMainWindowTo(int x, int y, bool instant) -{ - Window *w; - bool res = ScrollWindowTo(x, y, FindWindowById(WC_MAIN_WINDOW, 0), instant); - - /* If a user scrolls to a tile (via what way what so ever) and already is on - * that tile (e.g.: pressed twice), move the smallmap to that location, - * so you directly see where you are on the smallmap. */ - - if (res) return res; - - w = FindWindowById(WC_SMALLMAP, 0); - if (w == NULL) return res; - - SmallMapCenterOnCurrentPos(w); - - return res; -} - - bool ScrollMainWindowToTile(TileIndex tile, bool instant) { return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, instant);