Compare commits

..

21 commits

Author SHA1 Message Date
Atrik
d843c7349b Add test for queries with visibility checks 2026-08-05 22:19:49 +02:00
Atrik
192c1e9dc9 Enable attacks on foes visible through shared LOS
Adds baseRange parameter to parabolic queries for combined
2D + parabolic detection. StandGround and Chase stances now
use attack range (parabolic) with vision as baseRange, allowing
units to attack enemies visible through friendly vision.
Buildings benefit as well via BuildingAI.
2026-08-05 22:19:49 +02:00
Atrik
db8be29f82 Filter out hidden targets in CanAttack
Units should not be able to attack entities with "hidden" visibility.
Visible and fogged (mirage/retainInFog) targets remain attackable.
2026-07-23 10:08:24 +02:00
Atrik
150677672b Add tests for CanEverReachTarget and its helpers 2026-07-23 10:08:24 +02:00
Atrik
427682563d Prevent targeting unreachable turreted entities
Introduce CanEverReachTarget in the Attack component to check whether
a target is geometrically reachable at all, accounting for height
offsets and turreted units inside buildings.

For non-parabolic attacks (e.g. melee), a simple 3D distance check
from the closest approach point is used.

For parabolic attacks (e.g. ranged), the parabolic range formula
is used to determine if the height difference is surmountable
from the closest horizontal distance to the target.

Add GetClosestApproachDistanceToTurretPoint to TurretHolder
to estimate the minimum horizontal distance to a turret point,
using its local offset and the holder's obstruction size.
Passable buildings are not considered obstacles.

Fixes units on the ground trying to attack unreachable units on walls
or towers when the projectile's arc cannot reach the required height.
2026-07-23 10:08:24 +02:00
Atrik
24b50778fa Add GetEffectiveAttackRange wrapper
Wraps RangeManager.GetEffectiveParabolicRange for unified range
resolution. Maintains symmetry with GetRange(), improves readability,
and consistently translates NEVER_IN_RANGE.

Simplifies callers in UnitAI and Attack.
2026-07-23 10:08:24 +02:00
Atrik
b292c658e7 Fix range target detection for StandGround stance
StandGround units now use parabolic range queries to detect enemies,
accounting for terrain elevation and height offsets. This ensures
units on hills or when 'turreted', can detect enemies
that are in parabolic range but outside flat range.

Previously, StandGround detection used flat circular queries,
causing units to miss enemies in their elevation-buffed range.
Other stances are unaffected since they chase targets anyway.
2026-07-23 10:08:24 +02:00
Atrik
9506937fc3 Rename cmp to rangeManager for clarity 2026-07-23 10:08:24 +02:00
Atrik
ee463b1721 Add some tests for GetEffectiveParabolicRange 2026-07-23 10:08:24 +02:00
Atrik
0efde44f46 Fix terrain elevation not affecting attack range
The parabolic range formula in GetEffectiveParabolicRange was only
computating height differences from manual HeightOffset values,
completely ignoring actual terrain elevation.
This meant units on hills received no tactical advantage
despite the UI stat tooltip correctly showing extended ranges.

Fixes #8889
2026-07-23 10:08:24 +02:00
Atrik
1e09d33a9f Fix renamed entities on TurretPoint
Oversights from fb1c0d2a82

Fixes #8808
2026-07-23 10:08:24 +02:00
Atrik
8a7718cb6f Remove dead territory ownership code 2026-07-23 10:08:24 +02:00
phosit
9598c6c2e1
Only clone this.position when it's an object
Refs: #8951
2026-07-19 13:01:04 +02:00
phosit
e6f75f2c33
Fix displaying errors of map generation scripts
Displaying the error lead to a freeze.

Introduced in d842a134f9.
2026-07-19 11:17:35 +02:00
Ralph Sennhauser
6244d25f90
Don't generate SDL events on Atlas shutdown
WX may still generate mouse events after calling CVideoMode::Shutdown(),
so don't create SDL events triggering assertions.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-07-19 08:59:06 +02:00
Ralph Sennhauser
63629195ba
Wait for work to be finished before shutting down
Stopping the timers isn't sufficient, also wait for in-flight work to be
finished first.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-07-19 08:59:06 +02:00
Ralph Sennhauser
2fae39df3b
Use new WX event macros
Were added in 2010.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-07-18 13:32:23 +02:00
Ralph Sennhauser
f1181bada0 Don't install SDL default signal handler for Atlas
If we catch the signal we'd have to communicate that we terminated by
signal, which might depend on shell. There is also the issue of various
dialogs blocking regular quit which we don't want, so that would need
extra work as well.

As such just let the SIGINT/SIGTERM do there default action and forgo
cleanup and let the OS handle it.

Fixes: #198
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-07-18 11:50:31 +02:00
Ralph Sennhauser
309ed5ef28
Add fullscreen support to Atlas
Add a fullscreen toggle to the View menu and with a global hotkey,
reusing the default one from the main game.

Unlike the current implementation this one doesn't need the game canvas
to be focused and also works on GTK.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-07-18 11:33:17 +02:00
Ralph Sennhauser
3c8b7dfa7a
Fix Enter key behaviour on Windows
Commit fe192fe58f made it possible for
events to properly propagate to the top window. As on Windows Enter is
also used for navigation, i.e. used to trigger the dialogs default action,
which in our case seems to be quit.

Tell the wxSpinCtrl to fire wxEVT_TEXT_ENTER instead and handle it.

The wxCommandEvent wxEVT_TEXT_ENTER doesn't carry the value, so need to
use dynamic event binding (which is preferred way anyway).

Also show the numPlayerSpinner as a spinner instead of a text field to
match visuals to actual behaviour.

Fixes: #9026
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-07-18 11:24:36 +02:00
Ralph Sennhauser
32b9713781
Modernize Brush in Atlas
Use dynamic event bindings allowing to bind all events in all sort of
ways. Addionally no need for subclassing wx widgets.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2026-07-18 11:24:36 +02:00
58 changed files with 302 additions and 295 deletions

View file

