How to make Compose render my custom Shape? - kotlin

I have this Composable that draws some text with a custom Shape behind it:
#Composable
fun TextWithIcon(text: String, icon: Shape) {
Box(Modifier.size(48.dp)
.border(1.dp, MaterialTheme.colors.secondaryVariant)
.background(MaterialTheme.colors.background)
.padding(4.dp)
.border(2.dp, MaterialTheme.colors.secondaryVariant, icon)
.padding(4.dp), contentAlignment = Alignment.Center) {
Text(text, color = MaterialTheme.colors.onBackground)
}
}
Whenever I call it, Compose throws an Exception internally that doesn't even mention my code:
Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: Failed to Image::makeFromBitmap Bitmap(_ptr=0x249bafa64c0)
at org.jetbrains.skia.Image$Companion.makeFromBitmap(Image.kt:115)
at androidx.compose.ui.graphics.SkiaBackedCanvas.drawImageRect-cI72Soc(SkiaBackedCanvas.skiko.kt:210)
at androidx.compose.ui.graphics.SkiaBackedCanvas.drawImageRect-HPBpro0(SkiaBackedCanvas.skiko.kt:185)
at androidx.compose.ui.graphics.drawscope.CanvasDrawScope.drawImage-AZ2fEMs(CanvasDrawScope.kt:263)
at androidx.compose.ui.node.LayoutNodeDrawScope.drawImage-AZ2fEMs(LayoutNodeDrawScope.kt)
at androidx.compose.ui.graphics.drawscope.DrawScope.drawImage-AZ2fEMs$default(DrawScope.kt:510)
at androidx.compose.foundation.BorderKt$drawGenericBorder$3.invoke(Border.kt:318)
at androidx.compose.foundation.BorderKt$drawGenericBorder$3.invoke(Border.kt:315)
at androidx.compose.ui.draw.DrawContentCacheModifier.draw(DrawModifier.kt:218)
at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:320)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:310)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:839)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:90)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:318)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:310)
at androidx.compose.ui.node.ModifiedLayoutNode.performDraw(ModifiedLayoutNode.kt:139)
at androidx.compose.ui.node.LayoutNodeDrawScope.drawContent(LayoutNodeDrawScope.kt:48)
at androidx.compose.foundation.Background.draw(Background.kt:107)
at androidx.compose.ui.node.DrawEntity.draw(DrawEntity.kt:98)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:320)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:310)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:839)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:90)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:318)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:310)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:839)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:90)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:318)
at androidx.compose.ui.node.LayoutNodeWrapper.access$drawContainedDrawModifiers(LayoutNodeWrapper.kt:60)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:340)
at androidx.compose.ui.node.LayoutNodeWrapper$invoke$1.invoke(LayoutNodeWrapper.kt:339)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2117)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:113)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:78)
at androidx.compose.ui.node.LayoutNodeWrapper.invoke(LayoutNodeWrapper.kt:339)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:161)
at androidx.compose.ui.node.LayoutNodeWrapper$invokeOnCanvasInstance$1.invoke(LayoutNodeWrapper.kt:161)
at androidx.compose.ui.platform.SkiaLayer.performDrawLayer(SkiaLayer.skiko.kt:264)
at androidx.compose.ui.platform.SkiaLayer.drawLayer(SkiaLayer.skiko.kt:225)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:305)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:839)
at androidx.compose.ui.node.InnerPlaceable.performDraw(InnerPlaceable.kt:90)
at androidx.compose.ui.node.LayoutNodeWrapper.drawContainedDrawModifiers(LayoutNodeWrapper.kt:318)
at androidx.compose.ui.node.LayoutNodeWrapper.draw(LayoutNodeWrapper.kt:310)
at androidx.compose.ui.node.LayoutNode.draw$ui(LayoutNode.kt:839)
at androidx.compose.ui.platform.SkiaBasedOwner.draw(SkiaBasedOwner.skiko.kt:347)
at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:419)
at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:316)
at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:315)
at androidx.compose.ui.awt.ComposeLayer.catchExceptions(ComposeLayer.desktop.kt:107)
at androidx.compose.ui.awt.ComposeLayer.access$catchExceptions(ComposeLayer.desktop.kt:85)
at androidx.compose.ui.awt.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:315)
at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:510)
at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:40)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}#119c1b04, SwingDispatcher#56da22a8]
This happens for every shape, even one that doesn't even draw anything:
TextWithIcon("Hi", GenericShape { _, _ -> })
The weird thing is, I'm certain I've seen this code work and draw the shape. I'm just not sure what I changed between then and now, that broke it.
Removing everything from the Modifier except the (second) border doesn't help, still crashes. Also removing the Box content then fixes the crash, presumably because Compose knows the element is empty and won't even try to render it...
How do I get this to work?

In Compose a shape is not allowed to be null or zero or empty. When you try to draw empty it usually invoke error java.lang.IllegalArgumentException: width and height must be > 0 means GenericShape { _, _ -> } is not supported
but in your case the error is Exception in thread "AWT-EventQueue-0" which usually invoked on bad Initialization, this thread is for handling user events like clicks
you should change GenericShape to something which occupy width and height

