Transparent window and view using Apple's Metal - objective-c

I want to create a window which is fully transparent and which can be used for drawing (On-Screen-Display). It's actually quite simple to create such a window, the one has to set the opaque property to false and fill the corresponding view with a clear color. After that the CGImage can be drawn using the graphical context to update the view and the corresponding regions with alpha channel will be transparent / semi-transparent.
I decided to make the same thing but using the Metal API, i.e. I replaced my view with a MTKView and used textures instead of CGImage to draw onto the window. I read the corresponding chapters from Apple Documentation, then I took one of the examples ("Basic Texturing") and decided to modify it in order to test if it would work:
I modifed the example by settings the opaque property of the window to NO.
In the first line of drawInMTKView function I changed the clearColor in the following way: view.clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0); (as shown "Devices and Commands" tutorial from docs).
Then I changed the alpha channel value of the loaded image in AAPLImage.h from dstImageData[dstPixelIndex + 3] = 255; to dstImageData[dstPixelIndex + 3] = 125;.
After all these change, I would expect that my view is fully transparent (the clear color is a fully transparent color) and that the parts of the texture with the alpha channel would have the corresponding transparency level. However the view is black by default and I cannot make parts of the view (or the whole view) transparent.
I may assume that I have to add some additional configuration to the rendering pipeline in order to make it work. However it could be that such things are not possible with Metal, but I'm not sure about that.
Also I tried to follow the suggestions from Metal MTLTexture replaces semi-transparent areas with black when alpha values that aren't 1 or 0 , but unfortunately it did not help.

There is also an isOpaque property on the view class that may need to be false. In iOS (UIView), you can simply set it, but in macOS (NSView) you need to override it to return false.

Related

Completely transparent UIButton with irregular hit area

I know how to use a background image with alpha channel to create a UIButton with an irregular tap area. But with this solution, only the ignore-tap area is transparent; the tap area consists of the opaque.
What I want is a totally transparent UIButton, with an irregular tap area. (It triggers an animation behind the button.)
It seems that some sort of extra UILayer with some hit-testing could work, but I don't quite see how. Suggestions welcome.
Here's my solution. The problem: A UIImageView (call it the base view) to which I want to attach an irregularly-shaped tap area. The area corresponds to something in the image, let's call it a river. It could be a non-connected region.
In the Finder, duplicate the view's image, and make all the non-river pixels transparent, using your favorite graphics app. Call this the mask image.
When the base view is tapped, check to see if the corresponding pixel in the mask image is or is not transparent. (Solution left to reader; examples abound.)
So the mask image is never actually rendered, it is just used as a reference.
Note that if the base view gets resized or moved around (as it does in my app, via animating its constraints) then you have to "move" the mask image too, or in some other way manage the coordinate translation between view and mask. The easiest way to do this is to make the mask image a hidden subview of the base view, with its left, top, leading and trailing anchors constrained to be equal to those of the base view. Then they move around together, and the coord translation between the two is the identity.
I wrapped all this up in a subclass of UIImageView so that it manages its own mask, and calls a delegate if the "river" (or whatever) is tapped.

Codenameone Slider cannot set height

