Improve Git History navigation and asynchronous UI safety

Add a History ref selector for HEAD, local branches, remote branches, and tags without requiring checkout. Reuse cached branch-model display strings to keep large ref lists efficient.
Make deferred main-thread callbacks lifetime-safe across ecode controllers and plugins. Initialize plugin dispatchers during UIReady and extend MainThreadLifetime to support delayed and tagged dispatch.
Fix expandable Git History rows, empty merge projections, and commit-description expansion. Display only the physical first line while collapsed and avoid duplicating it in the expanded body.
Add coverage for history ref handling and preserve stale-request guards during repository and revision changes.
Fix UIImageViewer dimension reporting for sprites by displaying the underlying texture dimensions.
The Git History interface remains a work in progress.
This commit is contained in:
Martín Lucas Golini
2026-08-28 18:52:04 -03:00
parent baaa0a62c0
commit ef962fc61f
42 changed files with 601 additions and 247 deletions
+29 -1
View File
@@ -20,6 +20,7 @@ using namespace EE::Scene;
namespace EE::UI {
class UITreeView;
class UIDropDownList;
class UIDropDownModelList;
class UIStackWidget;
class UIListBoxItem;
class UIMenu;
@@ -31,6 +32,28 @@ namespace ecode {
class Git;
class GitBranchModel;
class GitHistoryRefModel : public Model {
public:
explicit GitHistoryRefModel( std::shared_ptr<GitBranchModel> source, String headLabel );
size_t rowCount( const ModelIndex& = {} ) const override { return mSourceIndexes.size() + 1; }
size_t columnCount( const ModelIndex& = {} ) const override { return 1; }
ModelIndex index( int row, int column, const ModelIndex& parent = {} ) const override;
Variant data( const ModelIndex& index, ModelRole role = ModelRole::Display ) const override;
std::string revision( size_t index ) const;
bool isRevision( size_t index, std::string_view revision ) const;
private:
std::shared_ptr<GitBranchModel> mSource;
std::vector<ModelIndex> mSourceIndexes;
String mHeadLabel;
};
static constexpr const char* GIT_EMPTY = "";
static constexpr const char* GIT_SUCCESS = "success";
static constexpr const char* GIT_ERROR = "error";
@@ -125,7 +148,8 @@ class GitPlugin : public PluginBase {
UITreeView* mBranchesTree{ nullptr };
UITreeView* mStatusTree{ nullptr };
UITreeView* mHistoryTree{ nullptr };
UITextView* mHistoryRefText{ nullptr };
UIDropDownModelList* mHistoryRefDropDown{ nullptr };
std::shared_ptr<GitHistoryRefModel> mHistoryRefModel;
std::shared_ptr<GitHistoryModel> mHistoryModel;
UIDropDownList* mPanelSwicher{ nullptr };
UIDropDownList* mRepoDropDown{ nullptr };
@@ -140,6 +164,8 @@ class GitPlugin : public PluginBase {
std::atomic<int> mRunningHistoryRequests{ 0 };
std::atomic<Uint64> mHistoryGeneration{ 0 };
std::string mHistoryRepo;
std::string mHistoryRevision{ "HEAD" };
bool mUpdatingHistoryRefs{ false };
bool mHistoryLoaded{ false };
UIWidget* mCommitDetailsView{ nullptr };
UITextView* mCommitDetailsSubject{ nullptr };
@@ -286,6 +312,8 @@ class GitPlugin : public PluginBase {
void updateHistoryHeader();
void updateHistoryRefs( const std::shared_ptr<GitBranchModel>& model );
void reloadHistory();
void invalidateHistory();