mirror of https://github.com/OpenTTD/OpenTTD.git
Add: Debug tool to draw widget outlines. (#11401)
This is considered a developer tool and is controlled from the help menu (or default hotkey Ctrl-O). This draws a white dashed outline around widgets. NWidgetSpacer and (unused) WWT_EMPTY widgets are also filled with check pattern to highlight them, as they usually indicate a design issue.
This commit is contained in:
parent
129e98fbab
commit
c0aa9a5f87
|
@ -521,7 +521,7 @@ STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Message history
|
||||||
STR_NEWS_MENU_DELETE_ALL_MESSAGES :Delete all messages
|
STR_NEWS_MENU_DELETE_ALL_MESSAGES :Delete all messages
|
||||||
|
|
||||||
# About menu
|
# About menu
|
||||||
###length 11
|
###length 12
|
||||||
STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information
|
STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information
|
||||||
STR_ABOUT_MENU_HELP :Help & manuals
|
STR_ABOUT_MENU_HELP :Help & manuals
|
||||||
STR_ABOUT_MENU_SEPARATOR :
|
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_SPRITE_ALIGNER :Sprite aligner
|
||||||
STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes
|
STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes
|
||||||
STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle colouring of dirty blocks
|
STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle colouring of dirty blocks
|
||||||
|
STR_ABOUT_MENU_TOGGLE_WIDGET_OUTLINES :Toggle widget outlines
|
||||||
|
|
||||||
# Place in highscore window
|
# Place in highscore window
|
||||||
###length 15
|
###length 15
|
||||||
|
|
|
@ -186,6 +186,7 @@ enum {
|
||||||
GHK_CONSOLE,
|
GHK_CONSOLE,
|
||||||
GHK_BOUNDING_BOXES,
|
GHK_BOUNDING_BOXES,
|
||||||
GHK_DIRTY_BLOCKS,
|
GHK_DIRTY_BLOCKS,
|
||||||
|
GHK_WIDGET_OUTLINES,
|
||||||
GHK_CENTER,
|
GHK_CENTER,
|
||||||
GHK_CENTER_ZOOM,
|
GHK_CENTER_ZOOM,
|
||||||
GHK_RESET_OBJECT_TO_PLACE,
|
GHK_RESET_OBJECT_TO_PLACE,
|
||||||
|
@ -307,6 +308,10 @@ struct MainWindow : Window
|
||||||
case GHK_DIRTY_BLOCKS:
|
case GHK_DIRTY_BLOCKS:
|
||||||
ToggleDirtyBlocks();
|
ToggleDirtyBlocks();
|
||||||
return ES_HANDLED;
|
return ES_HANDLED;
|
||||||
|
|
||||||
|
case GHK_WIDGET_OUTLINES:
|
||||||
|
ToggleWidgetOutlines();
|
||||||
|
return ES_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_game_mode == GM_MENU) return ES_NOT_HANDLED;
|
if (_game_mode == GM_MENU) return ES_NOT_HANDLED;
|
||||||
|
@ -467,6 +472,7 @@ struct MainWindow : Window
|
||||||
Hotkey(WKC_BACKQUOTE, "console", GHK_CONSOLE),
|
Hotkey(WKC_BACKQUOTE, "console", GHK_CONSOLE),
|
||||||
Hotkey('B' | WKC_CTRL, "bounding_boxes", GHK_BOUNDING_BOXES),
|
Hotkey('B' | WKC_CTRL, "bounding_boxes", GHK_BOUNDING_BOXES),
|
||||||
Hotkey('I' | WKC_CTRL, "dirty_blocks", GHK_DIRTY_BLOCKS),
|
Hotkey('I' | WKC_CTRL, "dirty_blocks", GHK_DIRTY_BLOCKS),
|
||||||
|
Hotkey('O' | WKC_CTRL, "widget_outlines", GHK_WIDGET_OUTLINES),
|
||||||
Hotkey('C', "center", GHK_CENTER),
|
Hotkey('C', "center", GHK_CENTER),
|
||||||
Hotkey('Z', "center_zoom", GHK_CENTER_ZOOM),
|
Hotkey('Z', "center_zoom", GHK_CENTER_ZOOM),
|
||||||
Hotkey(WKC_ESC, "reset_object_to_place", GHK_RESET_OBJECT_TO_PLACE),
|
Hotkey(WKC_ESC, "reset_object_to_place", GHK_RESET_OBJECT_TO_PLACE),
|
||||||
|
|
|
@ -1100,7 +1100,7 @@ static CallBackFunction PlaceLandBlockInfo()
|
||||||
|
|
||||||
static CallBackFunction ToolbarHelpClick(Window *w)
|
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;
|
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.
|
* Set the starting year for a scenario.
|
||||||
* @param year New starting year.
|
* @param year New starting year.
|
||||||
|
@ -1169,6 +1183,7 @@ static CallBackFunction MenuClickHelp(int index)
|
||||||
case 8: ShowSpriteAlignerWindow(); break;
|
case 8: ShowSpriteAlignerWindow(); break;
|
||||||
case 9: ToggleBoundingBoxes(); break;
|
case 9: ToggleBoundingBoxes(); break;
|
||||||
case 10: ToggleDirtyBlocks(); break;
|
case 10: ToggleDirtyBlocks(); break;
|
||||||
|
case 11: ToggleWidgetOutlines(); break;
|
||||||
}
|
}
|
||||||
return CBF_NONE;
|
return CBF_NONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ enum MainToolbarHotkeys {
|
||||||
void AllocateToolbar();
|
void AllocateToolbar();
|
||||||
void ToggleBoundingBoxes();
|
void ToggleBoundingBoxes();
|
||||||
void ToggleDirtyBlocks();
|
void ToggleDirtyBlocks();
|
||||||
|
void ToggleWidgetOutlines();
|
||||||
|
|
||||||
extern uint _toolbar_width;
|
extern uint _toolbar_width;
|
||||||
|
|
||||||
|
|
|
@ -915,6 +915,18 @@ int Window::SortButtonWidth()
|
||||||
return NWidgetScrollbar::GetVerticalDimension().width + 1;
|
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
|
* @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) {
|
for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
|
||||||
child_wid->Draw(w);
|
child_wid->Draw(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawOutline(w, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
NWidgetCore *NWidgetContainer::GetWidgetFromPos(int x, int y)
|
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) {
|
for (NWidgetBase *child_wid = this->head; child_wid != nullptr; plane++, child_wid = child_wid->next) {
|
||||||
if (plane == this->shown_plane) {
|
if (plane == this->shown_plane) {
|
||||||
child_wid->Draw(w);
|
child_wid->Draw(w);
|
||||||
|
DrawOutline(w, this);
|
||||||
return;
|
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
|
void NWidgetSpacer::SetDirty(const Window *) const
|
||||||
|
@ -2030,39 +2052,44 @@ NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y)
|
||||||
bool rtl = _current_text_dir == TD_RTL;
|
bool rtl = _current_text_dir == TD_RTL;
|
||||||
DrawPixelInfo tmp_dpi;
|
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;
|
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<NWidgetCore *>(this->head);
|
AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
|
||||||
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);
|
|
||||||
|
|
||||||
int offs_y = base_offs_y;
|
/* Get the appropriate offsets so we can draw the right widgets. */
|
||||||
for (int y = start_y; y < start_y + this->widgets_y + 1; y++, offs_y += this->widget_h) {
|
NWidgetCore *child = dynamic_cast<NWidgetCore *>(this->head);
|
||||||
/* Are we within bounds? */
|
assert(child != nullptr);
|
||||||
if (offs_y + child->smallest_y <= 0) continue;
|
int start_x, start_y, base_offs_x, base_offs_y;
|
||||||
if (offs_y >= (int)this->current_y) break;
|
this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y);
|
||||||
|
|
||||||
/* We've passed our amount of widgets. */
|
int offs_y = base_offs_y;
|
||||||
if (y * this->widgets_x >= this->count) break;
|
for (int y = start_y; y < start_y + this->widgets_y + 1; y++, offs_y += this->widget_h) {
|
||||||
|
|
||||||
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? */
|
/* Are we within bounds? */
|
||||||
if (offs_x + child->smallest_x <= 0) continue;
|
if (offs_y + child->smallest_y <= 0) continue;
|
||||||
if (offs_x >= (int)this->current_x) continue;
|
if (offs_y >= (int)this->current_y) break;
|
||||||
|
|
||||||
/* Do we have this many widgets? */
|
/* We've passed our amount of widgets. */
|
||||||
int sub_wid = y * this->widgets_x + x;
|
if (y * this->widgets_x >= this->count) break;
|
||||||
if (sub_wid >= this->count) break;
|
|
||||||
|
|
||||||
child->AssignSizePosition(ST_RESIZE, offs_x, offs_y, child->smallest_x, child->smallest_y, rtl);
|
int offs_x = base_offs_x;
|
||||||
child->SetLowered(this->clicked == sub_wid);
|
for (int x = start_x; x < start_x + this->widgets_x + 1; x++, offs_x += rtl ? -this->widget_w : this->widget_w) {
|
||||||
SB(child->index, 16, 16, sub_wid);
|
/* Are we within bounds? */
|
||||||
child->Draw(w);
|
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()) {
|
if (this->IsDisabled()) {
|
||||||
GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
|
GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawOutline(w, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
NWidgetCore *NWidgetBackground::GetWidgetFromPos(int x, int y)
|
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,
|
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);
|
(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()) {
|
if (this->IsDisabled()) {
|
||||||
GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
|
GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawOutline(w, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void NWidgetScrollbar::InvalidateDimensionCache()
|
/* static */ void NWidgetScrollbar::InvalidateDimensionCache()
|
||||||
|
@ -2872,6 +2905,10 @@ void NWidgetLeaf::Draw(const Window *w)
|
||||||
bool clicked = this->IsLowered();
|
bool clicked = this->IsLowered();
|
||||||
switch (this->type) {
|
switch (this->type) {
|
||||||
case WWT_EMPTY:
|
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;
|
break;
|
||||||
|
|
||||||
case WWT_PUSHBTN:
|
case WWT_PUSHBTN:
|
||||||
|
@ -2979,6 +3016,8 @@ void NWidgetLeaf::Draw(const Window *w)
|
||||||
if (this->IsDisabled()) {
|
if (this->IsDisabled()) {
|
||||||
GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
|
GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawOutline(w, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue