Scaling ImageView object does not seem to change the clickable area - java

First of all, this is my first project in JavaFX, so if my general approach is wrong, I very much appreciate feedback on how else to implement this.
I'm trying to set up a hexagon grid of clickable tiles, similar to Settlers of Catan. I did this by creating a hex class that includes an imageview. For scaling purposes, these imageviews are scaled by a common parameter, where I tried both the .setScaleX/Y and setFitWidth/Heigth functions.
For what it matters, each hex is combined into a StackPane object and then all the hexes are combined into a Group.
To detect mouseclicks, I'm using the .setOnMouseClicked() function.
The problem I've been facing is that when the scaling parameter gets small, the imageviews seem to overlap their clickable areas. The graphic, however, scales properly. Since the setOnMouseClicked() function only responds non-transparent parts, this means there is no response when clicking on tiles overlapped by others.
How can I solve this problem?
Is there a way to scale the clickable area using my global scale parameter?
Can I somehow define the clickable area using some kind of path along the border?
Would it work to define a transparent hexagon shaped button and place on top of my image?
I tried using different approaches to scaling, such as setScaleX and setFitWidth.
I tried using setMaxSize() on the StackPane.
I tried using viewport and clip, but I don't think they do what I'm looking for.
public Hex(Point2D pos, double sizeScale){
...
Image img = new Image( "images/hex.png" );
m_size = new Point2D(img.getWidth(), img.getHeight());
m_image = new ImageView( img );
...
m_image.setFitWidth( m_sizeScale * m_size.getX() );
m_image.setFitHeight( m_sizeScale * m_size.getY() );
...
}
Expected result:
Each hex is clickable, giving different responses based on which hex is clicked.
Actual result:
Hexes added before added hexes are not clickable if positioned to the right or below. (Anchor point is top-left)

Related

Codename One - Unwanted padding/spacing in ScaleImageLabel

New to Codename One, moving over from Android "native" java development.
I'm trying to create a SideMenu design that loosely resembles the Material side menu, as seen in just about every Google app (e.g. Play Store). Starting with a header image, I can't seem to get rid of some padding on the top and bottom:
The white bars on the top and bottom are unwanted. Current code:
public void start() {
if (current != null) {
current.show();
return;
}
home = new Home();
// SideMenu header BG image
Image headerImage = theme.getImage("bg_navdrawer_header.png");
ScaleImageLabel sideMenuHeaderBg = new ScaleImageLabel(headerImage);
sideMenuHeaderBg.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
// SideMenu header app title
Label sideMenuHeaderLabel = new Label("Title");
sideMenuHeaderLabel.setUIID("SideMenuHeaderTitle");
Container sideMenuHeader = new Container();
sideMenuHeader.add(LayeredLayout.encloseIn(sideMenuHeaderBg, FlowLayout.encloseBottom(sideMenuHeaderLabel)));
home.getToolbar().addComponentToSideMenu(sideMenuHeader);
home.show();
}
The white bars disappear if I use BACKGROUND_IMAGE_SCALED_FILL, but then it doesn't keep aspect ratio - it stretches to fill those two white spaces. (EDIT: It does keep aspect ratio, but it clips the longer dimension). I've tried setting the UIID to "Container" to... everything, makes no difference.
Any ideas?
UPDATE:
For some reason, calling setWidth on the ScaledImageView immediately after setting the background type solved it. Doesn't matter what the width is, any number at all and the "letterboxing" is gone and the height is as it should be.
ScaleImageLabel sideMenuHeaderBg = new ScaleImageLabel(headerImage);
sideMenuHeaderBg.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FILL);
sideMenuHeaderBg.setWidth(0);
Going to leave this open in case somebody has a better solution or can at least explain why this is the case, or exactly what is happening since my solution is more of a hack than an actual answer.
BACKGROUND_IMAGE_SCALED_FILL should keep aspect ratio. It resizes the image to "fill" the space's shorter dimension. The longer dimension is clipped.
BACKGROUND_IMAGE_SCALED will stretch to fill the space, but won't keep aspect ratio.
BACKGROUND_IMAGE_SCALED_FIT will also keep aspect ratio. It resizes the image to "fill" the space's longer dimension. The shorter dimension is "letterboxed", as you see in your screenshot.

Displaying a part of an image in libGDX - looks stretched

