Skip to content

Commit c85375c

Browse files
author
Roberto De Ioris
committed
added preliminary version of python console
1 parent 2f4dfd4 commit c85375c

File tree

10 files changed

+1290
-2
lines changed

10 files changed

+1290
-2
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2+
3+
#include "PythonConsolePrivatePCH.h"
4+
#include "SPythonConsole.h"
5+
#include "SPythonLog.h"
6+
#include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructureModule.h"
7+
#include "SDockTab.h"
8+
9+
IMPLEMENT_MODULE( FPythonConsoleModule, PythonLog );
10+
11+
namespace PythonConsoleModule
12+
{
13+
static const FName PythonLogTabName = FName(TEXT("PythonLog"));
14+
}
15+
16+
/** This class is to capture all log output even if the log window is closed */
17+
class FPythonLogHistory : public FOutputDevice
18+
{
19+
public:
20+
21+
FPythonLogHistory()
22+
{
23+
GLog->AddOutputDevice(this);
24+
GLog->SerializeBacklog(this);
25+
}
26+
27+
~FPythonLogHistory()
28+
{
29+
// At shutdown, GLog may already be null
30+
if( GLog != NULL )
31+
{
32+
GLog->RemoveOutputDevice(this);
33+
}
34+
}
35+
36+
/** Gets all captured messages */
37+
const TArray< TSharedPtr<FLogMessage> >& GetMessages() const
38+
{
39+
return Messages;
40+
}
41+
42+
protected:
43+
44+
virtual void Serialize( const TCHAR* V, ELogVerbosity::Type Verbosity, const class FName& Category ) override
45+
{
46+
// Capture all incoming messages and store them in history
47+
SPythonLog::CreateLogMessages(V, Verbosity, Category, Messages);
48+
}
49+
50+
private:
51+
52+
/** All log messsges since this module has been started */
53+
TArray< TSharedPtr<FLogMessage> > Messages;
54+
};
55+
56+
/** Our global output log app spawner */
57+
static TSharedPtr<FPythonLogHistory> PythonLogHistory;
58+
59+
TSharedRef<SDockTab> SpawnPythonLog( const FSpawnTabArgs& Args )
60+
{
61+
return SNew(SDockTab)
62+
.Icon(FEditorStyle::GetBrush("Log.TabIcon"))
63+
.TabRole( ETabRole::NomadTab )
64+
.Label( NSLOCTEXT("PythonConsole", "TabTitle", "Python Console") )
65+
[
66+
SNew(SPythonLog).Messages( PythonLogHistory->GetMessages() )
67+
];
68+
}
69+
70+
void FPythonConsoleModule::StartupModule()
71+
{
72+
FGlobalTabmanager::Get()->RegisterNomadTabSpawner(PythonConsoleModule::PythonLogTabName, FOnSpawnTab::CreateStatic( &SpawnPythonLog ) )
73+
.SetDisplayName(NSLOCTEXT("UnrealEditor", "PythonLogTab", "Python Console"))
74+
.SetTooltipText(NSLOCTEXT("UnrealEditor", "PythonLogTooltipText", "Open the Python Console tab."))
75+
.SetGroup( WorkspaceMenu::GetMenuStructure().GetDeveloperToolsLogCategory() )
76+
.SetIcon( FSlateIcon(FEditorStyle::GetStyleSetName(), "Log.TabIcon") );
77+
78+
79+
PythonLogHistory = MakeShareable(new FPythonLogHistory);
80+
}
81+
82+
void FPythonConsoleModule::ShutdownModule()
83+
{
84+
if (FSlateApplication::IsInitialized())
85+
{
86+
FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(PythonConsoleModule::PythonLogTabName);
87+
}
88+
}
89+
90+
TSharedRef< SWidget > FPythonConsoleModule::MakeConsoleInputBox( TSharedPtr< SEditableTextBox >& OutExposedEditableTextBox ) const
91+
{
92+
TSharedRef< SPythonConsoleInputBox > NewConsoleInputBox = SNew( SPythonConsoleInputBox );
93+
OutExposedEditableTextBox = NewConsoleInputBox->GetEditableTextBox();
94+
return NewConsoleInputBox;
95+
}
96+
97+
98+
void FPythonConsoleModule::TogglePythonConsoleForWindow( const TSharedRef< SWindow >& Window, const EPythonConsoleStyle::Type InStyle, const FPythonConsoleDelegates& PythonConsoleDelegates )
99+
{
100+
bool bShouldOpen = true;
101+
// Close an existing console box, if there is one
102+
TSharedPtr< SWidget > PinnedPythonConsole( PythonConsole.Pin() );
103+
if( PinnedPythonConsole.IsValid() )
104+
{
105+
// If the console is already open close it unless it is in a different window. In that case reopen it on that window
106+
bShouldOpen = false;
107+
TSharedPtr< SWindow > WindowForExistingConsole = FSlateApplication::Get().FindWidgetWindow(PinnedPythonConsole.ToSharedRef());
108+
if (WindowForExistingConsole.IsValid())
109+
{
110+
WindowForExistingConsole->RemoveOverlaySlot(PinnedPythonConsole.ToSharedRef());
111+
PythonConsole.Reset();
112+
}
113+
114+
if( WindowForExistingConsole != Window )
115+
{
116+
// Console is being opened on another window
117+
bShouldOpen = true;
118+
}
119+
}
120+
121+
TSharedPtr<SDockTab> ActiveTab = FGlobalTabmanager::Get()->GetActiveTab();
122+
if (ActiveTab.IsValid() && ActiveTab->GetLayoutIdentifier() == FTabId(PythonConsoleModule::PythonLogTabName))
123+
{
124+
FGlobalTabmanager::Get()->DrawAttention(ActiveTab.ToSharedRef());
125+
bShouldOpen = false;
126+
}
127+
128+
if( bShouldOpen )
129+
{
130+
const EPythonConsoleStyle::Type PythonConsoleStyle = InStyle;
131+
TSharedRef< SPythonConsole > PythonConsoleRef = SNew( SPythonConsole, PythonConsoleStyle, this, &PythonConsoleDelegates );
132+
PythonConsole = PythonConsoleRef;
133+
134+
const int32 MaximumZOrder = MAX_int32;
135+
Window->AddOverlaySlot( MaximumZOrder )
136+
.VAlign(VAlign_Bottom)
137+
.HAlign(HAlign_Center)
138+
.Padding( 10.0f )
139+
[
140+
PythonConsoleRef
141+
];
142+
143+
// Force keyboard focus
144+
PythonConsoleRef->SetFocusToEditableText();
145+
}
146+
}
147+
148+
149+
void FPythonConsoleModule::ClosePythonConsole()
150+
{
151+
TSharedPtr< SWidget > PinnedPythonConsole( PythonConsole.Pin() );
152+
153+
if( PinnedPythonConsole.IsValid() )
154+
{
155+
TSharedPtr< SWindow > WindowForExistingConsole = FSlateApplication::Get().FindWidgetWindow(PinnedPythonConsole.ToSharedRef());
156+
if (WindowForExistingConsole.IsValid())
157+
{
158+
WindowForExistingConsole->RemoveOverlaySlot( PinnedPythonConsole.ToSharedRef() );
159+
PythonConsole.Reset();
160+
}
161+
}
162+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2+
3+
#pragma once
4+
5+
#include "UnrealEd.h"
6+
#include "PythonConsoleModule.h"
7+
#include "SlateBasics.h"
8+
9+
#if UNREAL_ENGINE_PYTHON_ON_MAC
10+
#include <python3.5m/Python.h>
11+
#else
12+
#include <include/Python.h>
13+
#endif
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2+
3+
#include "PythonConsolePrivatePCH.h"
4+
#include "PythonConsoleModule.h"
5+
#include "SPythonConsole.h"
6+
#include "SPythonLog.h"
7+
8+
namespace PythonConsoleDefs
9+
{
10+
// How many seconds to animate when console is summoned
11+
static const float IntroAnimationDuration = 0.25f;
12+
}
13+
14+
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
15+
16+
void SPythonConsole::Construct( const FArguments& InArgs, const EPythonConsoleStyle::Type InStyle, FPythonConsoleModule* PythonConsoleModule, const FPythonConsoleDelegates* PythonConsoleDelegates )
17+
{
18+
CurrentStyle = InStyle;
19+
20+
TSharedPtr<SPythonConsoleInputBox> ConsoleInputBox;
21+
22+
check( PythonConsoleModule != NULL );
23+
ChildSlot
24+
[
25+
SNew( SVerticalBox )
26+
+SVerticalBox::Slot()
27+
.AutoHeight()
28+
[
29+
SNew( SVerticalBox )
30+
.Visibility( this, &SPythonConsole::MakeVisibleIfLogIsShown )
31+
32+
+SVerticalBox::Slot()
33+
.AutoHeight()
34+
.Padding( 10.0f )
35+
[
36+
SNew(SBox)
37+
.HeightOverride( 200.0f )
38+
[
39+
SNew( SBorder )
40+
.BorderImage( FEditorStyle::GetBrush( "ToolPanel.GroupBorder" ) )
41+
.ColorAndOpacity( this, &SPythonConsole::GetAnimatedColorAndOpacity )
42+
.BorderBackgroundColor( this, &SPythonConsole::GetAnimatedSlateColor )
43+
[
44+
SNew( SSpacer )
45+
]
46+
]
47+
]
48+
]
49+
50+
+SVerticalBox::Slot()
51+
.AutoHeight()
52+
.Padding( 10.0f )
53+
[
54+
SNew(SBox)
55+
.HeightOverride( 26.0f )
56+
.HAlign( HAlign_Left )
57+
[
58+
SNew( SBorder )
59+
.Padding( FMargin(2) )
60+
.BorderImage( FEditorStyle::GetBrush( "PythonConsole.Background" ) )
61+
.ColorAndOpacity( this, &SPythonConsole::GetAnimatedColorAndOpacity )
62+
.BorderBackgroundColor( this, &SPythonConsole::GetAnimatedSlateColor )
63+
[
64+
SNew(SHorizontalBox)
65+
+ SHorizontalBox::Slot()
66+
.AutoWidth()
67+
.Padding(3.0f)
68+
.VAlign(VAlign_Center)
69+
[
70+
SNew(STextBlock)
71+
.Text(NSLOCTEXT("Console", "ConsoleLabel", "Console"))
72+
73+
]
74+
+ SHorizontalBox::Slot()
75+
.Padding(5.0f, 2.0f)
76+
.VAlign(VAlign_Center)
77+
.MaxWidth(400.0f)
78+
[
79+
SAssignNew(ConsoleInputBox, SPythonConsoleInputBox)
80+
.OnConsoleCommandExecuted(PythonConsoleDelegates->OnConsoleCommandExecuted)
81+
]
82+
]
83+
]
84+
]
85+
];
86+
87+
EditableTextBox = ConsoleInputBox->GetEditableTextBox();
88+
89+
// Kick off intro animation
90+
AnimCurveSequence = FCurveSequence();
91+
AnimCurve = AnimCurveSequence.AddCurve( 0.0f, PythonConsoleDefs::IntroAnimationDuration, ECurveEaseFunction::QuadOut );
92+
FlashCurve = AnimCurveSequence.AddCurve( PythonConsoleDefs::IntroAnimationDuration, .15f, ECurveEaseFunction::QuadInOut );
93+
94+
AnimCurveSequence.Play(this->AsShared());
95+
}
96+
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
97+
98+
SPythonConsole::SPythonConsole()
99+
: CurrentStyle( EPythonConsoleStyle::Compact )
100+
{
101+
}
102+
103+
104+
void SPythonConsole::SetFocusToEditableText()
105+
{
106+
FSlateApplication::Get().SetKeyboardFocus( EditableTextBox.ToSharedRef(), EFocusCause::SetDirectly );
107+
}
108+
109+
EVisibility SPythonConsole::MakeVisibleIfLogIsShown() const
110+
{
111+
return CurrentStyle == EPythonConsoleStyle::WithLog ? EVisibility::Visible : EVisibility::Collapsed;
112+
}
113+
114+
115+
FLinearColor SPythonConsole::GetAnimatedColorAndOpacity() const
116+
{
117+
return FLinearColor( 1.0f, 1.0f, 1.0f, AnimCurve.GetLerp() );
118+
}
119+
120+
121+
FSlateColor SPythonConsole::GetAnimatedSlateColor() const
122+
{
123+
return FSlateColor( GetAnimatedColorAndOpacity() );
124+
}
125+
126+
FSlateColor SPythonConsole::GetFlashColor() const
127+
{
128+
float FlashAlpha = 1.0f - FlashCurve.GetLerp();
129+
130+
if (FlashAlpha == 1.0f)
131+
{
132+
FlashAlpha = 0.0f;
133+
}
134+
135+
return FLinearColor(1,1,1,FlashAlpha);
136+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2+
3+
#pragma once
4+
5+
6+
/**
7+
* Debug console widget, designed to be summoned on top of a viewport or window
8+
*/
9+
class SPythonConsole : public SCompoundWidget
10+
{
11+
public:
12+
13+
SLATE_BEGIN_ARGS( SPythonConsole )
14+
{
15+
}
16+
17+
SLATE_END_ARGS()
18+
19+
/** Constructs this widget */
20+
void Construct( const FArguments& InArgs, const EPythonConsoleStyle::Type InStyle, FPythonConsoleModule* PythonConsoleModule, const FPythonConsoleDelegates* PythonConsoleDelegates );
21+
22+
/** Call to set focus to this debug console's editable text box */
23+
void SetFocusToEditableText();
24+
25+
/** Default constructor */
26+
SPythonConsole();
27+
28+
29+
protected:
30+
/** Returns EVisibility::Visible if style has log being shown, otherwise VIS_COLLAPSED */
31+
EVisibility MakeVisibleIfLogIsShown() const;
32+
33+
/** Returns a color and opacity value to use based on any current animation */
34+
FLinearColor GetAnimatedColorAndOpacity() const;
35+
36+
/** Returns a Slate color based on any current animation (same color as GetAnimatedColorAndOpacity) */
37+
FSlateColor GetAnimatedSlateColor() const;
38+
39+
FSlateColor GetFlashColor() const;
40+
private:
41+
42+
/** Editable text box for this debug console's input line */
43+
TSharedPtr< SEditableTextBox > EditableTextBox;
44+
45+
/** Current style of the debug console. Can be changed on the fly. */
46+
EPythonConsoleStyle::Type CurrentStyle;
47+
48+
/** Intro/outro animation curve */
49+
FCurveSequence AnimCurveSequence;
50+
FCurveHandle AnimCurve;
51+
FCurveHandle FlashCurve;
52+
};
53+

0 commit comments

Comments
 (0)