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+ }
0 commit comments