I'm trying to build an progress bar in libGDX, for that I have one full horizontal image and in two lines I trying to display 2 different widths of that image:
imageFull:
imageFull.draw(batch,10,80,600,50);
imageFull.draw(batch,10,20,100,50);
the result is:
Its looks like when the width is 'small' its stretched and looks bad.
Why I can't display only part of the image without destroying the left side of the image?
Any ideas how to fix it?
That is normal behavior. If you stretch a image without keeping it's aspect ratio it will deform, it does not know the stretchable part by itself.
9-patch will help you here but you cannot simply draw the sprite as you are doing now (maybe with SpriteDrawable though?).
If I where you I would use the Scene2D Actor named ProgressBar. Feed that a 9-patch image, then it should stretch correctly. Or just use a Image if you want to control it yourself, and feed this image a ninepatch.
A quick way to create a ninepatch is to specify it's stretching regions yourself by hardcoding it.
texture = new NinePatch(yourTexture, A, B, C, D)
Where ABCD corresponds to the following image:
Now create a Scene2D Image with that ninepatch and it should stretch properly.
If you have a this texture already in a Atlas you can also supply the line split:a,b,c,d to the image data in the .atlas file and Scene2D will automatically pick it up as a ninepatch.
If you don't want to use Scene2D and/or ninepatch (but I recommend you to use it) you have to code the behavior yourself. Or cut the texture up yourself and stick the caps on the left and right side of your rectangle. But Scene2D is invented for this and a ton more GUI functionality.

Stretching buttons in libgdx?

In libgdx, you can create a TextButtonStyle that has images for up and down states, but when you set the size of a button it stretches the image. Is there anyway to make a button style that allows you to set the corners, sides and middle of a button so that instead of stretching the button image, it just tiles the sides and middle images? For example, a button in java's swing library can be set to any size without having a stretched look, but in libgdx a button stretches its image to fit the rectangle. This is more noticable on rounded buttons. How can I fix this?
What you are looking for is called a NinePatch. Basically that is an special kind of image that defines strechable and not-strechable parts of the image. A typical use case for the NinePatch is a Button as you usually don't want the edges to get stretched and just stretch the rest.
A Simple example of instantiating would be:
NinePatch patch = new NinePatch(new Texture(Gdx.files.internal("knob.png")), 12, 12, 12, 12);
For more details about this example you can see the wiki page about NinePatches: https://github.com/libgdx/libgdx/wiki/Ninepatches

Options to put corners in Android ImageView

I'm trying to put corners im my ImageView and I find these "workarounds":
1 - Take the Bitmap soure and paint then
2 - put a second ImageView on my layout and use shape+corners as its source
It's not possible take the image view and put a corner around then?
In my app i have a List with a lot of ImageView (the Bitmap used in this ImageView's is programmatically) and I want to put corners in every ImageView.
There is any other option?
You can create a selector that contains shape with rounded corners, and then apply it as the ImageView's background using xml.
Look at this answers here
You can also do it via code by using PorterDuffXfermode. PorterDuffXfermode uses alpha compositing that will allow you to create and intersection (things of mathematical sets here) between the Canvas you get from onDraw() and an off screen Canvas you will have to create. You will use one of the PorterDuff.Mode flags to tell the framework you want to only render the pixels that intersect from the two Bitmaps in each Canvas.
More on Alpha Compositing

How can I get a certain RGB value from a canvas painted with LinearGradientPaint?

I have used the LinearGradientPaint class to draw a rectangle dynamically filled with user-defined colors. This happens by overriding the paintComponent method.
Here is how it looks like:
.
You can see the small thumbs/ handle on top. The user can move these around, delete them, and add new ones. They can also change the color. As a result the user can completely customize how the gradient looks like. This works just fine so far, no issue.
What I need now, and I tried searching for this info, is to get RGB-values anywhere on this gradient.
I only know the x-amount of colors that LinearGradientPaint uses to generate the gradient. I know at what point (fraction) these colors are located (the number below the gradient box, corresponding with the 'thumbs' on top.
Is there anyway to get the colors in between the RGB-values which are used to generate the gradient? In my example above I mean the darkened red or green areas.
If this really is a linear gradient between new Color(r1,g1,b1) and new Color(r2,g2,b2), then the colour at x, where 0 <= x <= 1 is
new Color((int)(r1*(1-x)+r2*x),(int)(g1*(1-x)+g2*x),(int)(b1*(1-x)+b2*x));
Of course, I have no idea whether this is the formula that is actually used inside LinearGradientPaint - but it ought to be something equivalent to this.
A way you might be able to do this, is to create a 1 pixel high BufferedImage of the same width of your component, render the gradient to it and simple use something like BufferedImage#getRGB.
This will return a int packed color value, which you can then use Color(int) to return a Color object, which makes it easier to extract the color components of the pixel.
Of course, this would all be easier if you used the BufferedImage as your primary output as well, then you would only have to create it once and because you'd be updating the image so it could be rendered to the screen, it would also be up-to-date

Categories