@ -26,7 +26,7 @@ async function init(data)
"argument": data
} });
};
globalThis.cancelOnLoadGameError = async() =>
globalThis.cancelOnLoadGameError = async(errorMessage) =>
{
Engine.ResetCursor();
Engine.EndGame();

View file

@ -2280,7 +2280,7 @@ AttackPlan.prototype.Serialize = function()
"siegeState": this.siegeState,
"position5TurnsAgo": this.position5TurnsAgo,
"lastPosition": this.lastPosition,
"position": clone(this.position),
"position": this.position !== undefined ? clone(this.position) : undefined,
"isBlocked": this.isBlocked,
"targetPlayer": this.targetPlayer,
"target": this.target !== undefined ? this.target.id() : undefined,

View file

@ -75,6 +75,6 @@
<Acceleration op="mul">0.8</Acceleration>
</UnitMotion>
<Vision>
<Range>20</Range>
<Range>120</Range>
</Vision>
</Entity>

View file

@ -963,6 +963,11 @@ SDL_Window* CVideoMode::GetWindow()
return m_Window;
}
bool CVideoMode::IsInitialized() const
{
return m_IsInitialised;
}
void CVideoMode::SetWindowIcon()
{
// The window icon should be kept outside of art/textures/, or else it will be converted

View file

@ -95,6 +95,7 @@ public:
int GetBPP() const;
bool IsVSyncEnabled() const;
bool IsInitialized() const;
int GetDesktopXRes() const;
int GetDesktopYRes() const;

View file

@ -196,7 +196,7 @@ struct Query
bool enabled;
bool parabolic;
bool accountForSize; // If true, the query accounts for unit sizes, otherwise it treats all entities as points.
bool allowMirageBypass; // Allow mirages to bypass interface check
bool includeMirage; // Include mirage entities regardless of interface checks
};
/**
@ -331,7 +331,7 @@ struct SerializeHelper<Query>
serialize.Bool("enabled", value.enabled);
serialize.Bool("parabolic",value.parabolic);
serialize.Bool("account for size",value.accountForSize);
serialize.Bool("allowMirageBypass", value.allowMirageBypass);
serialize.Bool("includeMirage", value.includeMirage);
}
void operator()(ISerializer& serialize, const char* name, Query& value, const CSimContext&)
@ -968,22 +968,22 @@ public:
tag_t CreateActiveQuery(entity_id_t source,
entity_pos_t minRange, entity_pos_t maxRange,
const std::vector<int>& owners, int requiredInterface, u8 flags,
bool accountForSize, bool allowMirageBypass) override
bool accountForSize, bool includeMirage) override
{
tag_t id = m_QueryNext++;
Query q = ConstructQuery(source, minRange, maxRange, owners, requiredInterface, flags, accountForSize);
q.allowMirageBypass = allowMirageBypass;
q.includeMirage = includeMirage;
m_Queries[id] = q;
return id;
}
tag_t CreateActiveParabolicQuery(entity_id_t source,
entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t baseRange, entity_pos_t yOrigin,
const std::vector<int>& owners, int requiredInterface, u8 flags, bool allowMirageBypass = false) override
const std::vector<int>& owners, int requiredInterface, u8 flags, bool includeMirage = false) override
{
tag_t id = m_QueryNext++;
Query q = ConstructParabolicQuery(source, minRange, maxRange, baseRange, yOrigin, owners, requiredInterface, flags, true);
q.allowMirageBypass = allowMirageBypass;
q.includeMirage = includeMirage;
m_Queries[id] = q;
return id;
}
@ -1275,16 +1275,17 @@ public:
if (id == q.source.GetId())
return false;
// Ignore if it's missing the required interface but allow mirages to bypass if allowed
if (q.interface && !GetSimContext().GetComponentManager().QueryInterface(id, q.interface))
{
if (!q.allowMirageBypass)
return false;
// Check if this is a mirage entity
CmpPtr<ICmpMirage> cmpMirage(GetSimContext(), id);
bool isMirage = !!cmpMirage;
CmpPtr<ICmpMirage> cmpMirage(GetSimContext(), id);
if (!cmpMirage)
return false;
}
// If it's a mirage and we're not including mirages, skip it
if (isMirage && !q.includeMirage)
return false;
// If it's not a mirage, check interface normally
if (!isMirage && q.interface && !GetSimContext().GetComponentManager().QueryInterface(id, q.interface))
return false;
// Skip hidden entities (not visible to source player)
if (q.source.GetId() != INVALID_ENTITY)
@ -1596,7 +1597,7 @@ public:
q.maxRange = maxRange;
q.yOrigin = entity_pos_t::Zero();
q.accountForSize = accountForSize;
q.allowMirageBypass = false;
q.includeMirage = false;
if (q.accountForSize && q.source.GetId() != INVALID_ENTITY && q.maxRange != ALWAYS_IN_RANGE)
{
@ -1640,7 +1641,7 @@ public:
q.parabolic = true;
q.yOrigin = yOrigin;
q.baseRange = baseRange;
q.allowMirageBypass = false;
q.includeMirage = false;
return q;
}

View file

@ -161,13 +161,15 @@ public:
* @param requiredInterface if non-zero, an interface ID that matching entities must implement.
* @param flags if a entity in range has one of the flags set it will show up.
* @param accountForSize if true, compensate for source/target entity sizes.
* @param allowMirageBypass if true, mirage entities (entities in Fog-of-War)
* are allowed to bypass the requiredInterface check. This is needed for attack queries
* so units can target enemies they can see in fog. Defaults to false.
* @param includeMirage if true, mirage entities are included in results without
* interface checks (needed for targeting fogged enemies). Default false.
* When false (default), mirages are excluded entirely.
* @return unique non-zero identifier of query.
*/
virtual tag_t CreateActiveQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange,
const std::vector<int>& owners, int requiredInterface, u8 flags, bool accountForSize, bool allowMirageBypass = false) = 0;
virtual tag_t CreateActiveQuery(entity_id_t source,
entity_pos_t minRange, entity_pos_t maxRange,
const std::vector<int>& owners, int requiredInterface, u8 flags,
bool accountForSize, bool includeMirage = false) = 0;
/**
* Construct an active query of a parabolic form around the unit.
@ -184,15 +186,14 @@ public:
* @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
* @param requiredInterface if non-zero, an interface ID that matching entities must implement.
* @param flags if a entity in range has one of the flags set it will show up.
* @param allowMirageBypass if true, mirage entities (entities in Fog-of-War)
* are allowed to bypass the requiredInterface check. This is needed for attack queries
* so units can target enemies they can see in fog. Defaults to false.
* @param includeMirage if true, mirage entities are included in results without
* interface checks (needed for targeting fogged enemies). Default false.
* NB: this one has no accountForSize parameter (assumed true), because we currently can only have 7 arguments for JS functions.
* @return unique non-zero identifier of query.
*/
virtual tag_t CreateActiveParabolicQuery(entity_id_t source,
entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t baseRange, entity_pos_t yOrigin,
const std::vector<int>& owners, int requiredInterface, u8 flags, bool allowMirageBypass = false) = 0;
const std::vector<int>& owners, int requiredInterface, u8 flags, bool includeMirage = false) = 0;
/**
* Get the effective range in a parablic range query.

View file

@ -50,9 +50,9 @@
class wxWindow;
BEGIN_EVENT_TABLE(ActorEditor, AtlasWindow)
wxBEGIN_EVENT_TABLE(ActorEditor, AtlasWindow)
EVT_MENU(ID_CreateEntity, ActorEditor::OnCreateEntity)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
ActorEditor::ActorEditor(wxWindow* parent)

View file

@ -61,5 +61,5 @@ private:
// but should be persisted so for convenience keep a copy of the last loaded file.
AtObj m_Actor;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -39,9 +39,9 @@
class wxWindow;
BEGIN_EVENT_TABLE(ToolButton, wxButton)
wxBEGIN_EVENT_TABLE(ToolButton, wxButton)
EVT_BUTTON(wxID_ANY, ToolButton::OnClick)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
ToolButton::ToolButton
(ToolManager& toolManager, wxWindow *parent, const wxString& label, const wxString& toolName, const wxSize& size, long style)
@ -77,9 +77,9 @@ void ToolButton::SetSelectedAppearance(bool selected)
//////////////////////////////////////////////////////////////////////////
BEGIN_EVENT_TABLE(ToolButtonBar, wxToolBar)
wxBEGIN_EVENT_TABLE(ToolButtonBar, wxToolBar)
EVT_TOOL(wxID_ANY, ToolButtonBar::OnTool)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
ToolButtonBar::ToolButtonBar(ToolManager& toolManager, wxWindow* parent, SectionLayout* sectionLayout, int baseID, long style)
: wxToolBar(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style)

View file

@ -41,7 +41,7 @@ private:
wxString m_Tool;
bool m_Selected;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
class ToolButtonBar : public wxToolBar
@ -68,5 +68,5 @@ private:
std::map<int, Button> m_Buttons;
SectionLayout* m_SectionLayout;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -107,7 +107,7 @@ void Canvas::OnMouse(wxMouseEvent& evt)
HandleMouseEvent(evt);
}
BEGIN_EVENT_TABLE(Canvas, wxGLCanvas)
wxBEGIN_EVENT_TABLE(Canvas, wxGLCanvas)
EVT_SIZE (Canvas::OnResize)
EVT_LEFT_DCLICK (Canvas::OnMouse)
EVT_LEFT_DOWN (Canvas::OnMouse)
@ -121,4 +121,4 @@ BEGIN_EVENT_TABLE(Canvas, wxGLCanvas)
EVT_MOUSEWHEEL (Canvas::OnMouse)
EVT_MOTION (Canvas::OnMouse)
EVT_MOUSE_CAPTURE_LOST(Canvas::OnMouseCaptureLost)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -45,5 +45,5 @@ private:
wxPoint m_LastMousePos;
bool m_MouseCaptured;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -153,11 +153,11 @@ void DraggableListCtrl::OnChar(wxKeyEvent& event)
}
BEGIN_EVENT_TABLE(DraggableListCtrl, EditableListCtrl)
wxBEGIN_EVENT_TABLE(DraggableListCtrl, EditableListCtrl)
EVT_LIST_BEGIN_DRAG(wxID_ANY, DraggableListCtrl::OnBeginDrag)
EVT_LIST_ITEM_SELECTED(wxID_ANY, DraggableListCtrl::OnItemSelected)
EVT_MOTION(DraggableListCtrl::OnMouseEvent)
EVT_LEFT_UP(DraggableListCtrl::OnMouseEvent)
EVT_CHAR(DraggableListCtrl::OnChar)
EVT_MOUSE_CAPTURE_LOST(DraggableListCtrl::OnMouseCaptureLost)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -61,7 +61,7 @@ public:
private:
long m_DragSource;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
#endif // INCLUDED_DRAGGABLELISTCTRL

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -321,8 +321,8 @@ AtObj EditableListCtrl::FreezeData()
BEGIN_EVENT_TABLE(EditableListCtrl, wxListCtrl)
wxBEGIN_EVENT_TABLE(EditableListCtrl, wxListCtrl)
EVT_LEFT_DCLICK(EditableListCtrl::OnMouseEvent)
EVT_RIGHT_DOWN(EditableListCtrl::OnMouseEvent)
EVT_CHAR(EditableListCtrl::OnKeyDown)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -116,7 +116,7 @@ protected:
wxListItemAttr m_ListItemAttr[2]; // standard+alternate colors
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
#endif // INCLUDED_EDITABLELISTCTRL

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -67,7 +67,7 @@ void QuickComboBox::OnChar(wxKeyEvent& event)
event.Skip();
}
BEGIN_EVENT_TABLE(QuickComboBox, wxComboBox)
wxBEGIN_EVENT_TABLE(QuickComboBox, wxComboBox)
EVT_KILL_FOCUS(QuickComboBox::OnKillFocus)
EVT_CHAR(QuickComboBox::OnChar)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -32,5 +32,5 @@ public:
void OnChar(wxKeyEvent& event);
private:
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -79,13 +79,13 @@ public:
event.Skip();
}
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(FileCtrl_TextCtrl, wxTextCtrl)
wxBEGIN_EVENT_TABLE(FileCtrl_TextCtrl, wxTextCtrl)
EVT_KILL_FOCUS(FileCtrl_TextCtrl::OnKillFocus)
EVT_CHAR(FileCtrl_TextCtrl::OnChar)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
class FileCtrl_Button : public wxButton
{
@ -105,13 +105,13 @@ public:
virtual void OnPress(wxCommandEvent& event)=0;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(FileCtrl_Button, wxButton)
wxBEGIN_EVENT_TABLE(FileCtrl_Button, wxButton)
EVT_KILL_FOCUS(FileCtrl_Button::OnKillFocus)
EVT_BUTTON(wxID_ANY, FileCtrl_Button::OnPress)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -58,7 +58,7 @@ void QuickTextCtrl::OnChar(wxKeyEvent& event)
event.Skip();
}
BEGIN_EVENT_TABLE(QuickTextCtrl, wxTextCtrl)
wxBEGIN_EVENT_TABLE(QuickTextCtrl, wxTextCtrl)
EVT_KILL_FOCUS(QuickTextCtrl::OnKillFocus)
EVT_CHAR(QuickTextCtrl::OnChar)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -31,5 +31,5 @@ public:
void OnChar(wxKeyEvent& event);
private:
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -265,7 +265,7 @@ void MapDialog::SaveFile()
EndModal(wxID_OK);
}
BEGIN_EVENT_TABLE(MapDialog, wxDialog)
wxBEGIN_EVENT_TABLE(MapDialog, wxDialog)
EVT_BUTTON (wxID_CANCEL, MapDialog::OnCancel)
EVT_BUTTON (wxID_OPEN, MapDialog::OnOpen)
EVT_BUTTON (wxID_SAVE, MapDialog::OnSave)
@ -273,4 +273,4 @@ BEGIN_EVENT_TABLE(MapDialog, wxDialog)
EVT_LISTBOX_DCLICK (wxID_ANY, MapDialog::OnListBox)
EVT_TEXT (ID_MapDialogFilename, MapDialog::OnFilename)
EVT_NOTEBOOK_PAGE_CHANGED (ID_MapDialogNotebook, MapDialog::OnNotebookChanged)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -53,7 +53,7 @@ private:
wxString m_FileName;
MapDialogType m_Type;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
#endif // INCLUDED_MAPDIALOG

View file

@ -126,9 +126,9 @@ void MapResizeDialog::OnOK(wxCommandEvent& WXUNUSED(evt))
EndModal(wxID_OK);
}
BEGIN_EVENT_TABLE(MapResizeDialog, wxDialog)
wxBEGIN_EVENT_TABLE(MapResizeDialog, wxDialog)
EVT_BUTTON(wxID_CANCEL, MapResizeDialog::OnCancel)
EVT_BUTTON(wxID_OK, MapResizeDialog::OnOK)
EVT_LISTBOX(wxID_ANY, MapResizeDialog::OnListBox)
EVT_LISTBOX_DCLICK(wxID_ANY, MapResizeDialog::OnListBox)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -48,7 +48,7 @@ private:
ssize_t m_NewSize;
PseudoMiniMapPanel* m_MiniMap;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
#endif // INCLUDED_MAPRESIZEDIALOG

View file

@ -228,7 +228,7 @@ void PseudoMiniMapPanel::EraseBackground(wxEraseEvent& WXUNUSED(evt))
// Do nothing - don't erase to remove flicker.
}
BEGIN_EVENT_TABLE(PseudoMiniMapPanel, wxPanel)
wxBEGIN_EVENT_TABLE(PseudoMiniMapPanel, wxPanel)
EVT_LEAVE_WINDOW(PseudoMiniMapPanel::OnMouseUp)
EVT_LEFT_DOWN(PseudoMiniMapPanel::OnMouseDown)
EVT_LEFT_UP(PseudoMiniMapPanel::OnMouseUp)
@ -239,4 +239,4 @@ BEGIN_EVENT_TABLE(PseudoMiniMapPanel, wxPanel)
EVT_MOTION(PseudoMiniMapPanel::OnMouseMove)
EVT_LEAVE_WINDOW(PseudoMiniMapPanel::OnMouseLeave)
EVT_PAINT(PseudoMiniMapPanel::PaintEvent)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -57,7 +57,7 @@ private:
bool m_SameOrGrowing;
ssize_t m_NewSize;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
#endif // INCLUDED_PSEUDOMINIMAPPANEL

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -27,11 +27,11 @@
class wxWindow;
BEGIN_EVENT_TABLE(SnapSplitterWindow, wxSplitterWindow)
wxBEGIN_EVENT_TABLE(SnapSplitterWindow, wxSplitterWindow)
EVT_SPLITTER_SASH_POS_CHANGING(wxID_ANY, SnapSplitterWindow::OnSashPosChanging)
EVT_SPLITTER_SASH_POS_CHANGED(wxID_ANY, SnapSplitterWindow::OnSashPosChanged)
EVT_SPLITTER_DCLICK(wxID_ANY, SnapSplitterWindow::OnDoubleClick)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
SnapSplitterWindow::SnapSplitterWindow(wxWindow* parent, long style, const wxString& configPath)
: wxSplitterWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,

View file

@ -43,5 +43,5 @@ private:
int m_SnapTolerance;
wxString m_ConfigPath;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -48,9 +48,9 @@ class wxWindow;
// WDR: event table for wxVirtualDirTreeCtrl
BEGIN_EVENT_TABLE(wxVirtualDirTreeCtrl, wxTreeCtrl)
wxBEGIN_EVENT_TABLE(wxVirtualDirTreeCtrl, wxTreeCtrl)
EVT_TREE_ITEM_EXPANDING(-1, wxVirtualDirTreeCtrl::OnExpanding)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
wxVirtualDirTreeCtrl::wxVirtualDirTreeCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name)
: wxTreeCtrl(parent, id, pos, size, style, validator, name)

View file

@ -482,7 +482,7 @@ private:
// WDR: handler declarations for wxVirtualDirTreeCtrl
private:
DECLARE_EVENT_TABLE()
wxDECLARE_EVENT_TABLE();
};

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -35,10 +35,10 @@ class wxWindow;
IMPLEMENT_CLASS(AtlasDialog, wxDialog);
BEGIN_EVENT_TABLE(AtlasDialog, wxDialog)
wxBEGIN_EVENT_TABLE(AtlasDialog, wxDialog)
EVT_MENU(wxID_UNDO, AtlasDialog::OnUndo)
EVT_MENU(wxID_REDO, AtlasDialog::OnRedo)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
AtlasDialog::AtlasDialog(wxWindow* parent, const wxString& title, const wxSize& size)

View file

@ -51,7 +51,7 @@ protected:
private:
AtlasWindowCommandProc m_CommandProc;
DECLARE_EVENT_TABLE()
wxDECLARE_EVENT_TABLE();
};
#endif // INCLUDED_ATLASDIALOG

View file

@ -85,19 +85,19 @@ public:
void OnSave(wxCommandEvent& WXUNUSED(event)) { EndModal(wxID_SAVE); }
void OnNo(wxCommandEvent& WXUNUSED(event)) { EndModal(wxID_NO); }
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(SaveOnExitDialog, wxDialog)
wxBEGIN_EVENT_TABLE(SaveOnExitDialog, wxDialog)
EVT_BUTTON(wxID_SAVE, SaveOnExitDialog::OnSave)
EVT_BUTTON(wxID_NO, SaveOnExitDialog::OnNo)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_CLASS(AtlasWindow, wxFrame);
BEGIN_EVENT_TABLE(AtlasWindow, wxFrame)
wxBEGIN_EVENT_TABLE(AtlasWindow, wxFrame)
EVT_MENU(wxID_NEW, AtlasWindow::OnNew)
// EVT_MENU(ID_Import, AtlasWindow::OnImport)
// EVT_MENU(ID_Export, AtlasWindow::OnExport)
@ -111,7 +111,7 @@ BEGIN_EVENT_TABLE(AtlasWindow, wxFrame)
EVT_MENU(wxID_REDO, AtlasWindow::OnRedo)
EVT_CLOSE(AtlasWindow::OnClose)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
AtlasWindow::AtlasWindow(wxWindow* parent, const wxString& title, const wxSize& size)
: wxFrame(parent, wxID_ANY, _T(""), wxDefaultPosition, size),

View file

@ -97,7 +97,7 @@ private:
FileHistory m_FileHistory;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
#endif // INCLUDED_ATLASWINDOW

View file

@ -202,16 +202,6 @@ private:
return;
}
// Alt+enter toggles fullscreen
if (evt.GetKeyCode() == WXK_RETURN && wxGetKeyState(WXK_ALT))
{
if (m_ScenarioEditor.IsFullScreen())
m_ScenarioEditor.ShowFullScreen(false);
else
m_ScenarioEditor.ShowFullScreen(true, wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION);
return;
}
if (evt.GetKeyCode() == 'c')
{
POST_MESSAGE(CameraReset, ());
@ -339,15 +329,15 @@ private:
ScenarioEditor& m_ScenarioEditor;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(GameCanvas, Canvas)
wxBEGIN_EVENT_TABLE(GameCanvas, Canvas)
EVT_KEY_DOWN(GameCanvas::OnKeyDown)
EVT_KEY_UP(GameCanvas::OnKeyUp)
EVT_CHAR(GameCanvas::OnChar)
EVT_KILL_FOCUS(GameCanvas::OnKillFocus)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
@ -382,7 +372,7 @@ enum
ID_Toolbar // must be last in the list
};
BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
wxBEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
EVT_CLOSE(ScenarioEditor::OnClose)
EVT_TIMER(wxID_ANY, ScenarioEditor::OnTimer)
@ -417,7 +407,7 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
EVT_MENU_OPEN(ScenarioEditor::OnMenuOpen)
EVT_IDLE(ScenarioEditor::OnIdle)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
static AtlasWindowCommandProc g_CommandProc;
AtlasWindowCommandProc& ScenarioEditor::GetCommandProc() { return g_CommandProc; }
@ -520,6 +510,8 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
menuView->AppendCheckItem(ID_Wireframe, _("&Wireframe"));
menuView->AppendCheckItem(ID_SmoothFramerate, _("Smooth framerate"));
menuView->AppendCheckItem(ID_BirdsEyeView, _("&Birds Eye View\tCtrl+B"));
auto* fullscreenItem = menuView->AppendCheckItem(wxID_ANY, _("&Fullscreen\tAlt+Enter"));
this->Bind(wxEVT_MENU, [this, fullscreenItem](auto&){ SetFullscreen(fullscreenItem->IsChecked()); });
menuView->Append(ID_CameraReset, _("&Reset camera"));
}
@ -701,6 +693,9 @@ void ScenarioEditor::OnClose(wxCloseEvent& event)
m_Timer.Stop();
m_RenderTimer.Stop();
// Wait for in-flight work to finish.
qPing qry;
qry.Post();
m_ToolManager.SetCurrentTool(_T(""));
@ -1006,6 +1001,11 @@ void ScenarioEditor::OnBirdsEyeView(wxCommandEvent& event)
POST_MESSAGE(SetBirdsEyeView, (event.IsChecked()));
}
void ScenarioEditor::SetFullscreen(const bool enabled)
{
ShowFullScreen(enabled, wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION);
}
void ScenarioEditor::OnDumpState(wxCommandEvent& event)
{
wxDateTime time = wxDateTime::Now();

View file

@ -62,6 +62,7 @@ public:
void OnWireframe(wxCommandEvent& event);
void OnSmoothFramerate(wxCommandEvent& event);
void OnBirdsEyeView(wxCommandEvent& event);
void SetFullscreen(const bool enabled);
void OnCameraReset(wxCommandEvent& event);
void OnMessageTrace(wxCommandEvent& event);
@ -119,7 +120,7 @@ private:
};
std::map<int, HelpItem> m_HelpData;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
#endif // INCLUDED_SCENARIOEDITOR

View file

@ -79,12 +79,12 @@ private:
SidebarBook* m_Book;
size_t m_Id;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(SidebarButton, wxBitmapButton)
wxBEGIN_EVENT_TABLE(SidebarButton, wxBitmapButton)
EVT_BUTTON(wxID_ANY, SidebarButton::OnClick)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
class SidebarBook : public wxPanel
@ -257,12 +257,12 @@ private:
std::vector<SidebarPage> m_Pages;
ssize_t m_SelectedPage;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(SidebarBook, wxPanel)
wxBEGIN_EVENT_TABLE(SidebarBook, wxPanel)
EVT_SIZE(SidebarBook::OnSize)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
void SidebarButton::OnClick(wxCommandEvent& WXUNUSED(event))
{

View file

@ -148,8 +148,8 @@ void CinemaSidebar::ReloadPathList()
m_PathList->Append(*path.name);
}
BEGIN_EVENT_TABLE(CinemaSidebar, Sidebar)
wxBEGIN_EVENT_TABLE(CinemaSidebar, Sidebar)
EVT_CHECKBOX(ID_PathsDrawing, CinemaSidebar::OnTogglePathsDrawing)
EVT_BUTTON(ID_AddPath, CinemaSidebar::OnAddPath)
EVT_BUTTON(ID_DeletePath, CinemaSidebar::OnDeletePath)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();

View file

@ -47,5 +47,5 @@ private:
wxListBox* m_PathList;
wxTextCtrl* m_NewPathName;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -94,12 +94,12 @@ private:
Shareable<float>& m_Var;
float m_Min, m_Max;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableSliderBox, wxPanel)
wxBEGIN_EVENT_TABLE(VariableSliderBox, wxPanel)
EVT_SCROLL(VariableSliderBox::OnScroll)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
@ -152,12 +152,12 @@ private:
wxComboBox* m_Combo;
Shareable<std::wstring>& m_Var;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableListBox, wxPanel)
wxBEGIN_EVENT_TABLE(VariableListBox, wxPanel)
EVT_COMBOBOX(wxID_ANY, VariableListBox::OnSelect)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
@ -216,12 +216,12 @@ private:
wxButton* m_Button;
Shareable<AtlasMessage::Color>& m_Color;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(VariableColorBox, wxPanel)
wxBEGIN_EVENT_TABLE(VariableColorBox, wxPanel)
EVT_BUTTON(wxID_ANY, VariableColorBox::OnClick)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
@ -361,8 +361,8 @@ void EnvironmentSidebar::OnPickWaterHeight(wxCommandEvent& WXUNUSED(evt))
m_ScenarioEditor.GetToolManager().SetCurrentTool(_T("PickWaterHeight"), this);
}
BEGIN_EVENT_TABLE(EnvironmentSidebar, Sidebar)
wxBEGIN_EVENT_TABLE(EnvironmentSidebar, Sidebar)
EVT_BUTTON(ID_RecomputeWaterData, EnvironmentSidebar::RecomputeWaterData)
EVT_BUTTON(ID_PickWaterHeight, EnvironmentSidebar::OnPickWaterHeight)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();

View file

@ -46,5 +46,5 @@ private:
VariableListBox* m_WaterTypeList;
ObservableScopedConnection m_Conn;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -150,14 +150,14 @@ public:
float theta, phi;
LightControl* m_LightControl;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(LightSphere, wxControl)
wxBEGIN_EVENT_TABLE(LightSphere, wxControl)
EVT_PAINT(LightSphere::OnPaint)
EVT_MOTION(LightSphere::OnMouse)
EVT_LEFT_DOWN(LightSphere::OnMouse)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()
LightControl::LightControl(wxWindow* parent, const wxSize& size, Observable<AtlasMessage::sEnvironmentSettings>& environment)
: wxPanel(parent), m_Environment(environment)

View file

@ -158,16 +158,16 @@ private:
std::vector<wxChoice*> m_PlayerCivChoices;
Observable<AtObj>& m_MapSettings;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(MapSettingsControl, wxPanel)
wxBEGIN_EVENT_TABLE(MapSettingsControl, wxPanel)
EVT_TEXT(ID_MapName, MapSettingsControl::OnEdit)
EVT_TEXT(ID_MapDescription, MapSettingsControl::OnEdit)
EVT_TEXT(ID_MapPreview, MapSettingsControl::OnEdit)
EVT_CHECKBOX(wxID_ANY, MapSettingsControl::OnEdit)
EVT_CHOICE(wxID_ANY, MapSettingsControl::OnEdit)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
MapSettingsControl::MapSettingsControl(wxWindow* parent, ScenarioEditor& scenarioEditor)
: wxPanel(parent, wxID_ANY), m_MapSettings(scenarioEditor.GetMapSettings())
@ -837,7 +837,7 @@ void MapSidebar::OnResizeMap(wxCommandEvent& WXUNUSED(evt))
POST_COMMAND(ResizeMap, (dlg.GetNewSize(), offset.x, offset.y));
}
BEGIN_EVENT_TABLE(MapSidebar, Sidebar)
wxBEGIN_EVENT_TABLE(MapSidebar, Sidebar)
EVT_BUTTON(ID_SimPlay, MapSidebar::OnSimPlay)
EVT_BUTTON(ID_SimFast, MapSidebar::OnSimPlay)
EVT_BUTTON(ID_SimSlow, MapSidebar::OnSimPlay)
@ -848,4 +848,4 @@ BEGIN_EVENT_TABLE(MapSidebar, Sidebar)
EVT_BUTTON(ID_ResizeMap, MapSidebar::OnResizeMap)
EVT_BUTTON(ID_OpenPlayerPanel, MapSidebar::OnOpenPlayerPanel)
EVT_CHOICE(ID_RandomScript, MapSidebar::OnRandomScript)
END_EVENT_TABLE()
wxEND_EVENT_TABLE()

View file

@ -48,5 +48,5 @@ private:
int m_SimState;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -124,7 +124,7 @@ private:
wxScrolledWindow* m_TemplateNames;
ObjectSidebarImpl* p;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
struct ObjectSidebarImpl
@ -450,13 +450,13 @@ void ObjectSidebar::OnToggleExactFilter(wxCommandEvent& WXUNUSED(evt))
FilterObjects();
}
BEGIN_EVENT_TABLE(ObjectSidebar, Sidebar)
wxBEGIN_EVENT_TABLE(ObjectSidebar, Sidebar)
EVT_CHOICE(ID_ObjectType, ObjectSidebar::OnSelectType)
EVT_TEXT(ID_ObjectFilter, ObjectSidebar::OnSelectFilter)
EVT_LISTBOX(ID_SelectObject, ObjectSidebar::OnSelectObject)
EVT_BUTTON(ID_ToggleViewer, ObjectSidebar::OnToggleViewer)
EVT_CHECKBOX(ID_ObjectExactFilter, ObjectSidebar::OnToggleExactFilter)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
@ -525,11 +525,11 @@ private:
m_ObjectSettings.NotifyObserversExcept(m_ObjectConn);
}
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(PlayerComboBox, wxComboBox)
wxBEGIN_EVENT_TABLE(PlayerComboBox, wxComboBox)
EVT_COMBOBOX(wxID_ANY, PlayerComboBox::OnSelect)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
@ -792,7 +792,7 @@ void ObjectBottomBar::OnSpeed(wxCommandEvent& evt)
p->ActorViewerPostToGame();
}
BEGIN_EVENT_TABLE(ObjectBottomBar, wxPanel)
wxBEGIN_EVENT_TABLE(ObjectBottomBar, wxPanel)
EVT_BUTTON(ID_ViewerWireframe, ObjectBottomBar::OnViewerSetting)
EVT_BUTTON(ID_ViewerMove, ObjectBottomBar::OnViewerSetting)
EVT_BUTTON(ID_ViewerGround, ObjectBottomBar::OnViewerSetting)
@ -806,4 +806,4 @@ BEGIN_EVENT_TABLE(ObjectBottomBar, wxPanel)
EVT_BUTTON(ID_ViewerBoundingBox, ObjectBottomBar::OnViewerSetting)
EVT_BUTTON(ID_ViewerAxesMarker, ObjectBottomBar::OnViewerSetting)
EVT_BUTTON(ID_ViewerPropPoints, ObjectBottomBar::OnViewerSetting)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();

View file

@ -45,5 +45,5 @@ private:
std::unique_ptr<ObjectSidebarImpl> m_Impl;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -124,12 +124,12 @@ public:
private:
wxWindow* m_Control;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(DefaultCheckbox, wxCheckBox)
wxBEGIN_EVENT_TABLE(DefaultCheckbox, wxCheckBox)
EVT_CHECKBOX(wxID_ANY, DefaultCheckbox::OnChecked)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
class PlayerNotebookPage : public wxPanel
@ -192,35 +192,35 @@ public:
wxFlexGridSizer* gridSizer = new wxFlexGridSizer(3, 5, 5);
gridSizer->AddGrowableCol(2);
wxSpinCtrl* foodCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerFood, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
wxSpinCtrl* foodCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerFood, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(resourceSizer->GetStaticBox(), ID_DefaultFood, foodCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(resourceSizer->GetStaticBox(), wxID_ANY, _("Food")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(foodCtrl,
_("Initial value of food resource")), wxSizerFlags().Expand());
m_Controls.food = foodCtrl;
wxSpinCtrl* woodCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerWood, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
wxSpinCtrl* woodCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerWood, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(resourceSizer->GetStaticBox(), ID_DefaultWood, woodCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(resourceSizer->GetStaticBox(), wxID_ANY, _("Wood")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(woodCtrl,
_("Initial value of wood resource")), wxSizerFlags().Expand());
m_Controls.wood = woodCtrl;
wxSpinCtrl* metalCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerMetal, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
wxSpinCtrl* metalCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerMetal, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(resourceSizer->GetStaticBox(), ID_DefaultMetal, metalCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(resourceSizer->GetStaticBox(), wxID_ANY, _("Metal")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(metalCtrl,
_("Initial value of metal resource")), wxSizerFlags().Expand());
m_Controls.metal = metalCtrl;
wxSpinCtrl* stoneCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerStone, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
wxSpinCtrl* stoneCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerStone, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(resourceSizer->GetStaticBox(), ID_DefaultStone, stoneCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(resourceSizer->GetStaticBox(), wxID_ANY, _("Stone")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(stoneCtrl,
_("Initial value of stone resource")), wxSizerFlags().Expand());
m_Controls.stone = stoneCtrl;
wxSpinCtrl* popCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerPop, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, INT_MAX);
wxSpinCtrl* popCtrl = new wxSpinCtrl(resourceSizer->GetStaticBox(), ID_PlayerPop, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER, 0, INT_MAX);
gridSizer->Add(new DefaultCheckbox(resourceSizer->GetStaticBox(), ID_DefaultPop, popCtrl), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
gridSizer->Add(new wxStaticText(resourceSizer->GetStaticBox(), wxID_ANY, _("Pop limit")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT));
gridSizer->Add(Tooltipped(popCtrl,
@ -365,15 +365,15 @@ private:
PlayerPageControls m_Controls;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(PlayerNotebookPage, wxPanel)
wxBEGIN_EVENT_TABLE(PlayerNotebookPage, wxPanel)
EVT_BUTTON(ID_PlayerColor, PlayerNotebookPage::OnColor)
EVT_BUTTON(ID_CameraSet, PlayerNotebookPage::OnCameraSet)
EVT_BUTTON(ID_CameraView, PlayerNotebookPage::OnCameraView)
EVT_BUTTON(ID_CameraClear, PlayerNotebookPage::OnCameraClear)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
@ -440,12 +440,12 @@ protected:
private:
std::vector<PlayerNotebookPage*> m_Pages;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(PlayerNotebook, wxChoicebook)
wxBEGIN_EVENT_TABLE(PlayerNotebook, wxChoicebook)
EVT_CHOICEBOOK_PAGE_CHANGED(wxID_ANY, PlayerNotebook::OnPageChanged)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
@ -477,6 +477,14 @@ private:
}
}
void OnEditSpin(wxCommandEvent&)
{
if (!m_InGUIUpdate)
{
SendToEngine();
}
}
void OnPlayerColor(wxCommandEvent& WXUNUSED(evt))
{
if (!m_InGUIUpdate)
@ -493,22 +501,22 @@ private:
// and we don't want to handle the same event twice
}
void OnNumPlayersSpin(wxSpinEvent& evt)
void SetNumPlayers(int newNumPlayers)
{
if (!m_InGUIUpdate)
{
wxASSERT(evt.GetInt() > 0);
wxASSERT(newNumPlayers > 0);
// When wxMessageBox pops up, wxSpinCtrl loses focus, which
// forces another EVT_SPINCTRL event, which we don't want
// to handle, so we check here for a change
if (evt.GetInt() == (int)m_NumPlayers)
if (newNumPlayers == (int)m_NumPlayers)
{
return; // No change
}
size_t oldNumPlayers = m_NumPlayers;
m_NumPlayers = evt.GetInt();
m_NumPlayers = newNumPlayers;
if (m_NumPlayers < oldNumPlayers)
{
@ -565,24 +573,27 @@ private:
Observable<AtObj>& m_MapSettings;
size_t m_NumPlayers;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(PlayerSettingsControl, wxPanel)
wxBEGIN_EVENT_TABLE(PlayerSettingsControl, wxPanel)
EVT_BUTTON(ID_PlayerColor, PlayerSettingsControl::OnPlayerColor)
EVT_BUTTON(ID_CameraSet, PlayerSettingsControl::OnEdit)
EVT_BUTTON(ID_CameraClear, PlayerSettingsControl::OnEdit)
EVT_CHECKBOX(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_CHOICE(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_TEXT(ID_NumPlayers, PlayerSettingsControl::OnNumPlayersText)
EVT_TEXT(wxID_ANY, PlayerSettingsControl::OnEdit)
EVT_SPINCTRL(ID_NumPlayers, PlayerSettingsControl::OnNumPlayersSpin)
EVT_SPINCTRL(ID_PlayerFood, PlayerSettingsControl::OnEditSpin)
EVT_SPINCTRL(ID_PlayerWood, PlayerSettingsControl::OnEditSpin)
EVT_SPINCTRL(ID_PlayerMetal, PlayerSettingsControl::OnEditSpin)
EVT_SPINCTRL(ID_PlayerStone, PlayerSettingsControl::OnEditSpin)
EVT_SPINCTRL(ID_PlayerPop, PlayerSettingsControl::OnEditSpin)
END_EVENT_TABLE();
EVT_TEXT_ENTER(ID_PlayerFood, PlayerSettingsControl::OnEditSpin)
EVT_TEXT_ENTER(ID_PlayerWood, PlayerSettingsControl::OnEditSpin)
EVT_TEXT_ENTER(ID_PlayerMetal, PlayerSettingsControl::OnEditSpin)
EVT_TEXT_ENTER(ID_PlayerStone, PlayerSettingsControl::OnEditSpin)
EVT_TEXT_ENTER(ID_PlayerPop, PlayerSettingsControl::OnEditSpin)
wxEND_EVENT_TABLE();
PlayerSettingsControl::PlayerSettingsControl(wxWindow* parent, ScenarioEditor& scenarioEditor)
: wxPanel(parent, wxID_ANY), m_InGUIUpdate(false), m_MapSettings(scenarioEditor.GetMapSettings()), m_NumPlayers(0)
@ -604,9 +615,19 @@ PlayerSettingsControl::PlayerSettingsControl(wxWindow* parent, ScenarioEditor& s
boxSizer->AddSpacer(10);
wxSpinCtrl* numPlayersSpin = new wxSpinCtrl(topBox, ID_NumPlayers, wxEmptyString, wxDefaultPosition, wxSize(40, -1));
numPlayersSpin->SetValue(MAX_NUM_PLAYERS);
numPlayersSpin->SetRange(1, MAX_NUM_PLAYERS);
// NOTE: on MSW pressing Enter with wxSpinCtrl is used to navigate, ie
// it triggers the default Window action which is ok / close. So we
// have to explicitly generate the wxCommandEvent wxEVT_TEXT_ENTER and
// capture it.
// https://gitea.wildfiregames.com/0ad/0ad/issues/9026
wxSpinCtrl* numPlayersSpin = new wxSpinCtrl(topBox, ID_NumPlayers,
wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER,
1, MAX_NUM_PLAYERS, MAX_NUM_PLAYERS);
auto numPlayerSetter = [this, numPlayersSpin](auto&){ SetNumPlayers(numPlayersSpin->GetValue()); };
numPlayersSpin->Bind(wxEVT_SPINCTRL, numPlayerSetter);
numPlayersSpin->Bind(wxEVT_TEXT_ENTER, numPlayerSetter);
boxSizer->Add(numPlayersSpin);
gridSizer->Add(boxSizer);

View file

@ -211,12 +211,12 @@ private:
wxTimer m_Timer;
wxString m_TextureName;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(TexturePreviewPanel, wxPanel)
wxBEGIN_EVENT_TABLE(TexturePreviewPanel, wxPanel)
EVT_TIMER(wxID_ANY, TexturePreviewPanel::OnTimer)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
@ -324,10 +324,10 @@ void TerrainSidebar::OnShowPriorities(wxCommandEvent& evt)
POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::GAME, L"priorities", evt.IsChecked()));
}
BEGIN_EVENT_TABLE(TerrainSidebar, Sidebar)
wxBEGIN_EVENT_TABLE(TerrainSidebar, Sidebar)
EVT_CHOICE(ID_Passability, TerrainSidebar::OnPassabilityChoice)
EVT_CHECKBOX(ID_ShowPriorities, TerrainSidebar::OnShowPriorities)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
@ -531,14 +531,14 @@ private:
};
std::unordered_map<std::wstring, PreviewButton> m_PreviewButtons;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(TextureNotebookPage, wxPanel)
wxBEGIN_EVENT_TABLE(TextureNotebookPage, wxPanel)
EVT_BUTTON(wxID_ANY, TextureNotebookPage::OnButton)
EVT_SIZE(TextureNotebookPage::OnSize)
EVT_TIMER(wxID_ANY, TextureNotebookPage::OnTimer)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
class TextureNotebook : public wxChoicebook
@ -600,12 +600,12 @@ private:
ScenarioEditor& m_ScenarioEditor;
wxArrayString m_TerrainGroups;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(TextureNotebook, wxChoicebook)
wxBEGIN_EVENT_TABLE(TextureNotebook, wxChoicebook)
EVT_CHOICEBOOK_PAGE_CHANGED(wxID_ANY, TextureNotebook::OnPageChanged)
END_EVENT_TABLE();
wxEND_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////

View file

@ -41,5 +41,5 @@ private:
wxChoice* m_PassabilityChoice;
TexturePreviewPanel* m_TexturePreview;
DECLARE_EVENT_TABLE();
wxDECLARE_EVENT_TABLE();
};

View file

@ -34,6 +34,7 @@
#include <wx/spinctrl.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/toolbar.h>
#include <wx/translation.h>
@ -44,7 +45,7 @@ static Brush* g_Brush_CurrentlyActive = NULL; // only one brush can be active at
const float Brush::STRENGTH_MULTIPLIER = 1024.f;
Brush::Brush()
: m_Shape(CIRCLE), m_Size(4), m_Strength(1.f), m_IsActive(false)
: m_Shape(Shape::CIRCLE), m_Size(4), m_Strength(1.f), m_IsActive(false)
{
}
@ -76,9 +77,9 @@ int Brush::GetWidth() const
{
switch (m_Shape)
{
case CIRCLE:
case Shape::CIRCLE:
return m_Size;
case SQUARE:
case Shape::SQUARE:
return m_Size;
default:
wxFAIL;
@ -108,7 +109,7 @@ std::vector<float> Brush::GetData() const
switch (m_Shape)
{
case CIRCLE:
case Shape::CIRCLE:
{
int i = 0;
// All calculations are done in units of half-tiles, since that
@ -131,7 +132,7 @@ std::vector<float> Brush::GetData() const
break;
}
case SQUARE:
case Shape::SQUARE:
{
int i = 0;
for (int y = 0; y < height; ++y)
@ -144,6 +145,17 @@ std::vector<float> Brush::GetData() const
return data;
}
int Brush::GetSize() const
{
return m_Size;
}
void Brush::SetSize(int size)
{
m_Size = size;
Send();
}
float Brush::GetStrength() const
{
return m_Strength;
@ -152,115 +164,61 @@ float Brush::GetStrength() const
void Brush::SetStrength(float strength)
{
m_Strength = strength;
Send();
}
void Brush::SetCircle(int size)
void Brush::SetShape(Shape shape)
{
m_Shape = CIRCLE;
m_Size = size;
m_Shape = shape;
Send();
}
void Brush::SetSquare(int size)
{
m_Shape = SQUARE;
m_Size = size;
}
//////////////////////////////////////////////////////////////////////////
class BrushShapeCtrl : public wxRadioBox
{
public:
BrushShapeCtrl(wxWindow* parent, wxArrayString& shapes, Brush& brush)
: wxRadioBox(parent, wxID_ANY, _("Shape"), wxDefaultPosition, wxDefaultSize, shapes, 0, wxRA_SPECIFY_ROWS),
m_Brush(brush)
{
SetSelection(m_Brush.m_Shape);
}
private:
Brush& m_Brush;
void OnChange(wxCommandEvent& WXUNUSED(evt))
{
m_Brush.m_Shape = (Brush::BrushShape)GetSelection();
m_Brush.Send();
}
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(BrushShapeCtrl, wxRadioBox)
EVT_RADIOBOX(wxID_ANY, BrushShapeCtrl::OnChange)
END_EVENT_TABLE()
class BrushSizeCtrl: public wxSpinCtrl
{
public:
BrushSizeCtrl(wxWindow* parent, Brush& brush)
: wxSpinCtrl(parent, wxID_ANY, wxString::Format(_T("%d"), brush.m_Size), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 100, brush.m_Size),
m_Brush(brush)
{
}
private:
Brush& m_Brush;
void OnChange(wxSpinEvent& WXUNUSED(evt))
{
m_Brush.m_Size = GetValue();
m_Brush.Send();
}
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(BrushSizeCtrl, wxSpinCtrl)
EVT_SPINCTRL(wxID_ANY, BrushSizeCtrl::OnChange)
END_EVENT_TABLE()
class BrushStrengthCtrl : public wxSpinCtrl
{
public:
BrushStrengthCtrl(wxWindow* parent, Brush& brush)
: wxSpinCtrl(parent, wxID_ANY, wxString::Format(_T("%d"), (int)(10.f*brush.m_Strength)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 100, (int)(10.f*brush.m_Strength)),
m_Brush(brush)
{
}
private:
Brush& m_Brush;
void OnChange(wxSpinEvent& WXUNUSED(evt))
{
m_Brush.m_Strength = GetValue()/10.f;
m_Brush.Send();
}
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(BrushStrengthCtrl, wxSpinCtrl)
EVT_SPINCTRL(wxID_ANY, BrushStrengthCtrl::OnChange)
END_EVENT_TABLE()
void Brush::CreateUI(wxWindow* parent, wxSizer* sizer)
{
wxArrayString shapes; // Must match order of BrushShape enum
// Must match order of Brush::Shape enum
wxArrayString shapes;
shapes.Add(_("Circle"));
shapes.Add(_("Square"));
// TODO (maybe): get rid of the extra static box, by not using wxRadioBox
sizer->Add(new BrushShapeCtrl(parent, shapes, *this), wxSizerFlags().Expand().Border(wxALL, 5));
auto* brushShapeCtrl = new wxRadioBox(parent, wxID_ANY, _("Shape"), wxDefaultPosition, wxDefaultSize, shapes, 0, wxRA_SPECIFY_ROWS);
brushShapeCtrl->Bind(wxEVT_RADIOBOX, [this, brushShapeCtrl](auto&){ SetShape(static_cast<Shape>(brushShapeCtrl->GetSelection())); });
sizer->Add(brushShapeCtrl, wxSizerFlags().Expand().Border(wxALL, 5));
sizer->AddSpacer(5);
// TODO: These are yucky
// NOTE: on MSW pressing Enter with wxSpinCtrl is used to navigate, ie it
// triggers the default Window action which is ok / close. So we have to
// explicitly generate the wxCommandEvent wxEVT_TEXT_ENTER and capture it.
// https://gitea.wildfiregames.com/0ad/0ad/issues/9026
auto* brushSizeLabel = new wxStaticText(parent, wxID_ANY, _("Size"));
auto* brushSizeCtrl = new wxSpinCtrl(parent, wxID_ANY,
wxString::Format(_T("%d"), GetSize()),
wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER,
0, 100, GetSize());
auto burshSizeSetter = [this, brushSizeCtrl](auto&){ SetSize(brushSizeCtrl->GetValue()); };
brushSizeCtrl->Bind(wxEVT_SPINCTRL, burshSizeSetter);
brushSizeCtrl->Bind(wxEVT_TEXT_ENTER, burshSizeSetter);
auto* brushStrengthLabel = new wxStaticText(parent, wxID_ANY, _("Strength"));
auto* brushStrengthCtrl = new wxSpinCtrl(parent, wxID_ANY,
wxString::Format(_T("%d"), static_cast<int>(10.f * GetStrength())),
wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS | wxTE_PROCESS_ENTER,
0, 100, static_cast<int>(10.f * GetStrength()));
auto burshStrenghtSetter = [this, brushStrengthCtrl](auto&){ SetStrength(brushStrengthCtrl->GetValue() / 10.f); };
brushStrengthCtrl->Bind(wxEVT_SPINCTRL, burshStrenghtSetter);
brushStrengthCtrl->Bind(wxEVT_TEXT_ENTER, burshStrenghtSetter);
wxFlexGridSizer* spinnerSizer = new wxFlexGridSizer(2, 5, 5);
spinnerSizer->AddGrowableCol(1);
spinnerSizer->Add(new wxStaticText(parent, wxID_ANY, _("Size")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT));
spinnerSizer->Add(new BrushSizeCtrl(parent, *this), wxSizerFlags().Expand());
spinnerSizer->Add(new wxStaticText(parent, wxID_ANY, _("Strength")), wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT));
spinnerSizer->Add(new BrushStrengthCtrl(parent, *this), wxSizerFlags().Expand());
spinnerSizer->Add(brushSizeLabel, wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT));
spinnerSizer->Add(brushSizeCtrl, wxSizerFlags().Expand());
spinnerSizer->Add(brushStrengthLabel, wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT));
spinnerSizer->Add(brushStrengthCtrl, wxSizerFlags().Expand());
sizer->Add(spinnerSizer, wxSizerFlags().Expand().Border(wxALL, 5));
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games.
/* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -29,6 +29,8 @@ class Brush
friend class BrushSizeCtrl;
friend class BrushStrengthCtrl;
public:
enum class Shape { CIRCLE = 0, SQUARE};
Brush();
~Brush();
@ -38,8 +40,10 @@ public:
int GetHeight() const;
std::vector<float> GetData() const;
void SetCircle(int size);
void SetSquare(int size);
void SetShape(Shape shape);
int GetSize() const;
void SetSize(int size);
float GetStrength() const;
void SetStrength(float strength);
@ -54,8 +58,7 @@ private:
// If active, send SetBrush message to the game
void Send();
enum BrushShape { CIRCLE = 0, SQUARE};
BrushShape m_Shape;
Shape m_Shape;
int m_Size;
float m_Strength;
bool m_IsActive;

View file

@ -43,7 +43,8 @@ class FillTerrain : public StateDrivenTool<FillTerrain>
public:
FillTerrain()
{
m_Brush.SetSquare(2);
m_Brush.SetShape(Brush::Shape::SQUARE);
m_Brush.SetSize(2);
SetState(&Waiting);
}

View file

@ -53,7 +53,8 @@ public:
{
SetState(&Waiting);
m_EyedropperBrush.SetSquare(2);
m_EyedropperBrush.SetShape(Brush::Shape::SQUARE);
m_EyedropperBrush.SetSize(2);
}

View file

@ -43,7 +43,8 @@ class ReplaceTerrain : public StateDrivenTool<ReplaceTerrain>
public:
ReplaceTerrain()
{
m_Brush.SetSquare(2);
m_Brush.SetShape(Brush::Shape::SQUARE);
m_Brush.SetSize(2);
SetState(&Waiting);
}

View file

@ -109,6 +109,7 @@ MESSAGEHANDLER(InitAppWindow)
MESSAGEHANDLER(InitSDL)
{
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
// When using GLX (Linux), SDL has to load the GL library to find
// glXGetProcAddressARB before it can load any extensions.
// When running in Atlas, we skip the SDL video initialisation code

View file

@ -118,6 +118,9 @@ MESSAGEHANDLER(GuiSwitchPage)
MESSAGEHANDLER(GuiMouseButtonEvent)
{
if (!g_VideoMode.IsInitialized())
return;
SDL_Event ev{};
ev.type = msg->pressed ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
ev.button.button = msg->button;
@ -132,6 +135,9 @@ MESSAGEHANDLER(GuiMouseButtonEvent)
MESSAGEHANDLER(GuiMouseMotionEvent)
{
if (!g_VideoMode.IsInitialized())
return;
SDL_Event ev{};
ev.type = SDL_MOUSEMOTION;
float x, y;
@ -143,6 +149,9 @@ MESSAGEHANDLER(GuiMouseMotionEvent)
MESSAGEHANDLER(GuiKeyEvent)
{
if (!g_VideoMode.IsInitialized())
return;
SDL_Event ev{};
ev.type = msg->pressed ? SDL_KEYDOWN : SDL_KEYUP;
ev.key.keysym.sym = static_cast<SDL_Keycode>(static_cast<int>(msg->sdlkey));
@ -152,6 +161,9 @@ MESSAGEHANDLER(GuiKeyEvent)
MESSAGEHANDLER(GuiCharEvent)
{
if (!g_VideoMode.IsInitialized())
return;
// Simulate special 'text input' events in the SDL
// This isn't quite compatible with WXWidget's handling,
// so to avoid trouble we only send 'letter-like' ASCII input.