I am finding it difficult to set the right look and feel of a CN1 Slider control. Essentially i want it to look like the one in the CN1 Default Demo of the Theme window, and have it with the Thumb image to allow the user to set the scroll.
But when i code it up as per online examples, it comes out skinny on the simulator (as below)
...but doesn't display the line at all on the actual iphone device.
When i start messing with the methods, such as 'getSliderEmptyUnselectedStyle()' then this makes the background show and can see the progress but its tall and i cannot seem to shrink it.
Container container = new Container(new FlowLayout());
container.getAllStyles().setBgTransparency(255);
container.getAllStyles().setBgColor(0xffffff);
Slider slider = new Slider();
// slider.getAllStyles().setFgColor(0);
// slider.getAllStyles().setMarginLeft(0);
// slider.getSliderEmptyUnselectedStyle().setBgTransparency(255);
// slider.getSliderFullUnselectedStyle().setBgTransparency(255);
// slider.getSliderEmptySelectedStyle().setBgTransparency(255);
// slider.getSliderFullSelectedStyle().setBgTransparency(255);
// slider.getSliderEmptyUnselectedStyle().setBgColor(0xffffff);
// slider.getSliderFullUnselectedStyle().setBgColor(0x42B72A);
// slider.getSliderEmptySelectedStyle().setBgColor(0xffffff);
// slider.getSliderFullSelectedStyle().setBgColor(0x42B72A);
Style sliderStyle = UIManager.getInstance().getComponentStyle("Label");
sliderStyle.setFgColor(0);
slider.setThumbImage(
FontImage.createMaterial(FontImage.MATERIAL_RADIO_BUTTON_CHECKED, sliderStyle, 4).toImage());
slider.setMinValue(0);
slider.setIncrements(25);
slider.setProgress(entity.getCompletion_pct());
slider.setEditable(true);
container.add(slider);
return container;
How can i get it pretty much to the CN1 example?
Thanks
The slider in the example used a 9-piece border or a 3-piece border both of which have a fixed minimum height/width. This minimal height is applied to the way the slider is rendered.
Your code can be made thicker with padding but it will create a problem when you add a thumb. Once you add the thumb it will increase the overall size and make the entire height of the thumb have that background. So you need to style this via the designer and for this specific case you would want to use an image border that is carefully measured to align with the thumb image.
Also notice you used getAllStyles() which is wrong. Slider is a special case and uses the Slider and SliderFull UIID so effectively the component has two UIID's and two separate sets of Style objects.

View not resizing if done in the "viewWillAppear" or "viewDidLoad" method

I am developing a game: I need to load the user's score (locally and if internet is available, download it from the server) and resize an UIView based on the value.
The problem is that when the score is loaded locally (calling the "resizeUserBar" from viewWillAppear), no view gets resized. But if the same method ("resizeUserBar") is called after the score gets downloaded from the server, it gets resized properly. I have debugged the frame's values and they are correct in both cases.
Here's the code I am using to resize:
CGRect frame = firstBar.frame;
frame = CGRectMake(frame.origin.x, frame.origin.y, firstBarSpace, frame.size.height);
firstBar.frame = frame;
frame = secondBar.frame;
frame = CGRectMake(firstBar.frame.origin.x + firstBarSpace, frame.origin.y, secondBarSpace, frame.size.height);
secondBar.frame = frame;
Autolayout is active on my Storyboard but I'm not using it yet. There are no constraints on the views used in the method above.
Thank you
Thank you
You say:
Autolayout is active on my Storyboard but I'm not using it yet. There
are no constraints on the views used in the method above.
In Xcode 5, if you have Auto Layout turned on but don't set any constraints, the compiler will automatically generate fixed size and position constraints for you at build time.
Turn off Auto Layout and you'll see that your resizing will start to work. Or, setup some actual constraints.
Update: More information…
Auto Layout Guide: Working with Constraints in Interface Builder on Apple.com
When you drag out an element from the Object Library and drop it on
the Interface Builder canvas, it starts out unconstrained to make it
easy to prototype your interface by dragging elements around. If you
build and run without adding any constraints to an element, you’ll
find that Interface Builder fixes the element’s width and height, and
pins its position relative to the top left corner of the superview;
this means that resizing the window doesn’t move or resize the
elements. To make your interface react correctly to changes in size or
orientation, you need to start adding constraints.

iOS: Drawing a Rectangle on an ImageView and Adjusting Borders

