Transpiled version (54188L) is out of date.
1 | !7 |
2 | |
3 | set flag GazelleMain. |
4 | |
5 | !include early #1035306 // "need latest" Include |
6 | |
7 | // We're banning db_mainConcepts() again to allow multiple databases loaded at once |
8 | |
9 | // !transpileMainSnippet #1033860 |
10 | |
11 | !include once #1033998 // RSyntaxTextArea |
12 | !include once #1013490 // sarxos webcam |
13 | |
14 | !include early #1034876 // Gazelle 22 Flags [Include] |
15 | |
16 | !include early #1033884 // Compact Module Include Gazelle V [dev version] |
17 | |
18 | !include once #1034034 // Gazelle 22 Function Include for Scripts |
19 | |
20 | !include once #1035461 // Gazelle 22 Class synonyms Include |
21 | |
22 | module GazelleScreenCam is G22ProjectActions { |
23 | !include early #1025212 // +Enabled without visualization |
24 | { enabled = false; } |
25 | |
26 | transient static bool autoRunSelfTests = false; |
27 | |
28 | new SnPSettings screenCamSnPSettings; |
29 | settableWithVar bool screenCamShowDecolorizerSelection; |
30 | S script = "64p 8c gradientImage"; |
31 | settableWithVar S newScript; |
32 | S screenCamScript; |
33 | S selectedTab; |
34 | S javaCode; |
35 | bool horizontalLayout; // flat layout |
36 | int fpsTarget = 20; |
37 | S webCamName; |
38 | bool webCamAccessEnabled = true; |
39 | |
40 | // libraries to load when project is opened |
41 | gettable Set<S> projectLibs = syncSet(); |
42 | |
43 | G22WatchTarget watchTarget; |
44 | |
45 | new G22_TestScreenPanel testScreen; |
46 | |
47 | // The following fields related to the screen cam panel |
48 | transient ImageSurface isPosterized; |
49 | transient new ScreenCamStream imageStream; |
50 | |
51 | transient Gazelle22_ImageToRegions imageToRegions_finished; |
52 | transient new DoubleFPSCounter fpsCounter; |
53 | transient int fps; |
54 | transient WatchTargetSelector watchTargetSelector; |
55 | transient new RollingAverage remainingMSPerFrame; |
56 | transient int remainingMS; |
57 | // End of fields for screen cam panel |
58 | |
59 | transient new FunctionTimings<S> functionTimings; |
60 | |
61 | transient ReliableSingleThread rstRunScript = dm_rst(me(), r _runScript); |
62 | |
63 | transient JGazelleVScriptRunner scriptRunner; |
64 | |
65 | new UIURLSystem uiURLs; |
66 | |
67 | //transient L<Webcam> availableWebCams; |
68 | transient JComboBox<Webcam> cbWebCam; |
69 | transient SingleComponentPanel scpWebCamImage; |
70 | transient WebcamPanel webCamPanel; |
71 | |
72 | transient JLeftArrowScriptIDE screenCamScriptIDE; |
73 | transient GazelleV_LeftArrowScript.Script runningScreenCamScript; |
74 | |
75 | // set by host |
76 | transient gettable Concepts concepts; |
77 | |
78 | S uiURL = "Main Tabs"; |
79 | |
80 | transient SimpleCRUD_v2<Label> labelCRUD; |
81 | transient SimpleCRUD_v2<GalleryImage> galleryCRUD; |
82 | transient JComponent galleryCRUDVis; |
83 | |
84 | transient SimpleCRUD_v2<Entity> entityCRUD; |
85 | |
86 | transient JGallery /*gallery,*/ paintToolGallery; |
87 | //transient ImageSurface galleryImageSurface; |
88 | |
89 | transient FlexibleRateTimer screenCamTimer; |
90 | transient SingleComponentPanel scpMain; |
91 | transient gettable DynamicVStack topStack; |
92 | transient gettable JTabbedPane mainTabs; |
93 | transient bool showRegionsAsOutline = true; |
94 | transient JComponent watchScreenPane; |
95 | transient S screenCamRecognitionOutput; |
96 | |
97 | transient gettable new G22Utils g22utils; |
98 | delegate stdImageSurface, setupScriptCRUD, dbDir, makeVariablesPanel to g22utils. |
99 | |
100 | delegate showUIURL, renderUIURL to uiURLs. |
101 | |
102 | transient new BackgroundProcessesUI backgroundProcessesUI; |
103 | |
104 | transient BackgroundProcessesUI.Entry bgScreenCam = backgroundProcessesUI.new Entry("Screen Cam") |
105 | .menuItem(jMenuItem("Screen Cam", r showScreenCam)); |
106 | transient BackgroundProcessesUI.Entry bgWebCam = backgroundProcessesUI.new Entry("Web Cam") |
107 | .menuItem(jMenuItem("Web Cam", r showWebCam)); |
108 | |
109 | bool autoRunChallenge = true; |
110 | |
111 | transient G22ChallengesPanel challengesPanel; |
112 | |
113 | transient JComponent urlBar; |
114 | |
115 | transient JVideoLibDownloader videoLibDownloader; |
116 | transient JFFMPEGVideoPlayer videoPlayer; |
117 | |
118 | // it's now actually persistent |
119 | settableWithVar JPaintTool paintTool; |
120 | |
121 | // also persistent |
122 | G22AnalysisPanel paintAnalysisPanel; |
123 | |
124 | // to detect when the project is moved. not implemented yet |
125 | //settableWithVar File previousConceptsDir; |
126 | |
127 | transient gettable G22SelfTests selfTests; |
128 | |
129 | settableWithVar bool paintToolGalleryExpanded; |
130 | |
131 | transient JComponent screenCamTab; |
132 | |
133 | transient GazelleV_LeftArrowScriptParser prototypeParser; |
134 | |
135 | gettable transient JPanel generalInfoPanel = jline(); |
136 | |
137 | //new Ref<G22Analyzer> screenCamAnalyzer; TODO: module is not a concept... |
138 | settableWithVar G22Analyzer screenCamAnalyzer; |
139 | |
140 | settableWithVar G22LeftArrowScript showCasedScript; |
141 | |
142 | transient G22Analyzer.CompiledAnalyzer runningScreenCamAnalyzer; |
143 | |
144 | transient SourceTriggeredStream<BufferedImage> imageStreamForAnalyzer; |
145 | |
146 | transient SingleComponentPanel scpScreenCamImage = scp(); |
147 | |
148 | settableWithVar bool imageRecognitionEnabled = true; |
149 | |
150 | gettable L<PersistableThrowable> projectErrors = syncLinkedList(); |
151 | transient settable int maxProjectErrors = 40; |
152 | |
153 | // add fields here |
154 | |
155 | start { |
156 | g22utils.module(this); |
157 | |
158 | // load libraries if downloaded |
159 | for (S libID : projectLibs) { |
160 | File f = fileForLibrary(libID); |
161 | if (fileExists(f)) { |
162 | print("Loading iibrary " + libID); |
163 | addLibrary(f); |
164 | } |
165 | } |
166 | |
167 | testScreen.g22utils(g22utils); |
168 | testScreen.onChange(l0 change); |
169 | |
170 | dm_onFieldChange horizontalLayout( |
171 | //r dm_revisualize // deh buggy |
172 | r dm_reload |
173 | ); |
174 | |
175 | /*if (concepts == null) { |
176 | // non-standalone mode (doesn't work yet) |
177 | printWithMS("Starting DB"); |
178 | db(); |
179 | concepts = db_mainConcepts(); |
180 | } else |
181 | assertSame(concepts, db_mainConcepts());*/ |
182 | |
183 | concepts.quietSave = true; |
184 | concepts.modifyOnCreate(true); // It's just the right thing to do. |
185 | |
186 | setModuleName(replaceIfEquals(g22utils.projectName(), g22utils.defaultDBName(), "")); |
187 | |
188 | // make indexes |
189 | indexConceptField(concepts, GalleryImage, "path"); |
190 | indexConceptField(concepts, Example, "item"); |
191 | indexConceptFieldCI(concepts, G22Label, "name"); |
192 | indexConceptField(concepts, G22Variable, "name"); |
193 | indexConceptField(concepts, G22TravelLogEntry, "timestamp"); |
194 | ensureConceptClassesAreIndexed(concepts, G22PointOfInterest); |
195 | |
196 | // complete initialisation of g22utils |
197 | g22utils.concepts(concepts); |
198 | concepts.miscMapPut(G22Utils.class, g22utils); |
199 | g22utils.backgroundProcessesUI(backgroundProcessesUI); |
200 | g22utils.functionTimings(functionTimings); |
201 | |
202 | // Update project dir in G22ProjectInfo |
203 | |
204 | G22ProjectInfo projectInfo = g22utils.projectInfo(); |
205 | File oldProjectDir = projectInfo.projectDir; |
206 | File projectDir = g22utils.projectDir(); |
207 | if (cset_trueIfChanged(projectInfo, +projectDir) |
208 | && oldProjectDir != null) { |
209 | projectInfo.addHistoricalProjectDir(oldProjectDir); |
210 | //infoBox("TODO: Migrate project dir from " + oldProjectDir); |
211 | } |
212 | |
213 | // Update travel log |
214 | if (G22TravelLogEntry.shouldCreateEntry(g22utils)) |
215 | thread "Make Travel Log Entry" { |
216 | printWithMS("Creating travel log entry."); |
217 | registerConcept(concepts, G22TravelLogEntry.create(g22utils) |
218 | .scanProject(g22utils) |
219 | .action("First travel log entry")); |
220 | printWithMS("Created travel log entry."); |
221 | } |
222 | |
223 | // fix legacy bug |
224 | for (c : list(concepts)) fixFieldValues(c); |
225 | |
226 | makePrototypeParser(); |
227 | |
228 | g22utils.onSettingUpParser(l1 adaptLeftArrowParser); |
229 | g22utils.projectActions(this); |
230 | g22utils.onSettingUpScriptIDE(ide -> { |
231 | // go-to-script handler (for "callScript 123") |
232 | |
233 | ide.addGoToDefinitionHandler(tokPtr -> { |
234 | S prevToken = _get(tokPtr.list(), tokPtr.idx()-2); |
235 | S token = tokPtr.get(); |
236 | if (eq(prevToken, "callScript") && isInteger(token)) { |
237 | var script = g22utils.getScript(parseLong(token)); |
238 | if (script != null) |
239 | ret -> g22utils.editScript(script); |
240 | } |
241 | null; |
242 | }); |
243 | |
244 | // project-defined functions + classes |
245 | ide.addGoToDefinitionHandler(tokPtr -> { |
246 | S token = tokPtr.get(); |
247 | if (!isIdentifier(token)) null; |
248 | |
249 | var def = findDefinition(token); |
250 | ret def == null ?: -> goToSource(def); |
251 | }); |
252 | |
253 | if (!devMode()) ret; |
254 | |
255 | var scp = scp(); |
256 | addInFront(ide.buttons(), scp); |
257 | |
258 | ide.varCompileResult().onChange(cr -> { |
259 | temp enter(); |
260 | |
261 | // Offer to add standard function or class to Gazelle (if authorized) |
262 | var e = innerExceptionOfType(GazelleV_LeftArrowScriptParser.UnknownObject.class, cr?.compileError); |
263 | if (e != null) { |
264 | //print("Checking repo for unknown object " + quote(e.name)); |
265 | // An unknown object is referenced in the source. Let's hunt for it. |
266 | |
267 | if (isStandardFunction(e.name)) { |
268 | var btn = jbuttonWithDisable("Add function " + e.name, r { |
269 | infoBoxAndCompile(addFunctionNameToInclude(functionsIncludeID(), e.name)); |
270 | }); |
271 | componentPopupMenuItem(btn, "Add but don't recompile", |
272 | rThread { |
273 | addFunctionNameToInclude(functionsIncludeID(), e.name); |
274 | infoBox("Added"); |
275 | }); |
276 | ret with scp.set(btn); |
277 | } |
278 | |
279 | if (isStandardClass(e.name)) |
280 | ret with scp.set(jbuttonWithDisable("Add class " + e.name, r { |
281 | infoBoxAndCompile(addClassNameToInclude(functionsIncludeID(), e.name)); |
282 | })); |
283 | } |
284 | |
285 | scp.clear(); |
286 | }); |
287 | }); |
288 | |
289 | g22utils.autoStarter().init(); |
290 | |
291 | //g22utils.basicParserTest(); |
292 | |
293 | // update count in tab when tab isn't selected |
294 | // TODO: move this to a separate helper |
295 | /*onConceptChangeByClass(concepts, Label, -> { |
296 | labelCRUD?.updateEnclosingTabTitle(); |
297 | //galleryCRUD?.updateEnclosingTabTitle(); |
298 | });*/ |
299 | |
300 | uiURLs.owner = me(); |
301 | uiURLs.uiURL = dm_fieldLiveValue uiURL(); |
302 | uiURLs.addPreferredUIURL("Main Tabs"); |
303 | |
304 | dm_watchFieldAndNow enabled(-> backgroundProcessesUI.addOrRemove(enabled, bgScreenCam)); |
305 | |
306 | scriptRunner = new JGazelleVScriptRunner(dm_fieldLiveValue script(me())); |
307 | |
308 | printWithMS("Making image stream"); |
309 | |
310 | imageStream.onNewElement(img -> { |
311 | fpsCounter.inc(); |
312 | setField(fps := iround(fpsCounter!)); |
313 | |
314 | // perform analysis on screen cam image |
315 | |
316 | // new G22_ImageAnalysis screenCamImageAnalysis; |
317 | |
318 | assertTrue("meta", getMetaSrc(img) instanceof ScreenShotMeta); |
319 | |
320 | if (screenCamAnalyzer != null) { |
321 | imageStreamForAnalyzer?.newElement(img); |
322 | } else { |
323 | // DEFAULT analyzer (regions) |
324 | Gazelle22_ImageToRegions itr = new(functionTimings, img, screenCamSnPSettings); |
325 | itr.run(); |
326 | imageToRegions_finished = itr; |
327 | |
328 | // run "linear" script on image if any |
329 | |
330 | if (shouldRunScript()) rstRunScript.go(); |
331 | |
332 | // run left-arrow script |
333 | |
334 | if (screenCamScriptIDE != null |
335 | && screenCamScriptIDE.visible()) try { |
336 | g22_runPostAnalysisLeftArrowScript(itr, runningScreenCamScript); |
337 | } catch e { |
338 | printStackTrace(e); |
339 | screenCamScriptIDE.showRuntimeError(e); |
340 | } |
341 | |
342 | // make textual result of analysis |
343 | |
344 | S text = nRegions(itr.regions.regionCount()); |
345 | setField(screenCamRecognitionOutput := text); |
346 | |
347 | // display image after analysis so we can highlight a region |
348 | |
349 | g22_renderPosterizedHighlightedImage(isPosterized, itr, showRegionsAsOutline); |
350 | } // end of DEFAULT analysis path |
351 | }); |
352 | |
353 | if (watchTarget == null) { |
354 | watchTarget = defaultWatchTarget(); |
355 | change(); |
356 | } |
357 | |
358 | watchTargetSelector = new WatchTargetSelector; |
359 | watchTargetSelector.visualize(); |
360 | |
361 | /*if (webCamAccessEnabled) { |
362 | printWithMS("Detecting web cams"); |
363 | watchTargetSelector.updateCamCount(); |
364 | printWithMS("Found " + n2(availableWebCams, "web cam")); |
365 | }*/ |
366 | |
367 | isPosterized = stdImageSurface(); |
368 | |
369 | varScreenCamAnalyzer().onChangeAndNow(analyzer -> |
370 | q().add(-> { |
371 | if (analyzer == null) { |
372 | runningScreenCamAnalyzer = null; |
373 | imageStreamForAnalyzer = null; |
374 | scpScreenCamImage.set(withTools(isPosterized)); |
375 | } else { |
376 | runningScreenCamAnalyzer = analyzer.compileForAutoRun(); |
377 | imageStreamForAnalyzer = new SourceTriggeredStream<BufferedImage>; |
378 | G22AnalysisContext context = new(g22utils, imageStreamForAnalyzer); |
379 | O analyzerResult = runningScreenCamAnalyzer.get(context); |
380 | print(+analyzerResult); |
381 | scpScreenCamImage.set(new G22JavaObjectVisualizer(g22utils, analyzerResult)); |
382 | } // else branch |
383 | })); |
384 | |
385 | printWithMS("Starting screen cam"); |
386 | |
387 | ownResource(screenCamTimer = new FlexibleRateTimer(fpsTarget, rEnter { |
388 | if (!enabled) ret; |
389 | watchTargetSelector?.updateScreenCount(); |
390 | Timestamp deadline = tsNowPlusMS(1000/fpsTarget); |
391 | watchTarget?.mainWindow(getWindow(urlBar)); |
392 | watchTarget?.configureScreenCamStream(imageStream); |
393 | imageStream.step(); |
394 | long remaining = deadline.minus(tsNow()); |
395 | remainingMSPerFrame.add(remaining); |
396 | setField(remainingMS := iround(remainingMSPerFrame!)); |
397 | })); |
398 | screenCamTimer.start(); |
399 | dm_onFieldChange fpsTarget(-> screenCamTimer.setFrequencyImmediately(fpsTarget)); |
400 | |
401 | printWithMS("Gathering images from disk"); |
402 | //addDirToGallery(galleryDir())); |
403 | addDirToGallery(conceptsDir(concepts)); |
404 | printWithMS("Got dem images"); |
405 | |
406 | transpileRaw_makeTranslator = -> hotwire(#7); |
407 | |
408 | // OSHI adds 4.5 MB to the jar... |
409 | //doAfter(5.0, r { print("Process size: ", toM_str(oshi_currentProcessResidentSize_noZGCFix())) }); |
410 | } // end of start method |
411 | |
412 | void addDirToGallery(File dir) { |
413 | watchDirForGallery(dir); |
414 | for (f : allImageFiles(dir)) |
415 | addToGallery(f); |
416 | } |
417 | |
418 | void watchDirForGallery(File dir) { |
419 | g22utils.onProjectFileChanged(file -> { |
420 | if (isImageFile(file)) |
421 | addToGallery(file); |
422 | }); |
423 | } |
424 | |
425 | // main window visualization |
426 | cachedVisualize { |
427 | // if screen cam is not enabled, highlight regions of last captured image |
428 | // on mouse hover |
429 | |
430 | imageSurfaceOnHover(isPosterized, pt -> { |
431 | if (!enabled && imageToRegions_finished != null) |
432 | g22_renderPosterizedHighlightedImage(isPosterized, imageToRegions_finished, |
433 | showRegionsAsOutline); |
434 | }); |
435 | |
436 | labelCRUD = new SimpleCRUD_v2(concepts, Label); |
437 | labelCRUD.hideFields("globalID"); |
438 | //labelCRUD.addCountToEnclosingTab(true); |
439 | labelCRUD.itemToMap_inner2 = l |
440 | -> litorderedmap( |
441 | "Name" := l.name, |
442 | "# Examples" := n2(countConcepts(concepts, Example, label := l))); |
443 | |
444 | galleryCRUD = new SimpleCRUD_v2(concepts, GalleryImage); |
445 | //galleryCRUD.addCountToEnclosingTab(true); |
446 | galleryCRUD.itemToMap_inner2 = img |
447 | -> litorderedmap( |
448 | "File" := fileName(img.path), |
449 | "Folder" := dirPath(img.path)); |
450 | galleryCRUD.defaultAction(img -> { thread { showImage(img.path) }}); |
451 | galleryCRUDVis = galleryCRUD.visualize(); |
452 | galleryCRUD.addButton(jPopDownButton_noText( |
453 | "Forget missing images" := rThreadEnter forgetMissingImages |
454 | )); |
455 | galleryCRUD.addButton("Back to gallery", rThreadEnter { showUIURL("Gallery") }); |
456 | galleryCRUD.newConcept = -> { |
457 | new JFileChooser fc; |
458 | fc.setDialogTitle("Add image to gallery"); |
459 | fc.setCurrentDirectory(conceptsDir(concepts)); |
460 | fc.setFileFilter(new ImageFileFilter().allowDirectories(true)); |
461 | addToGallery(execFileChooser(fc)); |
462 | }; |
463 | |
464 | // main visual |
465 | |
466 | var screenCamSnPSelector = new G22SnPSelector(screenCamSnPSettings) |
467 | .allowDecolorizerSelection(true); |
468 | screenCamSnPSelector.onChange(l0 change); |
469 | linkVars(varScreenCamShowDecolorizerSelection(), |
470 | screenCamSnPSelector.varShowDecolorizerSelection()); |
471 | |
472 | watchScreenPane = jHigherScrollPane_borderless_center (vstack( |
473 | withLeftAndRightMargin(hstack( |
474 | dm_rcheckBox enabled("Watch"), |
475 | watchTargetSelector.visualize(), |
476 | jlabel(" in "), |
477 | screenCamSnPSelector, |
478 | jlabel(" Analyzer "), |
479 | bindComboBoxToVar(varScreenCamAnalyzer(), |
480 | swing(-> new ConceptsComboBox(g22utils.concepts(), G22Analyzer) |
481 | .allowNull(true))), |
482 | )), |
483 | verticalStrut(2), |
484 | withSideMargins(centerAndEastWithMargin( |
485 | dm_fieldLabel screenCamRecognitionOutput(), |
486 | dm_transientCalculatedToolTip speedInfo_long(rightAlignLabel(dm_transientCalculatedLabel speedInfo())) |
487 | )), |
488 | )); |
489 | |
490 | topStack = dynamicVStack(); |
491 | topStack.spacing(0); |
492 | |
493 | initUIURLs(); |
494 | |
495 | mainTabs = scrollingTabs(jTopOrLeftTabs(horizontalLayout)); |
496 | |
497 | //addUIURLToMainTabs("Screen Cam"); |
498 | addUIURLToMainTabs("Project Overview"); |
499 | addUIURLToMainTabs("Showcase"); |
500 | addUIURLToMainTabs("Scripts"); |
501 | if (imageRecognitionEnabled) { |
502 | addUIURLToMainTabs("Masks"); |
503 | addUIURLToMainTabs("Shape Collector"); |
504 | addUIURLToMainTabs("Points of interest"); |
505 | } |
506 | addUIURLToMainTabs("Gallery"); |
507 | addUIURLToMainTabs("Scratchpad"); |
508 | addUIURLToMainTabs("Paint"); |
509 | if (imageRecognitionEnabled) { |
510 | addUIURLToMainTabs("Analyzers"); |
511 | //addUIURLToMainTabs("Networks"); |
512 | } |
513 | addUIURLToMainTabs("Projects"); |
514 | |
515 | // add tabs here |
516 | |
517 | // add main tabs to UI URLs (probably don't need this anymore) |
518 | for (S tab : tabNames(mainTabs)) { |
519 | reMutable tab = dropTrailingBracketedCount(tab); |
520 | uiURLs.put(tab, -> { |
521 | int i = indexOfTabNameWithoutTrailingCount(mainTabs, tab); |
522 | if (i < 0) ret jcenteredlabel("Hmm. Tab not found"); |
523 | selectTab(mainTabs, i); |
524 | ret mainTabs; |
525 | }); |
526 | } |
527 | |
528 | // Fix UI URL after tab was changed manually |
529 | // Hopefully doesn't brake stuff (seems it doesn't) |
530 | onTabSelected(mainTabs, -> { |
531 | if (!isShowing(mainTabs)) ret; |
532 | S tabName = dropTrailingBracketedCount(selectedTabName(mainTabs)); |
533 | if (!eqicOneOf(uiURL, "Main Tabs", tabName)) |
534 | uiURLs.showUIURL("Main Tabs"); |
535 | //uiURLs.showUIURL(tabName); |
536 | }); |
537 | |
538 | var cbEnabled = toolTip("Switch screen cam on or off", dm_checkBox enabled("")); |
539 | var lblScreenCam = setToolTip("Show scaled down and color-reduced screen image", |
540 | jlabel("Screen Cam")); |
541 | tabComponentClickFixer(lblScreenCam); |
542 | screenCamTab = hstackWithSpacing(cbEnabled, lblScreenCam); |
543 | addActionListener(cbEnabled, -> { if (enabled) selectTabComponent(mainTabs, screenCamTab); }); |
544 | |
545 | replaceTabTitleComponent(mainTabs, "Screen Cam", screenCamTab); |
546 | |
547 | // for tab titles |
548 | /*challengesPanel?.updateCount(); |
549 | labelCRUD?.update(); |
550 | galleryCRUD?.update(); |
551 | for (crud : ll(analyzersPanel(), scriptsPanel(), poisPanel())) { |
552 | crud.addCountToEnclosingTab(true); |
553 | crud.updateCount(); |
554 | }*/ |
555 | |
556 | persistSelectedTabAsLiveValue(mainTabs, dm_fieldLiveValue selectedTab()); |
557 | |
558 | urlBar = uiURLs.urlBar(); |
559 | focusOnFirstShow(urlBar); |
560 | setToolTip(uiURLs.comboBox, "UI navigation system"); |
561 | |
562 | scpMain = singleComponentPanel(); |
563 | uiURLs.scp(scpMain); |
564 | uiURLs.go(); |
565 | |
566 | var projectSelector = new JG22ProjectSelector(g22utils); |
567 | |
568 | generalInfoPanel.add(backgroundProcessesUI.shortLabel()); |
569 | |
570 | topStack.addComponent(verticalStrut(6)); |
571 | topStack.addComponent( |
572 | westCenterAndEast( |
573 | withLabelToTheRight(projectSelector.visualize(), "| "), |
574 | urlBar, |
575 | withLeftMargin(generalInfoPanel))); |
576 | |
577 | // MAIN LAYOUT |
578 | |
579 | var vis = northAndCenter( |
580 | withSideMargin(topStack), |
581 | scpMain |
582 | ); |
583 | |
584 | g22utils.autoStarter().start(); |
585 | |
586 | if (autoRunSelfTests) { |
587 | autoRunSelfTests = false; |
588 | onFirstShow(vis, l0 runSelfTests); |
589 | } |
590 | |
591 | ret vis; |
592 | } |
593 | |
594 | void runSelfTests { |
595 | thread "Self-Tests" { |
596 | selfTests = new G22SelfTests(g22utils); |
597 | selfTests.run(); |
598 | selfTestsDone(); |
599 | } |
600 | } |
601 | |
602 | event selfTestsDone; |
603 | |
604 | event projectErrorsChanged; |
605 | event projectErrorOccurred(PersistableThrowable error); |
606 | |
607 | JComponent screenCamPanel() { |
608 | ret centerAndSouthOrEast(horizontalLayout, |
609 | scpScreenCamImage, |
610 | watchScreenPane); |
611 | } |
612 | |
613 | JComponent screenCamPlusScriptPanel() enter { |
614 | print("screenCamPlusScriptPanel"); |
615 | //ret watchScreenPane; |
616 | try { |
617 | var ide = screenCamScriptIDE = leftArrowScriptIDE(); |
618 | ide.runButtonShouldBeEnabled = -> |
619 | eq(getText(ide.btnRun), "Stop") |
620 | || ide.runButtonShouldBeEnabled_base(); |
621 | |
622 | ide.runScript = -> { |
623 | if (eq(getText(ide.btnRun), "Stop")) |
624 | runningScreenCamScript = null; |
625 | else { |
626 | runningScreenCamScript = screenCamScriptIDE.parsedScript(); |
627 | ide.showStatus("Running"); |
628 | } |
629 | setText(ide.btnRun, |
630 | runningScreenCamScript == null ? "Run" : "Stop"); |
631 | }; |
632 | |
633 | ret centerAndSouthOrEast(horizontalLayout, |
634 | //withTools( |
635 | jhsplit( |
636 | jscroll_centered_borderless(isPosterized), |
637 | screenCamScriptIDE |
638 | .lvScript(dm_fieldLiveValue screenCamScript()) |
639 | .visualize()) |
640 | //, isPosterized) |
641 | , watchScreenPane); |
642 | } on fail e { print(e); } |
643 | } |
644 | |
645 | S speedInfo() { |
646 | ret "FPS " + fps + " idle " + remainingMS + " ms"; |
647 | } |
648 | |
649 | S speedInfo_long() { |
650 | ret "Screen cam running at " + nFrames(fps) + "/second. " + n2(remainingMS) + " ms remaining per frame in first core" |
651 | + " (of targeted " + fpsTarget + " FPS)"; |
652 | } |
653 | |
654 | bool useErrorHandling() { false; } |
655 | |
656 | S renderFunctionTimings() { |
657 | ret lines(ciSorted(map(functionTimings!, (f, avg) -> |
658 | firstToUpper(f) + ": " + n2(iround(nsToMicroseconds(avg!))) + " " + microSymbol() + "s (" + n2(iround(avg.n())) + ")"))); |
659 | } |
660 | |
661 | transient long _runScript_idx; |
662 | |
663 | void _runScript() { |
664 | scriptRunner.parseAndRunOn(imageToRegions_finished.ii); |
665 | } |
666 | |
667 | bool shouldRunScript() { |
668 | ret isShowing(scriptRunner.scpScriptResult); |
669 | } |
670 | |
671 | JComponent testScreenPanel() { |
672 | ret withSideAndTopMargin(testScreen.visualize()); |
673 | } |
674 | |
675 | JComponent timingsPanel() { |
676 | JTextArea taTimings = jTextArea_noUndo(); |
677 | awtEveryAndNow(taTimings, .5, r { |
678 | setText(taTimings, renderFunctionTimings()) |
679 | }); |
680 | ret withRightAlignedButtons(taTimings, |
681 | Reset := r resetTimings); |
682 | } |
683 | |
684 | L popDownItems() { |
685 | ret ll(jCheckBoxMenuItem_dyn("Horizontal Layout", |
686 | -> horizontalLayout, |
687 | b -> setField(horizontalLayout := b))); |
688 | } |
689 | |
690 | void unvisualize {} // don't zero transient component fields |
691 | |
692 | void resetTimings { functionTimings.reset(); } |
693 | |
694 | // add tool side bar to image surface |
695 | JComponent withTools( |
696 | JComponent component default jscroll_centered_borderless(is), |
697 | ImageSurface is) { |
698 | ret centerAndEastWithMargin(component, |
699 | vstack( |
700 | verticalStrut(5), |
701 | jimageButtonScaledToWidth(16, #1103054, "Save screenshot in gallery", rThread saveScreenshotToGallery), |
702 | /*jPopDownButton_noText( |
703 | jCheckBoxMenuItem_dyn("Live scripting", -> liveScripting, b -> setLiveScripting(b) |
704 | ),*/ |
705 | ) |
706 | ); |
707 | } |
708 | |
709 | class WatchTargetSelector is Swingable { |
710 | JComboBox<G22WatchTarget> cb = jComboBox(); |
711 | int screenCount, camCount; |
712 | |
713 | cachedVisualize { |
714 | updateList(); |
715 | selectItem(cb, watchTarget); |
716 | |
717 | main onChangeAndNow(cb, watchTarget -> { |
718 | setField(+watchTarget); |
719 | toolTip(cb, watchTarget?.toolTip()); |
720 | }); |
721 | |
722 | ret cb; |
723 | } |
724 | |
725 | void updateScreenCount() { |
726 | if (screenCount != screenCount()) |
727 | updateList(); |
728 | } |
729 | |
730 | void updateList() swing { |
731 | setComboBoxItems(cb, makeWatchTargets()); |
732 | } |
733 | |
734 | L<G22WatchTarget> makeWatchTargets() { |
735 | ret flattenToList( |
736 | countIteratorAsList_incl(1, screenCount = screenCount(), |
737 | i -> WatchScreen(i)), |
738 | new WatchMouse, |
739 | new WatchScreenWithMouse, |
740 | new WatchOtherScreen, |
741 | ); |
742 | } |
743 | } |
744 | |
745 | JComponent wrapCRUD(S title, SimpleCRUD_v2 crud, JComponent vis default crud.visualize()) { |
746 | ret crud == null ?: withTopAndBottomMargin(jCenteredRaisedSection(title, withMargin(vis))); |
747 | } |
748 | |
749 | File galleryDir() { |
750 | ret picturesDir(gazelle22_imagesSubDirName()); |
751 | } |
752 | |
753 | void saveScreenshotToGallery enter { |
754 | var img = imageStream!; |
755 | addToGallery(saveImageWithCounter(galleryDir(), "Screenshot", img)); |
756 | } |
757 | |
758 | GalleryImage addToGallery(S name default "Unnamed Image", BufferedImage image) { |
759 | ret addToGallery(saveImageWithCounter(dbDir(), name, image)); |
760 | } |
761 | |
762 | void saveWebCamImageToGallery enter { |
763 | var img = webCamPanel.getImage(); |
764 | addToGallery(saveImageWithCounter(galleryDir(), "Webcam", img)); |
765 | } |
766 | |
767 | GalleryImage addToGallery(File imgFile) { |
768 | if (!isImageFile(imgFile)) null; |
769 | var img = uniq(concepts, GalleryImage, path := imgFile); |
770 | printVars("addToGallery", +imgFile, +img); |
771 | ret img; |
772 | } |
773 | |
774 | class StudyPanel { |
775 | new G22SnPSelector snpSelector; |
776 | GalleryImage image; |
777 | BufferedImage originalImage; |
778 | //ImageSurface isOriginal = stdImageSurface(); |
779 | ImageSurface isOriginalWithRegions = stdImageSurface(); |
780 | ImageSurface isPosterized = stdImageSurface(); |
781 | SingleComponentPanel scp = singleComponentPanel(); |
782 | SingleComponentPanel analysisPanel = singleComponentPanel(); |
783 | SingleComponentPanel scpExampleCRUD = singleComponentPanel(); |
784 | ConceptsComboBox<GalleryImage> cbImage = g22utils.galleryImagesComboBox(); |
785 | Gazelle22_ImageToRegions itr; |
786 | int iSelectedRegion; |
787 | SimpleCRUD_v2<SavedRegion> regionCRUD; |
788 | SimpleCRUD_v2<Example> exampleCRUD; |
789 | |
790 | *() { |
791 | print("Making StudyPanel " + this); |
792 | //cbImage.sortTheList = l -> sortConceptsByIDDesc(l); |
793 | cbImage.sortTheList = l -> sortedByComparator(l, (a, b) |
794 | -> cmpAlphanumIC(fileName(a.path), fileName(b.path))); |
795 | |
796 | main onChangeAndNow(cbImage, img -> { |
797 | /*print("Image selected 1: " + img); |
798 | print("Me: " + me() + ", q thread: " + me().q().hasThread() |
799 | + ", q jobs done: " + me().q().nJobsDone()); |
800 | print("Module queue current job: " + me().q().currentJob());*/ |
801 | dm_q(me(), r { |
802 | print("Image selected: " + img); |
803 | image = img; |
804 | scp.setComponent(studyImagePanel()); |
805 | }); |
806 | }); |
807 | |
808 | isPosterized.removeAllTools(); |
809 | isPosterized.onMousePositionChanged(r_dm_q(me(), l0 regionUpdate)); |
810 | |
811 | imageSurfaceOnLeftMouseDown(isPosterized, pt -> dm_q(me(), r { chooseRegionAt(pt) })); |
812 | |
813 | snpSelector.onChange(r_dm_q(me(), l0 runSnP)); |
814 | } |
815 | |
816 | void chooseRegionAt(Pt p) { |
817 | if (itr == null) ret; |
818 | iSelectedRegion = itr.regions.regionAt(p); |
819 | |
820 | if (iSelectedRegion > 0) { |
821 | var savedRegion = uniq_returnIfNew(concepts, SavedRegion, |
822 | +image, |
823 | snpSettings := snpSelector.settings.cloneMe(), |
824 | regionIndex := iSelectedRegion); |
825 | |
826 | // it's new, add values |
827 | if (savedRegion != null) { |
828 | print("Saved new region!"); |
829 | var bitMatrix = toScanlineBitMatrix(itr.regions.regionBitMatrix(iSelectedRegion)); |
830 | cset(savedRegion, +bitMatrix); |
831 | } |
832 | } |
833 | |
834 | regionUpdate(); |
835 | } |
836 | |
837 | // load new image |
838 | JComponent studyImagePanel() { |
839 | if (image == null) null; |
840 | originalImage = loadImage2(image.path); |
841 | if (originalImage == null) ret jcenteredlabel("Image not found"); |
842 | |
843 | //isOriginal.setImage(originalImage); |
844 | isOriginalWithRegions.setImage(originalImage); |
845 | |
846 | iSelectedRegion = 0; |
847 | itr = new Gazelle22_ImageToRegions(functionTimings, originalImage, snpSelector.settings); |
848 | runSnP(); |
849 | |
850 | regionCRUD = new SimpleCRUD_v2<SavedRegion>(concepts, SavedRegion); |
851 | regionCRUD.addFilter(+image); |
852 | regionCRUD |
853 | .showSearchBar(false) |
854 | .showAddButton(false) |
855 | .showEditButton(false) |
856 | .iconButtons(true); |
857 | |
858 | regionCRUD.itemToMap_inner2 = region -> { |
859 | var examples = conceptsWhere(concepts, Example, item := region); |
860 | |
861 | ret litorderedmap( |
862 | "Pixels" := region.bitMatrix == null ? "-" : n2(region.bitMatrix.pixelCount()), |
863 | //"Shape" := "TODO", |
864 | "Labels" := joinWithComma(map(examples, e -> e.label)), |
865 | |
866 | // TODO: scale using snpsettings |
867 | "Position" := region.bitMatrix == null ? "-" : region.bitMatrix.boundingBoxOfTrueBits()); |
868 | }; |
869 | |
870 | var regionCRUDComponent = regionCRUD.visualize(); |
871 | regionCRUD.onSelectionChanged(l0 updateExampleCRUD); |
872 | |
873 | ret hsplit( |
874 | jtabs( |
875 | //"Image" := jscroll_centered_borderless(isOriginal), |
876 | "Image + regions" := jscroll_centered_borderless(isOriginalWithRegions), |
877 | "Posterized" := jscroll_centered_borderless(isPosterized), |
878 | ), |
879 | northAndCenterWithMargin( |
880 | analysisPanel, |
881 | hsplit( |
882 | jCenteredSection("Saved regions", regionCRUDComponent), |
883 | scpExampleCRUD) |
884 | )); |
885 | } |
886 | |
887 | void runSnP { |
888 | if (itr == null) ret; |
889 | itr.run(); |
890 | regionUpdate(); |
891 | } |
892 | |
893 | void regionUpdate { |
894 | if (itr == null) ret; |
895 | |
896 | var pixels = itr.posterized.getRGBPixels(); |
897 | |
898 | // hovering region marked green |
899 | g22_highlightRegion(pixels, isPosterized, itr, showRegionsAsOutline); |
900 | |
901 | // selected region marked blue |
902 | itr.regions.markRegionInPixelArray(pixels, iSelectedRegion, 0xFFADD8E6); |
903 | |
904 | var highlighted = bufferedImage(pixels, itr.posterized.getWidth(), itr.posterized.getHeight()); |
905 | |
906 | isPosterized.setImage(highlighted); |
907 | isPosterized.performAutoZoom(); // seems to be necessary for some reason |
908 | |
909 | updateAnalysis(); |
910 | } |
911 | |
912 | void updateAnalysis { |
913 | /*new LS lines; |
914 | lines.add(nRegions(itr.regions.regionCount())); |
915 | lines.add("Selected region: " + iSelectedRegion); |
916 | S text = lines_rtrim(lines); |
917 | analysisPanel.setComponent(jLabel(text)));*/ |
918 | } |
919 | |
920 | void updateExampleCRUD { |
921 | var region = regionCRUD.selected(); |
922 | if (region == null) ret with scpExampleCRUD.clear(); |
923 | |
924 | exampleCRUD = new SimpleCRUD_v2<Example>(concepts, Example); |
925 | exampleCRUD.entityName = -> "label for region"; |
926 | exampleCRUD.addFilter(item := region); |
927 | exampleCRUD.showSearchBar(false); |
928 | exampleCRUD.iconButtons(true); |
929 | scpExampleCRUD.set(jCenteredSection("Labels for region", |
930 | exampleCRUD.visualize())); |
931 | } |
932 | |
933 | void importImage { |
934 | new JFileChooser fc; |
935 | if (fc.showOpenDialog(cbImage) == JFileChooser.APPROVE_OPTION) { |
936 | File file = fc.getSelectedFile().getAbsoluteFile(); |
937 | if (!isImageFile(file)) ret with infoMessage("Not an image file"); |
938 | var img = addToGallery(file); |
939 | waitUntil(250, 5.0, -> comboBoxContainsItem(cbImage, img)); |
940 | setSelectedItem(cbImage, img); |
941 | } |
942 | } |
943 | |
944 | visual |
945 | jRaisedSection(northAndCenterWithMargins( |
946 | centerAndEast(withLabel("Study", cbImage), |
947 | hstack( |
948 | jlabel(" in "), |
949 | snpSelector.visualize(), |
950 | horizontalStrut(10), |
951 | jPopDownButton_noText( |
952 | "Import image...", rThreadEnter importImage, |
953 | ), |
954 | )), |
955 | scp)); |
956 | } // end of StudyPanel |
957 | |
958 | void initUIURLs { |
959 | uiURLs.put("Main Tabs", -> |
960 | horizontalLayout ? withMargin(mainTabs) : withSideMargin(mainTabs)); |
961 | |
962 | uiURLs.put("Screen Cam FPS", -> jFullCenter( |
963 | vstackWithSpacing( |
964 | jCenteredLabel("FPS target (frames per second) for screen cam:"), |
965 | jFullCenter(dm_spinner fpsTarget(1, 60)), |
966 | jCenteredLabel("(You can lower this value if you have a slower computer)")))); |
967 | |
968 | uiURLs.put("Timings", -> timingsPanel()); |
969 | |
970 | uiURLs.put("Test Screen" := -> testScreenPanel()); |
971 | |
972 | //uiURLs.put("Operators" := -> operatorsPanel()); |
973 | |
974 | uiURLs.put("Settings" := -> settingsPanel()); |
975 | |
976 | uiURLs.put("System Info" := -> systemInfoPanel()); |
977 | |
978 | uiURLs.put("Web Cam" := -> webCamPanel()); |
979 | |
980 | uiURLs.put("Labels" := -> wrapCRUD("Labels", labelCRUD)); |
981 | |
982 | uiURLs.put(WithToolTip("Screen Cam + Linear Script", "Run a simple (linear) Gazelle V script") |
983 | := -> withBottomMargin(scriptRunner.scriptAndResultPanel())); |
984 | |
985 | uiURLs.put(WithToolTip("Scratchpad", "Write and run a \"left-arrow script\"") |
986 | := -> withBottomMargin(jOnDemand scratchpad/*leftArrowScriptPanel*/())); |
987 | |
988 | uiURLs.put("Screen Cam + Script" := -> jOnDemand screenCamPlusScriptPanel()); |
989 | |
990 | uiURLs.put(WithToolTip("Gallery CRUD", "Gallery view with more functions (delete etc)") |
991 | := -> wrapCRUD("Images", galleryCRUD, galleryCRUDVis)); |
992 | |
993 | uiURLs.put(WithToolTip("Paint", "Paint a picture for Gazelle with your mouse!") |
994 | := -> withBottomMargin(jOnDemand paintPanel())); |
995 | |
996 | uiURLs.put(WithToolTip("Video", "A little video player (Note: no sound and doesn't handle some videos)") |
997 | := -> withBottomMargin(videoPanel())); |
998 | |
999 | uiURLs.put(WithToolTip("Analyzers", "Manage image analyzers here") |
1000 | := -> withBottomMargin(analyzersPanel().visualize())); |
1001 | |
1002 | uiURLs.put(WithToolTip("Scripts", "Manage all left-arrow scripts here") |
1003 | := -> withBottomMargin(scriptsPanel().visualize())); |
1004 | |
1005 | uiURLs.put(WithToolTip("Shape Collector", "Looks at your screen live") |
1006 | := -> withBottomMargin(shapeCollectorPanel().visualize())); |
1007 | |
1008 | uiURLs.put(WithToolTip("Points of interest", "Points in random images you have clicked on") |
1009 | := -> withBottomMargin(poisPanel().visualize())); |
1010 | |
1011 | uiURLs.put(WithToolTip("Networks", "Manage recognition networks") |
1012 | := -> withBottomMargin(networksPanel().visualize())); |
1013 | |
1014 | uiURLs.put("Screen Cam" := -> jOnDemand screenCamPanel()) |
1015 | |
1016 | .put(WithToolTip("Study", "Here you can analyze gallery images") |
1017 | := -> withTopAndBottomMargin(studyPanel().visualize())) |
1018 | |
1019 | .put(WithToolTip("Java", "Write & run actual Java code") |
1020 | := -> withBottomMargin(jOnDemand javaPanel())) |
1021 | |
1022 | .put(WithToolTip("Gallery", "Gallery view with preview images") |
1023 | := -> galleryPanel().visualize()) |
1024 | |
1025 | .put(WithToolTip("Challenges", "Gazelle's self-tests") |
1026 | := -> challengesPanel()) |
1027 | |
1028 | .put(WithToolTip("Projects", "Manage/load Gazelle projects") |
1029 | := -> databasesPanel().visualize()) |
1030 | |
1031 | .put(WithToolTip("Entities", "Define entities (meta-level)") |
1032 | := -> entitiesPanel()) |
1033 | |
1034 | .put("Local Fonts" := -> localFontsPanel().visualize()) |
1035 | |
1036 | .put("Points of interest" := -> new G22POIsPanel().g22utils(g22utils).visualize()) |
1037 | |
1038 | .put("Scripts from all projects" := -> new G22ScriptsFromAllDBsPanel(g22utils).visualize()) |
1039 | |
1040 | .put("Networks from all projects" := -> new G22NetworksFromAllDBsPanel(g22utils).visualize()) |
1041 | |
1042 | .put("Files in project" := -> new G22DBFileBrowser(g22utils).visualize()) |
1043 | |
1044 | //.put("HTML Editor Test" := -> new G22HtmlEditor().visualize()) |
1045 | |
1046 | .put("Project Overview" := -> new G22ProjectOverviewPanel(g22utils).visualize()) |
1047 | |
1048 | .put("Showcase" := -> withTopMargin(new G22ShowCasePanel(g22utils).visualize())) |
1049 | |
1050 | .put("Story" := -> new G22ProjectStoryEditor(g22utils).visualize()) |
1051 | |
1052 | .put("All objects by ID" := -> new G22AllConceptsPanel(g22utils).visualize()) |
1053 | |
1054 | .put("Variables" := -> makeVariablesPanel().visualize()) |
1055 | |
1056 | .put("Connectivity" := -> new G22ConnectivityPanel().g22utils(g22utils).visualize()) |
1057 | |
1058 | .put("Travel Log" := -> new G22TravelLogPanel(g22utils).visualize()) |
1059 | |
1060 | .put("Screen parts" := -> screenPartsPanel().g22utils(g22utils).visualize()) |
1061 | |
1062 | .put("Masks" := -> masksPanel().g22utils(g22utils).visualize()) |
1063 | |
1064 | // TODO: .put("Log" := -> log view) |
1065 | |
1066 | // add ui urls above this line |
1067 | ; |
1068 | } |
1069 | |
1070 | transient simplyCached G22LocalFontsPanel localFontsPanel() { ret new G22LocalFontsPanel(g22utils); } |
1071 | |
1072 | JComponent settingsPanel() { |
1073 | var cbMinimizeToTray = jCheckBox(isTrue(getOpt(dm_stem(), "minimizeToTray"))); |
1074 | onUpdate(cbMinimizeToTray, -> dm_callStem(me(), "setMinimizeToTray", isChecked(cbMinimizeToTray))); |
1075 | ret jscroll_vertical(makeForm3( |
1076 | "Minimize to tray", toolTip("Remove Gazelle from task bar when minimized (click Gazelle icon in system tray to reactivate)", cbMinimizeToTray), |
1077 | "Access web cams", dm_checkBox webCamAccessEnabled(), |
1078 | )); |
1079 | } |
1080 | |
1081 | JComponent operatorsPanel() { |
1082 | ret jcenteredlabel("TODO"); |
1083 | } |
1084 | |
1085 | JLeftArrowScriptIDE leftArrowScriptIDE() { |
1086 | ret g22utils.leftArrowIDE(); |
1087 | } |
1088 | |
1089 | void makePrototypeParser() { |
1090 | var parser = prototypeParser = new GazelleV_LeftArrowScriptParser; |
1091 | // global function containers for all scripts! |
1092 | parser.allowTheWorld(me(), new G22MaskUtils(g22utils), g22utils, mc(), utils.class); |
1093 | parser.isBlockedFunctionContainerMethod = |
1094 | (fc, name) -> fc == this && eqOneOf(name, "onChange", "onChangeAndNow", "removeChangeListener"); |
1095 | |
1096 | //parser.importedClasses = -> listPlus(parser.importedClasses_base(), |
1097 | //"loadableUtils.utils$Timestamp"); |
1098 | |
1099 | var classNames = parser.globalClassNames(); |
1100 | classNames.put("Timestamp", "loadableUtils.utils$Timestamp"); |
1101 | } |
1102 | |
1103 | void adaptLeftArrowParser(GazelleV_LeftArrowScriptParser parser) { |
1104 | parser.copyFunctionContainersFrom(prototypeParser); |
1105 | } |
1106 | |
1107 | JComponent scratchpad() { |
1108 | var scratchpad = uniq(concepts(), G22LAScratchpad); |
1109 | if (nempty(newScript)) { |
1110 | scratchpad.text(newScript); |
1111 | newScript(null); |
1112 | } |
1113 | ret scratchpad.visualize(); |
1114 | } |
1115 | |
1116 | /*JComponent leftArrowScriptPanel() { |
1117 | var ide = leftArrowScriptIDE(); |
1118 | |
1119 | var btnSave = jImageButton(#1103084, "Save script", rThreadEnter saveAsNewScript); |
1120 | |
1121 | // place to the right of hideable stuff |
1122 | int idx = 0; |
1123 | while (getComponentAtIndex(ide.buttons(), idx) instanceof SingleComponentPanel) idx++; |
1124 | addComponentAtIndex(ide.buttons(), idx, btnSave); |
1125 | |
1126 | ide.sectionTitle("Left Arrow Script Scratchpad"); |
1127 | ide.lvScript(dm_fieldLiveValue newScript()); |
1128 | ret withTopMargin(ide.visualize()); |
1129 | }*/ |
1130 | |
1131 | public void saveAsNewScript(S text /*default newScript*/) { |
1132 | inputText("Name for this script", description -> { |
1133 | temp enter(); |
1134 | |
1135 | // Note: This only works like this, i.e. when showUIURL is called |
1136 | // first. |
1137 | |
1138 | showUIURL("Scripts"); |
1139 | var script = cnewUnlisted(G22LeftArrowScript, +description, +text); |
1140 | scriptsPanel().selectAfterUpdate(script); |
1141 | concepts.register(script); |
1142 | }); |
1143 | } |
1144 | |
1145 | JComponent javaPanel() enter { |
1146 | var scpResult = singleComponentPanel(); |
1147 | |
1148 | new JMiniJavaIDE ide; |
1149 | ide.stringifier(g22utils.stringifier); |
1150 | ide.extraClassMembers = script -> { |
1151 | LS tok = javaTok(script); |
1152 | |
1153 | if (contains(tok, "draw")) ret [[ |
1154 | import java.awt.*; |
1155 | import java.awt.image.*; |
1156 | |
1157 | interface SimpleRenderable { |
1158 | void renderOn(Graphics2D g); |
1159 | } |
1160 | |
1161 | static BufferedImage draw(int w, int h, SimpleRenderable r) { |
1162 | BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); |
1163 | Graphics2D g = img.createGraphics(); |
1164 | g.setColor(Color.white); |
1165 | g.fillRect(0, 0, w, h); |
1166 | g.setColor(Color.black); |
1167 | r.renderOn(g); |
1168 | return img; |
1169 | } |
1170 | ]]; |
1171 | |
1172 | ret ""; |
1173 | }; |
1174 | |
1175 | ide.callCompiledObject = o -> { |
1176 | O result = ide.callCompiledObject_base(o); |
1177 | if (result cast BufferedImage) |
1178 | scpResult.set(jscroll_centered_borderless(stdImageSurface(result))); |
1179 | ret result; |
1180 | }; |
1181 | |
1182 | ide.lvScript(dm_fieldLiveValue javaCode()); |
1183 | ret jhsplit( |
1184 | jCenteredSection("Image will show here", scpResult), |
1185 | ide.visualize()); |
1186 | } |
1187 | |
1188 | JComponent webCamPanel() { |
1189 | if (cbWebCam == null) { |
1190 | var cams = listWebCams(); |
1191 | cbWebCam = jTypedComboBox(cams, findWebCamByName(cams, webCamName)); |
1192 | } |
1193 | |
1194 | if (scpWebCamImage == null) scpWebCamImage = singleComponentPanel(); |
1195 | |
1196 | ret northAndCenterWithMargins( |
1197 | centerAndEastWithMargin( |
1198 | withLabel("Cam", cbWebCam), |
1199 | jline( |
1200 | jbutton("Start", rThreadEnter startWebCam), |
1201 | jbutton("Stop", rThreadEnter stopWebCam) |
1202 | )), |
1203 | scpWebCamImage); |
1204 | } |
1205 | |
1206 | void stopWebCam { |
1207 | if (webCamPanel != null) { |
1208 | webCamPanel.stop(); |
1209 | webCamPanel = null; |
1210 | scpWebCamImage?.clear(); |
1211 | backgroundProcessesUI.remove(bgWebCam); |
1212 | } |
1213 | } |
1214 | |
1215 | void startWebCam { |
1216 | temp tempInfoBox("Starting Web Cam"); |
1217 | stopWebCam(); |
1218 | var cam = getSelectedItem_typed(cbWebCam); |
1219 | setField(webCamName := cam?.getName()); |
1220 | if (cam != null) { |
1221 | scpWebCamImage.set( |
1222 | northAndCenterWithMargin( |
1223 | rightAlignedLine( |
1224 | jimageButtonScaledToWidth(16, #1103054, "Save web cam image in gallery", rThread saveWebCamImageToGallery) |
1225 | ), |
1226 | webCamPanel = new WebcamPanel(cam, true) |
1227 | )); |
1228 | backgroundProcessesUI.add(bgWebCam); |
1229 | } |
1230 | } |
1231 | |
1232 | void forgetMissingImages { |
1233 | int n = l(deleteConcepts(concepts, GalleryImage, img -> !img.imageExists())); |
1234 | infoBox(n == 0 ? "Nothing to forget" : "Forgot " + nImages(n)); |
1235 | } |
1236 | |
1237 | bool hasUIURL(S url) { |
1238 | ret uiURLs.hasURL(url); |
1239 | } |
1240 | |
1241 | void addUIURLToMainTabs(S url) swing { |
1242 | if (containsTabNameWithoutTrailingCount(mainTabs, url)) ret; |
1243 | if (!hasUIURL(url)) ret with print("URL not found: " + url); |
1244 | |
1245 | addTab(mainTabs, WithToolTip(uiURLs.toolTipForURL(url), url), |
1246 | uiURLs.renderUIURL(url)); |
1247 | } |
1248 | |
1249 | void showScreenCam() { showUIURL("Screen Cam"); } |
1250 | void showWebCam() { showUIURL("Web Cam"); } |
1251 | |
1252 | transient simplyCached G22NetworksPanel networksPanel() { |
1253 | ret uniq(concepts, G22NetworksPanel).g22utils(g22utils); |
1254 | } |
1255 | |
1256 | JComponent challengesPanel() { |
1257 | if (challengesPanel == null) |
1258 | challengesPanel = new G22ChallengesPanel().g22utils(g22utils); |
1259 | ret challengesPanel.visualize(); |
1260 | } |
1261 | |
1262 | transient simplyCached G22GalleryPanel galleryPanel() { |
1263 | ret new G22GalleryPanel().g22utils(g22utils); |
1264 | } |
1265 | |
1266 | JComponent entitiesPanel() { |
1267 | if (entityCRUD == null) |
1268 | entityCRUD = new SimpleCRUD_v2(concepts, Entity); |
1269 | ret wrapCRUD("Entities", entityCRUD); |
1270 | } |
1271 | |
1272 | // for scripts |
1273 | Gazelle22_ImageToRegions imageToRegions(BufferedImage inputImage, SnPSettings snpSettings,) { |
1274 | ret new Gazelle22_ImageToRegions(functionTimings, inputImage, snpSettings); |
1275 | } |
1276 | |
1277 | Gazelle22_ImageToRegions imageToRegionsWithDiagonals(BufferedImage inputImage, SnPSettings snpSettings) { |
1278 | ret imageToRegions(inputImage, snpSettings).withDiagonals(true); |
1279 | } |
1280 | |
1281 | G22DatabasesPanel databasesPanel() { |
1282 | ret new G22DatabasesPanel(g22utils); |
1283 | } |
1284 | |
1285 | transient simplyCached JComponent paintPanel() { |
1286 | if (paintToolGallery == null) { |
1287 | paintToolGallery = JGallery().horizontal(false); |
1288 | paintToolGallery.openImage = img -> paintTool.loadImageProtected(img); |
1289 | paintToolGallery.imageLoader().imageHeight(50); |
1290 | |
1291 | new AWTOnConceptChangesByClass(concepts, GalleryImage, paintToolGallery.visualize(), -> { |
1292 | var images = galleryImagesIn(conceptsDir(concepts)); |
1293 | print("Paint tool images: " + l(images)); |
1294 | paintToolGallery.setImageFiles(sortFilesAlphaNumIC(images)); |
1295 | }).install(); |
1296 | } |
1297 | |
1298 | if (paintTool == null) paintTool(new JPaintTool); |
1299 | ownResource(paintTool); |
1300 | main onChange(paintTool, me()); |
1301 | |
1302 | paintTool.createAutoPersistFile = |
1303 | -> makeFileNameUnique_beforeExtension_startWith1_noDot(conceptsDir(concepts, "Painting.png")); |
1304 | |
1305 | new JG22Labels labelsView; |
1306 | paintTool.bottomLeftControls = -> labelsView.visualize(); |
1307 | |
1308 | var paintToolVis = paintTool.visualize(); |
1309 | |
1310 | paintTool.imageSurface().defaultImageDir = -> g22utils.dbDir(); |
1311 | |
1312 | // migrating between directories - just make a new file |
1313 | if (!isDeepContainedInDir_canonical(paintTool.autoPersistFile(), conceptsDir(concepts))) |
1314 | paintTool.newImage(); |
1315 | |
1316 | paintTool.varAutoPersistFile().onChangeAndNow(imageFile -> { |
1317 | labelsView.setLabels(g22utils.labelsForFile(imageFile)); |
1318 | paintToolGallery.selectFile(imageFile); |
1319 | }); |
1320 | labelsView.addLabel = text -> { |
1321 | var imageFile = paintTool.autoPersistFile(); |
1322 | var labels = g22utils.labelsForFile(imageFile); |
1323 | labels.add(g22utils.getLabel(text)); |
1324 | print(+labels); |
1325 | g22utils.setLabelsForFile(imageFile, labels); |
1326 | labelsView.setLabels(labels); |
1327 | }; |
1328 | |
1329 | labelsView.removeLabel = label -> { |
1330 | var imageFile = paintTool.autoPersistFile(); |
1331 | var labels = g22utils.labelsForFile(imageFile); |
1332 | labels = listWithout(labels, label); |
1333 | g22utils.setLabelsForFile(imageFile, labels); |
1334 | labelsView.setLabels(labels); |
1335 | }; |
1336 | |
1337 | paintAnalysisPanel if null = new G22AnalysisPanel; |
1338 | paintAnalysisPanel.editAnalyzer = l1 editAnalyzer; |
1339 | paintAnalysisPanel.g22utils(g22utils).imageSurface(paintTool.imageSurface()); |
1340 | ownResource(paintAnalysisPanel); |
1341 | main onChange(paintAnalysisPanel, me()); |
1342 | |
1343 | paintTool.onImageChanged(img -> paintAnalysisPanel.setImage(img)); |
1344 | paintAnalysisPanel.setImage(paintTool.getImage()); |
1345 | |
1346 | var collapsiblePanel = CollapsibleLeftPanel(false, "Paintings", |
1347 | paintToolGallery.visualize(), paintToolVis); |
1348 | linkVars(varPaintToolGalleryExpanded(), collapsiblePanel.varExpanded()); |
1349 | paintToolGallery.varFiles().onChangeAndNow(files -> collapsiblePanel.sidePanelName(n2(files, "Painting"))); |
1350 | |
1351 | ret jvsplit(0.75, |
1352 | collapsiblePanel.visualize(), |
1353 | jRaisedCenteredSection("Image Analysis", paintAnalysisPanel.visualize())); |
1354 | } |
1355 | |
1356 | JComponent videoPanel() { |
1357 | if (videoLibDownloader == null) { |
1358 | videoLibDownloader = new JVideoLibDownloader(); |
1359 | videoLibDownloader.forward(-> videoPlayer().visualize()); |
1360 | } |
1361 | ret videoLibDownloader.visualize(); |
1362 | } |
1363 | |
1364 | JFFMPEGVideoPlayer videoPlayer() { |
1365 | if (videoPlayer == null) |
1366 | videoPlayer = new JFFMPEGVideoPlayer; |
1367 | ret videoPlayer; |
1368 | } |
1369 | |
1370 | transient simplyCached G22AnalyzersPanel analyzersPanel() { |
1371 | ret uniq(concepts, G22AnalyzersPanel).g22utils(g22utils); |
1372 | } |
1373 | |
1374 | transient simplyCached G22ScriptsPanel scriptsPanel() { |
1375 | ret uniq(concepts, G22ScriptsPanel).g22utils(g22utils); |
1376 | } |
1377 | |
1378 | transient simplyCached G22ScreenPartsPanel screenPartsPanel() { |
1379 | ret uniq(concepts, G22ScreenPartsPanel).g22utils(g22utils); |
1380 | } |
1381 | |
1382 | transient simplyCached G22MasksPanel masksPanel() { |
1383 | ret uniq(concepts, G22MasksPanel).g22utils(g22utils); |
1384 | } |
1385 | |
1386 | transient simplyCached G22POIsPanel poisPanel() { |
1387 | ret uniq(concepts, G22POIsPanel).g22utils(g22utils); |
1388 | } |
1389 | |
1390 | // Not cached for now, stores defaults in project variables |
1391 | G22ShapeCollectorPanel shapeCollectorPanel() { |
1392 | ret G22ShapeCollectorPanel.fullyConfigured(g22utils); |
1393 | } |
1394 | |
1395 | Cl<File> galleryImagesIn(File dir) { |
1396 | ret mapNonNulls(list(concepts, GalleryImage), |
1397 | i -> isDeepContainedInDir_absolute(i.path, dir) ? i.path : null); |
1398 | } |
1399 | |
1400 | void editAnalyzer(G22Analyzer analyzer) { |
1401 | if (analyzer == null) ret; |
1402 | analyzersPanel().edit(analyzer); |
1403 | showUIURL("Analyzers"); |
1404 | } |
1405 | |
1406 | public void editScript(G22LeftArrowScript script) { |
1407 | if (script == null) ret; |
1408 | showUIURL("Scripts"); |
1409 | scriptsPanel().edit(script); |
1410 | } |
1411 | |
1412 | public void editScreenPart(G22ScreenPart screenPart) { |
1413 | screenPartsPanel().edit(screenPart); |
1414 | showUIURL("Screen parts"); |
1415 | } |
1416 | |
1417 | O inlineScript(long scriptID, VarContext varContext) { |
1418 | var script = getConcept(concepts, G22LeftArrowScript, scriptID); |
1419 | if (script == null) fail("Script ID " + scriptID + " not found"); |
1420 | GazelleV_LeftArrowScript.Script parsedScript = script.compileSaved().parsedScript; |
1421 | ret parsedScript.get(varContext); |
1422 | } |
1423 | |
1424 | transient simplyCached StudyPanel studyPanel() { ret new StudyPanel; } |
1425 | |
1426 | SingleComponentPanel jOnDemand(IF0<JComponent> makeComponent) { |
1427 | ret main jOnDemand(-> { temp enter(); ret makeComponent?!; }); |
1428 | } |
1429 | |
1430 | // implementation of G22ProjectActions |
1431 | |
1432 | public void editScripts() { |
1433 | showUIURL("Scripts"); |
1434 | } |
1435 | |
1436 | public void editProjectStory() { |
1437 | showUIURL("Story"); |
1438 | } |
1439 | |
1440 | public void openObjectInProject(long id) { |
1441 | var c = getConcept(concepts, id); |
1442 | if (c == null) |
1443 | infoBox("Object ID not found in project: " + id); |
1444 | else |
1445 | openConcept(c); |
1446 | } |
1447 | |
1448 | public void openConcept(Concept c) { |
1449 | if (c cast G22Analyzer) { |
1450 | showUIURL("Analyzers"); |
1451 | analyzersPanel().setSelected(c); |
1452 | } else if (c cast G22LeftArrowScript) { |
1453 | editScript(c); |
1454 | } else if (c cast G22PointOfInterest) { |
1455 | showUIURL("Points of interest"); |
1456 | poisPanel().setSelected(c); |
1457 | } else if (c cast G22GalleryImage) { |
1458 | showInGallery(c); |
1459 | } else if (c cast G22Network) { |
1460 | showNetwork(c); |
1461 | } else |
1462 | infoBox("Don't know how to show " + c); |
1463 | } |
1464 | |
1465 | void showNetwork(G22Network network) { |
1466 | if (network == null) ret; |
1467 | showUIURL("Networks"); |
1468 | networksPanel().setSelected(network); |
1469 | } |
1470 | |
1471 | public void openUIURL(S url) { |
1472 | uiURLs.showUIURL(url); |
1473 | } |
1474 | |
1475 | public bool openPathInProject(S path) { |
1476 | path = trim(path); |
1477 | S path2; |
1478 | |
1479 | if ((path2 = dropPrefixOrNull("../", path)) != null) |
1480 | ret true with masterStuff().openDB(path2, false); |
1481 | |
1482 | if (isInteger(path)) |
1483 | ret true with openObjectInProject(parseLong(path)); |
1484 | |
1485 | if (hasUIURL(path)) |
1486 | ret true with openUIURL(path); |
1487 | |
1488 | File f = newFile(dbDir(), path); |
1489 | print(+f); |
1490 | if (isFile(f)) { |
1491 | if (isImageFile(f)) { |
1492 | showInGallery(addToGallery(f)); |
1493 | true; |
1494 | } else { |
1495 | infoBox("Unknown file type: " + fileName(f)); |
1496 | false; |
1497 | } |
1498 | } |
1499 | |
1500 | infoBox("Not a UI URL, object ID or project file: " + path); |
1501 | false; |
1502 | } |
1503 | |
1504 | void showInGallery(G22GalleryImage img) { |
1505 | if (img == null) ret; |
1506 | showUIURL("Gallery"); |
1507 | galleryPanel().selectImage(img); |
1508 | } |
1509 | |
1510 | G22GalleryImage galleryImageConcept(long id) { |
1511 | ret getConcept(concepts, G22GalleryImage, id); |
1512 | } |
1513 | |
1514 | BufferedImage getGalleryImage(long id) { |
1515 | var img = galleryImageConcept(id); |
1516 | if (img == null) fail("Image not found: " + id); |
1517 | ret img.load(); |
1518 | } |
1519 | |
1520 | void cleanMeUp_g22utils { |
1521 | g22utils.close(); |
1522 | } |
1523 | |
1524 | public void waitUntilStarted aka waitForAutoStart() { |
1525 | g22utils.autoStarter().waitUntilDone(); |
1526 | } |
1527 | |
1528 | S functionsIncludeID() { ret #1034034; } |
1529 | |
1530 | void infoBoxAndCompile(S msg) { |
1531 | //topLeftInfoBox(msg); |
1532 | infoBox(msg); |
1533 | if (cic(msg, "edited")) |
1534 | dm_callOS("compile"); |
1535 | } |
1536 | |
1537 | bool devMode() { ret g22_devMode(); } |
1538 | |
1539 | G22WatchTarget defaultWatchTarget() { |
1540 | ret screenCount() > 1 ? new WatchOtherScreen : new WatchScreen(1); |
1541 | } |
1542 | |
1543 | G22MasterStuff masterStuff() { ret g22utils.masterStuff(); } |
1544 | |
1545 | void addProjectLibs(Cl<S> libs) { if (addAll(projectLibs, libs)) change(); } |
1546 | void removeProjectLibs(Cl<S> libs) { if (removeAll(projectLibs, libs)) change(); } |
1547 | |
1548 | void addUIURL(S url, IF0<? extends JComponent> maker) { |
1549 | uiURLs.put(url, maker); |
1550 | } |
1551 | |
1552 | L<IImageRegion<BWImage>> quickRegions(BufferedImage image, int colors) { |
1553 | ret imageToRegions(image, new SnPSettings(image, colors))!!; |
1554 | } |
1555 | |
1556 | L<IImageRegion<BWImage>> quickRegionsWithDiagonals(BufferedImage image, int colors) { |
1557 | ret imageToRegionsWithDiagonals(image, new SnPSettings(image, colors))!!; |
1558 | } |
1559 | |
1560 | WebcamListener webcamImageObtainedListener(IVF1<WebcamEvent> r) { |
1561 | ret new WebcamListener { |
1562 | public void webcamOpen(WebcamEvent we) {} |
1563 | public void webcamClosed(WebcamEvent we) {} |
1564 | |
1565 | public void webcamDisposed(WebcamEvent we) {} |
1566 | |
1567 | public void webcamImageObtained(WebcamEvent we) { |
1568 | r?.get(we); |
1569 | } |
1570 | }; |
1571 | } |
1572 | |
1573 | void restartGazelle { masterStuff().restart(); } |
1574 | |
1575 | void closeProject { |
1576 | masterStuff().closeDatabase(g22utils.projectDir()); |
1577 | } |
1578 | |
1579 | <A extends Throwable> A addProjectError(A e) { |
1580 | if (e == null) null; |
1581 | printStackTrace(e); |
1582 | var persistable = toPersistableThrowable(e); |
1583 | addToListWithMaxSize(projectErrors, persistable, maxProjectErrors); |
1584 | change(); |
1585 | projectErrorOccurred(persistable); |
1586 | projectErrorsChanged(); |
1587 | ret e; |
1588 | } |
1589 | |
1590 | void clearProjectErrors { |
1591 | if (syncClear_trueIfChanged(projectErrors)) { |
1592 | change(); |
1593 | projectErrorsChanged(); |
1594 | } |
1595 | } |
1596 | |
1597 | JComponent systemInfoPanel() { |
1598 | ret new G22SystemInfoPanel(g22utils).visualize(); |
1599 | } |
1600 | |
1601 | public void goToSource(TokenRangeWithSrc src) { |
1602 | if (src == null) ret; |
1603 | var script = src.sourceInfo(); |
1604 | if (script cast G22LeftArrowScript) { |
1605 | if (script._concepts() != concepts()) { |
1606 | // forward to other project |
1607 | main g22utils(script._concepts).projectActions().goToSource(src); |
1608 | } else { |
1609 | showUIURL("Scripts"); |
1610 | scriptsPanel().edit(script, src.startLineAndCol()); |
1611 | } |
1612 | } |
1613 | } |
1614 | |
1615 | TokenRangeWithSrc findDefinition(S id) { |
1616 | var fd = g22utils.projectWideFunctionDefs.get(id); |
1617 | if (fd != null) |
1618 | ret fd.tokenRangeWithSrc(); |
1619 | |
1620 | Class c = g22utils.projectWideClassDefs.get(id); |
1621 | if (c != null) |
1622 | ret (TokenRangeWithSrc) getOpt(c, "__srcRef"); |
1623 | |
1624 | null; |
1625 | } |
1626 | } // end of module |
1627 | |
1628 | concept SavedRegion { |
1629 | new Ref image; // e.g. a GalleryImage |
1630 | SnPSettings snpSettings; |
1631 | int regionIndex; // region number relative to snpSettings |
1632 | //Rect bounds; // get it from bitMatrix instead |
1633 | ScanlineBitMatrix bitMatrix; |
1634 | //new RefL<Label> labels; |
1635 | } |
1636 | |
1637 | concept Example { |
1638 | new Ref<Label> label; |
1639 | new Ref item; // e.g. a SavedRegion |
1640 | double confidence = 1; |
1641 | } |
1642 | |
1643 | concept IfThenTheory { |
1644 | new Ref if_; |
1645 | new Ref then; |
1646 | } |
1647 | |
1648 | !include once #1034593 // Entity etc. |
Began life as a copy of #1033683
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj, wnsclhtenguj
No comments. add comment
Snippet ID: | #1033862 |
Snippet name: | GazelleScreenCam [implementation of G22ProjectActions, Gazelle 22 main module] |
Eternal ID of this version: | #1033862/1113 |
Text MD5: | 3b313a27c6e91b213243709959681b3f |
Author: | stefan |
Category: | javax / gazelle v |
Type: | JavaX source code (Dynamic Module) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2023-01-07 21:21:03 |
Source code size: | 54431 bytes / 1648 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 702 / 6356 |
Version history: | 1112 change(s) |
Referenced in: | [show references] |