diff options
-rw-r--r-- | src/rail_gui.cpp | 27 | ||||
-rw-r--r-- | src/viewport.cpp | 164 | ||||
-rw-r--r-- | src/viewport_type.h | 21 |
3 files changed, 173 insertions, 39 deletions
diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index b0ab53f2d..42e84553c 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -76,29 +76,27 @@ static void GenericPlaceRail(TileIndex tile, int cmd) static void PlaceRail_N(TileIndex tile) { - int cmd = _tile_fract_coords.x > _tile_fract_coords.y ? 4 : 5; - GenericPlaceRail(tile, cmd); + VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); } static void PlaceRail_NE(TileIndex tile) { - VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_RAIL_NE); + VpStartPlaceSizing(tile, VPM_FIX_Y | VPM_RAILDIRS, DDSP_PLACE_RAIL); } static void PlaceRail_E(TileIndex tile) { - int cmd = _tile_fract_coords.x + _tile_fract_coords.y <= 15 ? 2 : 3; - GenericPlaceRail(tile, cmd); + VpStartPlaceSizing(tile, VPM_FIX_HORIZONTAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); } static void PlaceRail_NW(TileIndex tile) { - VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_RAIL_NW); + VpStartPlaceSizing(tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL); } static void PlaceRail_AutoRail(TileIndex tile) { - VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_AUTORAIL); + VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL); } /** @@ -332,7 +330,7 @@ static bool RailToolbar_CtrlChanged(Window *w) */ static void BuildRailClick_N(Window *w) { - HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_RECT, PlaceRail_N); + HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_LINE | HT_DIR_VL, PlaceRail_N); } /** @@ -342,7 +340,7 @@ static void BuildRailClick_N(Window *w) */ static void BuildRailClick_NE(Window *w) { - HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_RECT, PlaceRail_NE); + HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_LINE | HT_DIR_X, PlaceRail_NE); } /** @@ -352,7 +350,7 @@ static void BuildRailClick_NE(Window *w) */ static void BuildRailClick_E(Window *w) { - HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_RECT, PlaceRail_E); + HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_LINE | HT_DIR_HL, PlaceRail_E); } /** @@ -362,7 +360,7 @@ static void BuildRailClick_E(Window *w) */ static void BuildRailClick_NW(Window *w) { - HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_RECT, PlaceRail_NW); + HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_LINE | HT_DIR_Y, PlaceRail_NW); } /** @@ -704,7 +702,7 @@ struct BuildRailToolbarWindow : Window { ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype); break; - case DDSP_PLACE_AUTORAIL: + case DDSP_PLACE_RAIL: HandleAutodirPlacement(); break; @@ -728,11 +726,6 @@ struct BuildRailToolbarWindow : Window { } HandleStationPlacement(start_tile, end_tile); break; - - case DDSP_PLACE_RAIL_NE: - case DDSP_PLACE_RAIL_NW: - DoRailroadTrack(select_proc == DDSP_PLACE_RAIL_NE ? TRACK_X : TRACK_Y); - break; } } } diff --git a/src/viewport.cpp b/src/viewport.cpp index 0feca0c8d..724fa1202 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -900,7 +900,7 @@ static void DrawTileSelection(const TileInfo *ti) } } DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part); - } else if (_thd.drawstyle & HT_RAIL /* && _thd.place_mode == VHM_RAIL*/) { + } else if (_thd.drawstyle & HT_RAIL) { /* autorail highlight piece under cursor */ HighLightStyle type = _thd.drawstyle & HT_DIR_MASK; assert(type < HT_DIR_END); @@ -2171,7 +2171,7 @@ void UpdateTileSelection() x1 = pt.x; y1 = pt.y; if (x1 != -1) { - switch (_thd.place_mode) { + switch (_thd.place_mode & HT_DRAG_MASK) { case HT_RECT: _thd.new_drawstyle = HT_RECT; break; @@ -2181,7 +2181,28 @@ void UpdateTileSelection() y1 += TILE_SIZE / 2; break; case HT_RAIL: - _thd.new_drawstyle = GetAutorailHT(pt.x, pt.y); // draw one highlighted tile + /* Draw one highlighted tile in any direction */ + _thd.new_drawstyle = GetAutorailHT(pt.x, pt.y); + break; + case HT_LINE: + switch (_thd.place_mode & HT_DIR_MASK) { + case HT_DIR_X: _thd.new_drawstyle = HT_LINE | HT_DIR_X; break; + case HT_DIR_Y: _thd.new_drawstyle = HT_LINE | HT_DIR_Y; break; + + case HT_DIR_HU: + case HT_DIR_HL: + _thd.new_drawstyle = (pt.x & TILE_UNIT_MASK) + (pt.y & TILE_UNIT_MASK) <= TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL; + break; + + case HT_DIR_VL: + case HT_DIR_VR: + _thd.new_drawstyle = (pt.x & TILE_UNIT_MASK) > (pt.y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; + break; + + default: NOT_REACHED(); + } + _thd.selstart.x = x1 & ~TILE_UNIT_MASK; + _thd.selstart.y = y1 & ~TILE_UNIT_MASK; break; default: NOT_REACHED(); @@ -2246,7 +2267,10 @@ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDrag if (_thd.place_mode == HT_RECT) { _thd.place_mode = HT_SPECIAL; _thd.next_drawstyle = HT_RECT; - } else if (_thd.place_mode == HT_RAIL) { // autorail one piece + } else if (_thd.place_mode & HT_RAIL) { + _thd.place_mode = HT_SPECIAL; + _thd.next_drawstyle = HT_RAIL; + } else if (_thd.place_mode & HT_LINE) { _thd.place_mode = HT_SPECIAL; _thd.next_drawstyle = _thd.drawstyle; } else { @@ -2436,6 +2460,35 @@ static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_t static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF}; +/** + * Check for underflowing the map. + * @param test the variable to test for underflowing + * @param other the other variable to update to keep the line + * @param mult the constant to multiply the difference by for \c other + */ +static void CheckUnderflow(int &test, int &other, int mult) +{ + if (test >= 0) return; + + other += mult * test; + test = 0; +} + +/** + * Check for overflowing the map. + * @param test the variable to test for overflowing + * @param other the other variable to update to keep the line + * @param max the maximum value for the \c test variable + * @param mult the constant to multiply the difference by for \c other + */ +static void CheckOverflow(int &test, int &other, int max, int mult) +{ + if (test <= max) return; + + other += mult * (test - max); + test = max; +} + /** while dragging */ static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y, int method) { @@ -2446,8 +2499,97 @@ static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y, int meth uint w = abs(dx) + TILE_SIZE; uint h = abs(dy) + TILE_SIZE; - if (TileVirtXY(thd->selstart.x, thd->selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile - if (method == VPM_RAILDIRS) { + if (method & ~(VPM_RAILDIRS | VPM_SIGNALDIRS)) { + /* We 'force' a selection direction; first four rail buttons. */ + method &= ~(VPM_RAILDIRS | VPM_SIGNALDIRS); + int raw_dx = thd->selstart.x - thd->selend.x; + int raw_dy = thd->selstart.y - thd->selend.y; + switch (method) { + case VPM_FIX_X: + b = HT_LINE | HT_DIR_Y; + x = thd->selstart.x; + break; + + case VPM_FIX_Y: + b = HT_LINE | HT_DIR_X; + y = thd->selstart.y; + break; + + case VPM_FIX_HORIZONTAL: + if (dx == -dy) { + /* We are on a straight horizontal line. Determine the 'rail' + * to build based the sub tile location. */ + b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; + } else { + /* We are not on a straight line. Determine the rail to build + * based on whether we are above or below it. */ + b = dx + dy >= TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL; + + /* Calculate where a horizontal line through the start point and + * a vertical line from the selected end point intersect and + * use that point as the end point. */ + int offset = (raw_dx - raw_dy) / 2; + x = thd->selstart.x - (offset & ~TILE_UNIT_MASK); + y = thd->selstart.y + (offset & ~TILE_UNIT_MASK); + + /* 'Build' the last half rail tile if needed */ + if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) { + if (dx + dy >= TILE_SIZE) { + x += (dx + dy < 0) ? TILE_SIZE : -TILE_SIZE; + } else { + y += (dx + dy < 0) ? TILE_SIZE : -TILE_SIZE; + } + } + + /* Make sure we do not overflow the map! */ + CheckUnderflow(x, y, 1); + CheckUnderflow(y, x, 1); + CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, 1); + CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, 1); + assert(x >= 0 && y >= 0 && x <= (int)MapMaxX() * TILE_SIZE && y <= (int)MapMaxY() * TILE_SIZE); + } + break; + + case VPM_FIX_VERTICAL: + if (dx == dy) { + /* We are on a straight vertical line. Determine the 'rail' + * to build based the sub tile location. */ + b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; + } else { + /* We are not on a straight line. Determine the rail to build + * based on whether we are left or right from it. */ + b = dx < dy ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; + + /* Calculate where a vertical line through the start point and + * a horizontal line from the selected end point intersect and + * use that point as the end point. */ + int offset = (raw_dx + raw_dy + TILE_SIZE) / 2; + x = thd->selstart.x - (offset & ~TILE_UNIT_MASK); + y = thd->selstart.y - (offset & ~TILE_UNIT_MASK); + + /* 'Build' the last half rail tile if needed */ + if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) { + if (dx - dy < 0) { + y += (dx > dy) ? TILE_SIZE : -TILE_SIZE; + } else { + x += (dx < dy) ? TILE_SIZE : -TILE_SIZE; + } + } + + /* Make sure we do not overflow the map! */ + CheckUnderflow(x, y, -1); + CheckUnderflow(y, x, -1); + CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, -1); + CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, -1); + assert(x >= 0 && y >= 0 && x <= (int)MapMaxX() * TILE_SIZE && y <= (int)MapMaxY() * TILE_SIZE); + } + break; + + default: + NOT_REACHED(); + } + } else if (TileVirtXY(thd->selstart.x, thd->selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile + if (method & VPM_RAILDIRS) { b = GetAutorailHT(x, y); } else { // rect for autosignals on one tile b = HT_RECT; @@ -2578,7 +2720,7 @@ void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method) } /* Special handling of drag in any (8-way) direction */ - if (method == VPM_RAILDIRS || method == VPM_SIGNALDIRS) { + if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) { _thd.selend.x = x; _thd.selend.y = y; CalcRaildirsDrawstyle(&_thd, x, y, method); @@ -2710,12 +2852,10 @@ bool VpHandlePlaceSizingDrag() _special_mouse_mode = WSM_NONE; if (_thd.next_drawstyle == HT_RECT) { _thd.place_mode = HT_RECT; - } else if (_thd.select_method == VPM_SIGNALDIRS) { // some might call this a hack... -- Dominik + } else if (_thd.select_method & VPM_SIGNALDIRS) { _thd.place_mode = HT_RECT; - } else if (_thd.next_drawstyle & HT_LINE) { - _thd.place_mode = HT_RAIL; - } else if (_thd.next_drawstyle & HT_RAIL) { - _thd.place_mode = HT_RAIL; + } else if (_thd.select_method & VPM_RAILDIRS) { + _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : HT_RAIL; } else { _thd.place_mode = HT_POINT; } diff --git a/src/viewport_type.h b/src/viewport_type.h index 09bf2dcf3..6822339cc 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -49,14 +49,17 @@ enum { /** Viewport place method (type of highlighted area and placed objects) */ enum ViewportPlaceMethod { - VPM_X_OR_Y = 0, ///< drag in X or Y direction - VPM_FIX_X = 1, ///< drag only in X axis - VPM_FIX_Y = 2, ///< drag only in Y axis - VPM_RAILDIRS = 3, ///< all rail directions - VPM_X_AND_Y = 4, ///< area of land in X and Y directions - VPM_X_AND_Y_LIMITED = 5, ///< area of land of limited size - VPM_SIGNALDIRS = 6, ///< similiar to VMP_RAILDIRS, but with different cursor + VPM_X_OR_Y = 0, ///< drag in X or Y direction + VPM_FIX_X = 1, ///< drag only in X axis + VPM_FIX_Y = 2, ///< drag only in Y axis + VPM_X_AND_Y = 3, ///< area of land in X and Y directions + VPM_X_AND_Y_LIMITED = 4, ///< area of land of limited size + VPM_FIX_HORIZONTAL = 5, ///< drag only in horizontal direction + VPM_FIX_VERTICAL = 6, ///< drag only in vertical direction + VPM_RAILDIRS = 0x40, ///< all rail directions + VPM_SIGNALDIRS = 0x80, ///< similiar to VMP_RAILDIRS, but with different cursor }; +DECLARE_ENUM_AS_BIT_SET(ViewportPlaceMethod); /** Drag and drop selection process, or, what to do with an area of land when * you've selected it. */ @@ -73,9 +76,7 @@ enum ViewportDragDropSelectionProcess { DDSP_BUILD_BRIDGE, /* Rail specific actions */ - DDSP_PLACE_RAIL_NE, - DDSP_PLACE_RAIL_NW, - DDSP_PLACE_AUTORAIL, + DDSP_PLACE_RAIL, DDSP_BUILD_SIGNALS, DDSP_BUILD_STATION, DDSP_REMOVE_STATION, |