Attached 1 is a screenshot from an app called GeniusScan where you can photograph any document and an adjustable rectangular grid shows on the imageview. You can easily adjust the borders of the grid with your fingers to select the portion of the image that you want to scan. It will be then transformed into the correct prospective.
1- How can I draw and interact with the grid on the imageview?
2- How can I return the corner points of the grid to my view controller.
Update: I found a wonderful class called BJImageCropper which allows to use fingers to ajust the borders, but only for a box like rectangle. Can anyone suggest how it can be updated to support shapes like in the GeniusScan app?
Dude:
I created a demo that solves both questions:
1- How can I draw and interact with the grid on the imageview?
By Adding 4 views that will act as interactive control points by adding UIPanGestureRecognizer and then drawing the grid using CAShapeLayer on top of your view.
2- How can I return the corner points of the grid to my view controller.
You must keep references to the four control points of your grid.
Here's the link to my code.
This isn't actually drawing on top of UIImageView. It's actually an overlay (view) on top of the UIImageView. You need to keep track of 4 points (have 4 views as subview of the layer), track their positions, once moved, use drawRect: to draw lines based on the 4 points.
The way I've implemented it in my app is, I overlay the UIImageView with a transparent 'SelectionView' (a custom view that I wrote). The selectionView contains 4 custom subview of class 'Vertex'. The vertex talk back to the selectionView via protocol method every time user touches/moves it (it's actually not important which vertex moved, just that it moved):
- (void)vertexMoved:(Vertex *)vertex;
Then the selectionView knows that it needs to re-draw, so it calls setNeedsDisplay which calls internally calls drawRect (you should never call drawRect) where I do the actual drawing of the bounding rect. Basically, iterate through each vertex and draw a line using Quartz APIs and fill it with semi transparent/hollow color.
This is how I am doing it atleast, I am sure there are other ways.

How Can I use Graphics.CopyFromScreen to enable alpha transparent controls?

I am trying to use (and this may be my problem already) e.Graphics.CopyFromScreen() in the OnPaint() method of my control to prepare a background onto which I can draw the content of the control. The goal is a tool-tip with rounded corners and other specific features to replace the default Windows tool tip.
Ideally the tool tip could be antialiased and blended into the backdrop, however at a pinch I could tolerate an aliased boundary. This may also be necessary as the control will often be covering a control with an OpenGL overlay and the whole blending procedure may end up a nightmare.
I have created a custom user control, a persistent instance of which belonds to my applications's main form, overriding the OnPaint and OnPaintBackground methods. The application of transparency however is challenging. As I understand, the graphics object passed to the paint method starts with a copy of the current VisibleClipBounds, where generally the first move is to clear the control with a solid colour and start drawing the main features. My first thought was to bypass the fill and start drawing on the captured background. For the first redraw this works fine, but subsequent redraws keep the previous content instead of re-capturing the backdrop. I hoped that CopyFromScreen would specifically eliminate the currently drawing control from its capture so as to start from a clean base but this is not the case, it captures the rectangle of the new location including the image of the previous location if it is in the bounds.
Other solutions and permutations thereof such as
SetStyle(ControlStyles.SupportsTransparentBackColor, True)
Me.BackColor = Color.Transparent
e.Graphics.Clear(Color.FromArgb(0,0,0,0))
have to-date yielded no appropriate results.
I started with a transparent form using the transparent key colour. This worked with aliasing but using a form as a tool tip seemed excessive and caused annoying artifacts (some of which could be overcome) such as the temporary presence of the taskbar button, focus loss of underlying form with subsequent visual feedback in the host form's title bar colour. The control is much lighter weight but I am struggling to make it work even as well as the form.
At this point I simply ask how to achieve the desired result and whether CopyFromScreen is a part of that solution.
That's a lot of text to read - but addressing transparency to achieve a custom-shaped form/control... Control.Region can do the same thing:
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // height of ellipse
int nHeightEllipse // width of ellipse
);
private void CreateRegion()
{
this.Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 40, 40));
}
If your control is set as a top-level window and you're running it on Windows 7 or 8, check into DwmEnableBlurBehindWindow. In the parameter structure, I set enable to true and I create a region 1x1 pixels for the blur. With BackColor and TransparencyKey set to Black, this gives me a entirely transparent window (complete with mouse pass-through) that I can paint 32-bit images to with full alpha transparency (using Graphics.FromHwnd). A bonus to this method is that if the window moves or the background changes, Windows DWM does all the work--I don't have to update a thing.