Related

see if the div is present or not in geb

We are using Geb for automation. I have spinner loaded before every page gets loaded. we are using waitFor() , but it takes a long time and the scripts are getting run more than the specified time.The DOM element is
<div classname="loader"></div>
i tried to see if the element is present.
if(!$(".loader").displayed== true)
{}
But i am getting error as ,
geb.waiting.WaitTimeoutException: condition did not pass in 40.0 seconds (failed with exception)
at geb.waiting.Wait.waitFor(Wait.groovy:138)
at geb.waiting.DefaultWaitingSupport.doWaitFor(DefaultWaitingSupport.groovy:51)
at geb.waiting.DefaultWaitingSupport.waitFor(DefaultWaitingSupport.groovy:46)
at geb.Page.waitFor(Page.groovy:516)
at geb.Browser.methodMissing(Browser.groovy:206)
at geb.spock.GebSpec.methodMissing(GebSpec.groovy:56)
at loaderSpec(loaderSpec.groovy:415)
Caused by: Assertion failed:
$(".loader").displayed== false
| | |
| true false
[[[ChromeDriver: chrome on XP (1b3943691dd96ebaf9098b1720c87ee9)] -> css
selector: .loader]]
at loaderSpec(loaderSpec.groovy:415)
at loaderSpec(loaderSpec.groovy:415)
at geb.waiting.Wait.waitFor(Wait.groovy:127)
... 6 more
I am not sure how to check if the div is present or not present. If I extend the time to wait for, I am getting element not found error.
Kindly let me know your input.
Are you checking that the div is visible while you are waiting for the spinner to go away?
I've had an issue exactly like this that plagued me. Here is the solution my coworkers and I came up with:
try{
waitFor(10) { element.isDisplayed() } //wait for spinner to kick in
waitFor() { !element.isDisplayed() } //wait for spinner to go away
} catch(WaitTimeoutException e) {
// if spinner loads & deloads faster than this code is reached
// then WTE will be caught and we dont need to handle the spinner any more
//println(e.printStackTrace())
}
Your boolean expression is more complicated than it needs to be, and in this case you might be noting (!) something you don't mean to be.
in general, you never need to compare booleans. (bool1==true) is the same as saying (bool1).
instead of saying
if(!$(".loader").displayed== true){}
just say:
if($(".loader").displayed){} //to check if the div is displayed
or
if(!$(".loader").displayed){} //to check if the div is not displayed
You can try with code if(!$(".loader")==undefined){}

Infinite loop when using disabled attribute binding to a function

The pre rendering is not working when I bind the "disabled" directive to a function which contains a console.log().
<button [disabled]="!isValid()"></button>
My function
public isValid(){
console.log("isvalid");
return true;
}
From my visual studio output console, I got this :
Microsoft.AspNetCore.NodeServices: Information: isvalid
Microsoft.AspNetCore.NodeServices: Information: isvalid
Microsoft.AspNetCore.NodeServices: Information: isvalid
..... (the same infinite loop message) ............
If I remove the console.log, the pre-rendering works, but I suppose the proccess keep on checking the if the button isValid or not.
My package versions
"angular2-platform-node": "2.1.0-rc.1",
"angular2-universal": "2.1.0-rc.1",
"angular2-universal-patch": "0.2.1",
"angular2-universal-polyfills": "2.1.0-rc.1",
"aspnet-prerendering": "2.0.3",
Microsoft.AspNetCore.SpaServices : 1.1.0;
Microsoft.AspNetCore.NodeServices : 1.1.0;
The issue is, that when you call a method in the template, it is called every time change detection is run, which happens often. So this is actually not an infinite loop, Angular just calls this method on each change detection.
You can solve this by handling the logic in the component, store it in a variable, and use the variable in the template.

JavaFX select TreeItem automatically when a node inside the TreeItem gains focus

I have a TreeView that I've modified by putting an HBox in the "graphic" of the TreeItem label. This HBox contains a MenuButton. I want to be able to automatically select the TreeItem whenever focus is given to the MenuButton inside it -- something JavaFX doesn't do automatically. However, when I do something like this in the TreeView's cell factory:
menuButton.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> value, Boolean oldVal, Boolean newVal)
{
if(newVal.equals(oldVal))
return;
if(newVal)
{
TreeItem<FormationDataModel> treeItem = getTreeItem();
System.out.println("Setting selection to " + treeItem + "...");
treeView.getSelectionModel().select(treeItem);
}
}});
The focus on the menu button will often cause this Exception:
java.lang.NullPointerException
at javafx.scene.Scene$ScenePulseListener.synchronizeSceneProperties(Scene.java:2148)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2210)
at com.sun.javafx.tk.Toolkit$5.run(Toolkit.java:363)
at com.sun.javafx.tk.Toolkit$5.run(Toolkit.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:361)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:384)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:463)
at com.sun.javafx.tk.quantum.QuantumToolkit$9.run(QuantumToolkit.java:332)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:17)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:67)
at java.lang.Thread.run(Thread.java:744)
Does anyone have any idea what would cause this or how to fix it so that I can have a TreeItem selected automatically when a node inside the TreeItem gains focus?
For anyone else interested, this turns out to be one or more bugs in JavaFX 2.2 specifically where they override the implementation of the MultipleSelectionModel to fix OTHER bugs. In the process of doing that, they cause all sorts of problems because they automatically expand the children of any selected item. When you do that, many of the TreeItems are invalidated, causing all sorts of sync havoc. The workaround was to select items by INDEX instead of by OBJECT. That works perfectly fine.

CoreDispatcher.ProcessEvents() causes an indirect crash?

I have to port some legacy code, that uses modal dialog boxes all over the place to Metro/WinRT (using C++/CX). Because these dialog boxes provide their own message loop (using DialogBoxParam()), the calling code will wait until the user has clicked a button on the message box.
I'm currently trying to write a replacement for the old message box class, that uses XAML and the popup control. To reproduce the same behavior, I have to wait in the calling thread, but also have to keep the UI responsive. I've found out, that CoreDispatcher::ProcessEvents() can be used in a loop, to keep processing events (yeah I realize that this isn't very beautiful, but I don't want to change all of our legacy code to a new threading model). However I'm running into an issue that keeps crashing my app.
Here is a minimal example that reproduces the issue (just create a XAML app and wire this to a button):
void CPPXamlTest::MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
bool cancel = false;
auto popup = ref new Popup();
auto button = ref new Button();
button->Content = "Boom";
auto token = (button->Click += ref new RoutedEventHandler([&cancel] (Object ^, RoutedEventArgs ^) { cancel = true; }));
popup->Child = button;
popup->IsOpen = true;
while (!cancel)
{
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
popup->IsOpen = false;
button->Click -= token;
}
This seems to work well for the first one or two tries of opening and closing the popup, using the two buttons. After a few tries however, the application will instantly crash deep in Windows.UI.Xaml.dll, while trying to dereference a null pointer. I can also reproduce this in C# (with practically the same code).
Does anyone have an idea, what is going on in here? Or a suggestion for an alternative approach?
If anyone is interested: I asked the same question a few days later on the MSDN forums and got a response there from a Microsoft employee:
http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/11fa65e7-90b7-41f5-9884-80064ec6e2d8/
Apparently the problem here is the nested message loop that is caused by calling ProcessEvents inside an event handler. It seems that this is not supported by WinRT, but instead of failing in a well-defined manner, this will or may cause a crash.
Alas this was the best and only answer I could find, so I ended up working around the problem, by dispatching the event handler (and a lot of other code) into another thread. I could then emulate the waiting behavior of DialogBox()/DialogBoxParam() (outside the main thread), by waiting on an event that was signaled when the user clicked/tapped a button on my XAML "dialog" popup.
A workaround that works fine for me is to replace the line:
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
with:
auto myDispatchedHandler = ref new DispatchedHandler([&](){
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
});
dispatcher->RunAsync(CoreDispatcherPriority::Normal,myDispatchedHandler);
For more info see this post at MSDN.

geb StaleElementReferenceException

I have just started using geb with webdriver for automating testing. As I understand it, when I define content on a page, the page element should be looked up each time I invoke a content definition.
//In the content block of SomeModule, which is part of a moduleList on the page:
itemLoaded {
waitFor{ !loading.displayed }
}
loading { $('.loading') }
//in the page definition
moduleItems {index -> moduleList SomeModule, $("#module-list > .item"), index}
//in a test on this page
def item = moduleItems(someIndex)
assert item.itemLoaded
So in this code, I think $('.loading') should be called repeatedly, to find the element on the page by its selector, within the context of the module's base element. Yet I sometimes get a StaleElementReference exception at this point. As far as I can tell, the element does not get removed from the page, but even if it does, that should not produce this exception unless $ is doing some caching behind the scenes, but if that were the case it would cause all sorts of other problems.
Can someone help me understand what's happening here? Why is it possible to get a StaleElementReferenceException while looking up an element? A pointer to relevant documentation or geb source code would be useful as well.
It turns out that the problem was that the reference to the element represented by the module itself had become stale by modification, and not the .loading element. I suspect that the exception originated from that line because it was trying to search within the module's base element to find the .loading element. The solution is to load the module at the same time as checking for the element inside it. In this case it would look something like this:
//In the content block of SomeModule, which is part of a moduleList on the page:
itemLoaded { !loading.displayed }
loading { $('.loading') }
//in the page definition
moduleItems {index -> moduleList SomeModule, $("#module-list > .item"), index}
//in a test on this page
waitFor { moduleItems(someIndex).itemLoaded }
Thanks to Marcin on the geb-user mailing list for pointing me in the right direction.