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