diff --git a/src/lang/english.txt b/src/lang/english.txt index a8ed981464..69e4f3c989 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -521,7 +521,7 @@ STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Message history STR_NEWS_MENU_DELETE_ALL_MESSAGES :Delete all messages # About menu -###length 11 +###length 12 STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information STR_ABOUT_MENU_HELP :Help & manuals STR_ABOUT_MENU_SEPARATOR : @@ -533,6 +533,7 @@ STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle colouring of dirty blocks +STR_ABOUT_MENU_TOGGLE_WIDGET_OUTLINES :Toggle widget outlines # Place in highscore window ###length 15 diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 36578e4672..ec1648b08d 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -186,6 +186,7 @@ enum { GHK_CONSOLE, GHK_BOUNDING_BOXES, GHK_DIRTY_BLOCKS, + GHK_WIDGET_OUTLINES, GHK_CENTER, GHK_CENTER_ZOOM, GHK_RESET_OBJECT_TO_PLACE, @@ -307,6 +308,10 @@ struct MainWindow : Window case GHK_DIRTY_BLOCKS: ToggleDirtyBlocks(); return ES_HANDLED; + + case GHK_WIDGET_OUTLINES: + ToggleWidgetOutlines(); + return ES_HANDLED; } if (_game_mode == GM_MENU) return ES_NOT_HANDLED; @@ -467,6 +472,7 @@ struct MainWindow : Window Hotkey(WKC_BACKQUOTE, "console", GHK_CONSOLE), Hotkey('B' | WKC_CTRL, "bounding_boxes", GHK_BOUNDING_BOXES), Hotkey('I' | WKC_CTRL, "dirty_blocks", GHK_DIRTY_BLOCKS), + Hotkey('O' | WKC_CTRL, "widget_outlines", GHK_WIDGET_OUTLINES), Hotkey('C', "center", GHK_CENTER), Hotkey('Z', "center_zoom", GHK_CENTER_ZOOM), Hotkey(WKC_ESC, "reset_object_to_place", GHK_RESET_OBJECT_TO_PLACE), diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 23d2c73929..2fa08a805f 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1100,7 +1100,7 @@ static CallBackFunction PlaceLandBlockInfo() static CallBackFunction ToolbarHelpClick(Window *w) { - PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_HELP : (int)WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 11 : 8); + PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_HELP : (int)WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 12 : 8); return CBF_NONE; } @@ -1138,6 +1138,20 @@ void ToggleDirtyBlocks() } } +/** + * Toggle drawing of widget outlihes. + * @note has only an effect when newgrf_developer_tools are active. + */ +void ToggleWidgetOutlines() +{ + extern bool _draw_widget_outlines; + /* Always allow to toggle them off */ + if (_settings_client.gui.newgrf_developer_tools || _draw_widget_outlines) { + _draw_widget_outlines = !_draw_widget_outlines; + MarkWholeScreenDirty(); + } +} + /** * Set the starting year for a scenario. * @param year New starting year. @@ -1169,6 +1183,7 @@ static CallBackFunction MenuClickHelp(int index) case 8: ShowSpriteAlignerWindow(); break; case 9: ToggleBoundingBoxes(); break; case 10: ToggleDirtyBlocks(); break; + case 11: ToggleWidgetOutlines(); break; } return CBF_NONE; } diff --git a/src/toolbar_gui.h b/src/toolbar_gui.h index cede0a7c19..4c3f4360db 100644 --- a/src/toolbar_gui.h +++ b/src/toolbar_gui.h @@ -56,6 +56,7 @@ enum MainToolbarHotkeys { void AllocateToolbar(); void ToggleBoundingBoxes(); void ToggleDirtyBlocks(); +void ToggleWidgetOutlines(); extern uint _toolbar_width; diff --git a/src/widget.cpp b/src/widget.cpp index 3d8ad479e1..ebeefc55aa 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -915,6 +915,18 @@ int Window::SortButtonWidth() return NWidgetScrollbar::GetVerticalDimension().width + 1; } +bool _draw_widget_outlines; + +void DrawOutline(const Window *, const NWidgetBase *wid) +{ + if (!_draw_widget_outlines || wid->current_x == 0 || wid->current_y == 0) return; + + Rect r = wid->GetCurrentRect(); + GfxDrawLine(r.left, r.top, r.right, r.top, PC_WHITE, 1, 4); + GfxDrawLine(r.left, r.top, r.left, r.bottom, PC_WHITE, 1, 4); + GfxDrawLine(r.right, r.top, r.right, r.bottom, PC_WHITE, 1, 4); + GfxDrawLine(r.left, r.bottom, r.right, r.bottom, PC_WHITE, 1, 4); +} /** * @defgroup NestedWidgets Hierarchical widgets @@ -1308,6 +1320,8 @@ void NWidgetContainer::Draw(const Window *w) for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->Draw(w); } + + DrawOutline(w, this); } NWidgetCore *NWidgetContainer::GetWidgetFromPos(int x, int y) @@ -1420,6 +1434,7 @@ void NWidgetStacked::Draw(const Window *w) for (NWidgetBase *child_wid = this->head; child_wid != nullptr; plane++, child_wid = child_wid->next) { if (plane == this->shown_plane) { child_wid->Draw(w); + DrawOutline(w, this); return; } } @@ -1849,9 +1864,16 @@ void NWidgetSpacer::FillNestedArray(NWidgetBase **, uint) { } -void NWidgetSpacer::Draw(const Window *) +void NWidgetSpacer::Draw(const Window *w) { - /* Spacer widget is never visible. */ + /* Spacer widget is never normally visible. */ + + if (_draw_widget_outlines && this->current_x != 0 && this->current_y != 0) { + /* Spacers indicate a potential design issue, so get extra highlighting. */ + GfxFillRect(this->GetCurrentRect(), PC_WHITE, FILLRECT_CHECKER); + + DrawOutline(w, this); + } } void NWidgetSpacer::SetDirty(const Window *) const @@ -2030,39 +2052,44 @@ NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) bool rtl = _current_text_dir == TD_RTL; DrawPixelInfo tmp_dpi; if (!FillDrawPixelInfo(&tmp_dpi, this->pos_x + (rtl ? this->pip_post : this->pip_pre), this->pos_y + this->pip_pre, this->current_x - this->pip_pre - this->pip_post, this->current_y - this->pip_pre - this->pip_post)) return; - AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi); - /* Get the appropriate offsets so we can draw the right widgets. */ - NWidgetCore *child = dynamic_cast(this->head); - assert(child != nullptr); - int start_x, start_y, base_offs_x, base_offs_y; - this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); + { + AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi); - int offs_y = base_offs_y; - for (int y = start_y; y < start_y + this->widgets_y + 1; y++, offs_y += this->widget_h) { - /* Are we within bounds? */ - if (offs_y + child->smallest_y <= 0) continue; - if (offs_y >= (int)this->current_y) break; + /* Get the appropriate offsets so we can draw the right widgets. */ + NWidgetCore *child = dynamic_cast(this->head); + assert(child != nullptr); + int start_x, start_y, base_offs_x, base_offs_y; + this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); - /* We've passed our amount of widgets. */ - if (y * this->widgets_x >= this->count) break; - - int offs_x = base_offs_x; - for (int x = start_x; x < start_x + this->widgets_x + 1; x++, offs_x += rtl ? -this->widget_w : this->widget_w) { + int offs_y = base_offs_y; + for (int y = start_y; y < start_y + this->widgets_y + 1; y++, offs_y += this->widget_h) { /* Are we within bounds? */ - if (offs_x + child->smallest_x <= 0) continue; - if (offs_x >= (int)this->current_x) continue; + if (offs_y + child->smallest_y <= 0) continue; + if (offs_y >= (int)this->current_y) break; - /* Do we have this many widgets? */ - int sub_wid = y * this->widgets_x + x; - if (sub_wid >= this->count) break; + /* We've passed our amount of widgets. */ + if (y * this->widgets_x >= this->count) break; - child->AssignSizePosition(ST_RESIZE, offs_x, offs_y, child->smallest_x, child->smallest_y, rtl); - child->SetLowered(this->clicked == sub_wid); - SB(child->index, 16, 16, sub_wid); - child->Draw(w); + int offs_x = base_offs_x; + for (int x = start_x; x < start_x + this->widgets_x + 1; x++, offs_x += rtl ? -this->widget_w : this->widget_w) { + /* Are we within bounds? */ + if (offs_x + child->smallest_x <= 0) continue; + if (offs_x >= (int)this->current_x) continue; + + /* Do we have this many widgets? */ + int sub_wid = y * this->widgets_x + x; + if (sub_wid >= this->count) break; + + child->AssignSizePosition(ST_RESIZE, offs_x, offs_y, child->smallest_x, child->smallest_y, rtl); + child->SetLowered(this->clicked == sub_wid); + SB(child->index, 16, 16, sub_wid); + child->Draw(w); + } } } + + DrawOutline(w, this); } /** @@ -2275,6 +2302,8 @@ void NWidgetBackground::Draw(const Window *w) if (this->IsDisabled()) { GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); } + + DrawOutline(w, this); } NWidgetCore *NWidgetBackground::GetWidgetFromPos(int x, int y) @@ -2328,6 +2357,8 @@ void NWidgetViewport::Draw(const Window *w) GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, (this->disp_flags & ND_SHADE_DIMMED) ? PALETTE_TO_TRANSPARENT : PALETTE_NEWSPAPER, FILLRECT_RECOLOUR); } + + DrawOutline(w, this); } /** @@ -2527,6 +2558,8 @@ void NWidgetScrollbar::Draw(const Window *w) if (this->IsDisabled()) { GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); } + + DrawOutline(w, this); } /* static */ void NWidgetScrollbar::InvalidateDimensionCache() @@ -2872,6 +2905,10 @@ void NWidgetLeaf::Draw(const Window *w) bool clicked = this->IsLowered(); switch (this->type) { case WWT_EMPTY: + /* WWT_EMPTY used as a spacer indicates a potential design issue. */ + if (this->index == -1 && _draw_widget_outlines) { + GfxFillRect(r, PC_BLACK, FILLRECT_CHECKER); + } break; case WWT_PUSHBTN: @@ -2979,6 +3016,8 @@ void NWidgetLeaf::Draw(const Window *w) if (this->IsDisabled()) { GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); } + + DrawOutline(w, this); } /**