@@ -24,6 +24,7 @@ import OutputViewToggle from "../OutputViewToggle";
24
24
import { SettingsContext } from "../../../../../utils/settings" ;
25
25
import RunnerControls from "../../../../RunButton/RunnerControls" ;
26
26
import { MOBILE_MEDIA_QUERY } from "../../../../../utils/mediaQueryBreakpoints" ;
27
+ import { getPythonImports } from "../../../../../utils/getPythonImports" ;
27
28
28
29
const externalLibraries = {
29
30
"./pygal/__init__.js" : {
@@ -55,6 +56,15 @@ const externalLibraries = {
55
56
} ,
56
57
} ;
57
58
59
+ const VISUAL_LIBRARIES = [
60
+ "pygal" ,
61
+ "py5" ,
62
+ "py5_imported" ,
63
+ "p5" ,
64
+ "sense_hat" ,
65
+ "turtle" ,
66
+ ] ;
67
+
58
68
const SkulptRunner = ( { active, outputPanels = [ "text" , "visual" ] } ) => {
59
69
const loadedRunner = useSelector ( ( state ) => state . editor . loadedRunner ) ;
60
70
const projectCode = useSelector ( ( state ) => state . editor . project . components ) ;
@@ -83,10 +93,31 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
83
93
const settings = useContext ( SettingsContext ) ;
84
94
const isMobile = useMediaQuery ( { query : MOBILE_MEDIA_QUERY } ) ;
85
95
96
+ const project = useSelector ( ( state ) => state . editor . project ) ;
97
+
98
+ const testForVisualImports = ( project ) => {
99
+ for ( const component of project . components || [ ] ) {
100
+ if ( component . extension === "py" ) {
101
+ try {
102
+ const imports = getPythonImports ( component . content , t ) ;
103
+ const hasVisualImports = imports . some ( ( name ) =>
104
+ VISUAL_LIBRARIES . includes ( name ) ,
105
+ ) ;
106
+ if ( hasVisualImports ) {
107
+ return true ;
108
+ }
109
+ } catch ( error ) {
110
+ console . error ( "Error occurred while getting imports:" , error ) ;
111
+ }
112
+ }
113
+ }
114
+ return false ;
115
+ } ;
116
+
86
117
const [ codeHasVisualOutput , setCodeHasVisualOutput ] = useState (
87
- senseHatAlwaysEnabled ,
118
+ ! ! senseHatAlwaysEnabled || testForVisualImports ( project ) ,
88
119
) ;
89
- const [ showVisualOutput , setShowVisualOutput ] = useState ( true ) ;
120
+ const [ showVisualOutput , setShowVisualOutput ] = useState ( codeHasVisualOutput ) ;
90
121
91
122
const getInput = ( ) => {
92
123
const pageInput = document . getElementById ( "input" ) ;
@@ -96,6 +127,14 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
96
127
return pageInput || webComponentInput ;
97
128
} ;
98
129
130
+ useEffect ( ( ) => {
131
+ if ( ! codeRunTriggered ) {
132
+ setCodeHasVisualOutput (
133
+ ! ! senseHatAlwaysEnabled || testForVisualImports ( project ) ,
134
+ ) ;
135
+ }
136
+ } , [ project , codeRunTriggered , senseHatAlwaysEnabled , t ] ) ;
137
+
99
138
useEffect ( ( ) => {
100
139
if ( active && loadedRunner !== "skulpt" ) {
101
140
dispatch ( setLoadedRunner ( "skulpt" ) ) ;
@@ -136,15 +175,6 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
136
175
}
137
176
} , [ drawTriggered , codeRunTriggered ] ) ;
138
177
139
- const visualLibraries = [
140
- "./pygal/__init__.js" ,
141
- "./py5/__init__.js" ,
142
- "./py5_imported/__init__.js" ,
143
- "./p5/__init__.js" ,
144
- "./_internal_sense_hat/__init__.js" ,
145
- "src/builtin/turtle/__init__.js" ,
146
- ] ;
147
-
148
178
const outf = ( text ) => {
149
179
if ( text !== "" ) {
150
180
const node = output . current ;
@@ -169,10 +199,6 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
169
199
170
200
// TODO: Handle pre-importing py5_imported when refactored py5 shim imported
171
201
172
- if ( visualLibraries . includes ( library ) ) {
173
- setCodeHasVisualOutput ( true ) ;
174
- }
175
-
176
202
let localProjectFiles = projectCode
177
203
. filter ( ( component ) => component . name !== "main" )
178
204
. map ( ( component ) => `./${ component . name } .py` ) ;
@@ -436,6 +462,18 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
436
462
} ) ;
437
463
} ;
438
464
465
+ const [ tabbedViewSelectedIndex , setTabbedViewSelectedIndex ] = useState (
466
+ showVisualOutput ? 0 : 1 ,
467
+ ) ;
468
+
469
+ useEffect ( ( ) => {
470
+ if ( showVisualOutput ) {
471
+ setTabbedViewSelectedIndex ( 0 ) ;
472
+ } else {
473
+ setTabbedViewSelectedIndex ( 1 ) ;
474
+ }
475
+ } , [ showVisualOutput ] ) ;
476
+
439
477
return (
440
478
< div
441
479
className = { classNames ( "pythonrunner-container" , "skulptrunner" , {
@@ -444,8 +482,11 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
444
482
>
445
483
{ isSplitView || singleOutputPanel ? (
446
484
< >
447
- { showVisualOutput && showVisualOutputPanel && (
448
- < div className = { outputPanelClasses ( "visual" ) } >
485
+ { showVisualOutputPanel && (
486
+ < div
487
+ className = { outputPanelClasses ( "visual" ) }
488
+ style = { { blockSize : showVisualOutput ? "auto" : 0 } }
489
+ >
449
490
< Tabs forceRenderTabPanel = { true } >
450
491
< div
451
492
className = { classNames ( "react-tabs__tab-container" , {
@@ -503,16 +544,16 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
503
544
< Tabs
504
545
forceRenderTabPanel = { true }
505
546
defaultIndex = { showVisualOutput ? 0 : 1 }
547
+ selectedIndex = { tabbedViewSelectedIndex }
548
+ onSelect = { setTabbedViewSelectedIndex }
506
549
>
507
550
< div className = "react-tabs__tab-container" >
508
551
< TabList >
509
- { showVisualOutput ? (
510
- < Tab key = { 0 } >
511
- < span className = "react-tabs__tab-text" >
512
- { t ( "output.visualOutput" ) }
513
- </ span >
514
- </ Tab >
515
- ) : null }
552
+ < Tab key = { 0 } style = { { blockSize : showVisualOutput ? "auto" : 0 } } >
553
+ < span className = "react-tabs__tab-text" >
554
+ { t ( "output.visualOutput" ) }
555
+ </ span >
556
+ </ Tab >
516
557
< Tab key = { 1 } >
517
558
< span className = "react-tabs__tab-text" >
518
559
{ t ( "output.textOutput" ) }
@@ -523,11 +564,9 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
523
564
{ ! isEmbedded && isMobile && < RunnerControls skinny /> }
524
565
</ div >
525
566
{ ! isOutputOnly && < ErrorMessage /> }
526
- { showVisualOutput ? (
527
- < TabPanel key = { 0 } >
528
- < VisualOutputPane />
529
- </ TabPanel >
530
- ) : null }
567
+ < TabPanel key = { 0 } >
568
+ < VisualOutputPane />
569
+ </ TabPanel >
531
570
< TabPanel key = { 1 } >
532
571
< pre
533
572
className = { `pythonrunner-console pythonrunner-console--${ settings . fontSize } ` }
0 commit comments