Can I use icons with RGBA transparency when using GTK+ drag and drop? - drag-and-drop

I am in the process of adding drag and drop support to an existing Mono/C#/GTK# application. I was wondering whether it was possible to use RGBA transparency on the icons that appear under the mouse pointer when I start dragging an object.
So far, I realized the following:
I can set the bitmap in question by calling the Gtk.Drag.SourceSetIconPixbuf() method. However, no luck with alpha transparency: pixels that are not fully opaque would get 100% transparent this way.
I also tried calling RenderPixmapAndMask() on the GdkPixbuf so that I could use Gtk.Drag.SourceSetIcon() with an RGBA colormap of my Screen. It didn't work either: whenever I started dragging, I got the following error:
[Gdk] IA__gdk_window_set_back_pixmap: assertion 'pixmap == NULL || gdk_drawable_get_depth (window) == gdk_drawable_get_depth (pixmap)' failed.
This way, the pixmap doesn't even get copied, only a white shape (presumably set by the mask argument of SetSourceIcon()) shows up on dragging.
I'd like to ask if there's a way to make these icons have alpha transparency, despite the fact that I failed to do so. In case it's impossible, answers discussing the reasons of the lack of this feature would also be helpful. Thank you.
(Compositing is - of course - enabled on my desktop (Ubuntu/10.10, Compiz/0.8.6-0ubuntu9).)

Ok, finally I solved it. You should create a new Gtk.Window of POPUP type, set its Colormap to your screen's RGBA colormap, have the background erased by Cairo to a transparent color, draw whatever you'd like on it and finally pass it on to Gtk.Drag.SetIconWidget().
Sample code (presumably you'll want to use this inside OnDragBegin, or at a point where you have a valid drag context to be passed to SetIconWidget()):
Gtk.Window window = new Gtk.Window (Gtk.WindowType.Popup);
window.Colormap = window.Screen.RgbaColormap;
window.AppPaintable = true;
window.Decorated = false;
window.Resize (/* specify width, height */);
/* The cairo context can only be created when the window is being drawn by the
* window manager, so wrap drawing code into an ExposeEvent delegate. */
window.ExposeEvent += delegate {
Context ctx = Gdk.CairoHelper.Create (window.GdkWindow);
/* Erase the background */
ctx.SetSourceRGBA (0, 0, 0, 0);
ctx.Operator = Operator.Source;
ctx.Paint ();
/* Draw whatever you'd like to here, and then clean up by calling
Dispose() on the context's target. */
(ctx.Target as IDisposable).Dispose ();
};
Gtk.Drag.SetIconWidget(drag_context, window, 10, 10);

Related

Draw to GdkWindow root window with Gtk3 and Cairo

I want to be able to draw directly to the root window with Gtk3 using Cairo. I have and old Gtk2 code drawing on a fullscreened window like this:
GdkWindow* drawable;
GdkGC* gc;
drawable = gdk_screen_get_root_window (gdk_screen_get_default());
gc = gdk_gc_new (drawable);
gdk_gc_set_subwindow (gc, GDK_INCLUDE_INFERIORS);
...
do_draw(drawable, gc);
With Gtk3 I tried this,
GdkWindow* drawable;
drawable = gdk_screen_get_root_window (gdk_screen_get_default());
cairo_surface_t *source_surface = gdk_window_create_similar_surface (drawable, CAIRO_CONTENT_COLOR_ALPHA, gdk_window_get_width(drawable), gdk_window_get_height(drawable) );
cairo_t *cairo = cairo_create(source_surface);
cairo_set_source_surface(cairo, source_surface, 0, 0);
....
do_draw(cairo);
The code seems to runs fine, but nothing is ever drawn to the screen. Is there a way to do something similar with Gtk3 and Cairo?
gdk_window_create_similar_surface creates a new surface that is "similar" to an already given one. But it is still a new surface.
You are looking for gdk_cairo_create() instead, I think (which is deprecated).
Unrelated to your question, but what is the following code supposed to do? Why are you preparing to copy a surface to itself? I think that is not really an allowed operation in cairo.
cairo_t *cairo = cairo_create(source_surface);
cairo_set_source_surface(cairo, source_surface, 0, 0);

Unity - Set GUI.Box background color

I'm trying to set the background color of a GUI.Box:
void OnGUI()
{
string LatLong;
LatLong = map.calc.prettyCurrentLatLon;
var mousePosition = Input.mousePosition;
float x = mousePosition.x + 10;
float y = Screen.height - mousePosition.y + 10;
GUI.backgroundColor = Color.red;
GUI.Box(new Rect(x, y, 200, 200), LatLong);
}
However, the box is showing in a semi-transparent black, and the white text is subdued, not opaque white.
You have to use s gui style:
private GUIStyle currentStyle = null;
void OnGUI()
{
InitStyles();
GUI.Box( new Rect( 0, 0, 100, 100 ), "Hello", currentStyle );
}
private void InitStyles()
{
if( currentStyle == null )
{
currentStyle = new GUIStyle( GUI.skin.box );
currentStyle.normal.background = MakeTex( 2, 2, new Color( 0f, 1f, 0f, 0.5f ) );
}
}
private Texture2D MakeTex( int width, int height, Color col )
{
Color[] pix = new Color[width * height];
for( int i = 0; i < pix.Length; ++i )
{
pix[ i ] = col;
}
Texture2D result = new Texture2D( width, height );
result.SetPixels( pix );
result.Apply();
return result;
}
Taken from unity forum.
I'm gonna slide in with a more elegant solution here before this question gets old. I saw Thomas's answer and started to wonder if there is a way to do that without having to do the "InitStyles" in the OnGUI loop. Since ideally you only want to init the GuiSkin once in Awake or Start or wherever, but only once, and then never check to see if it's null ever again.
Anyway, after some trial and error, I came up with this.
private void Awake() {
// this variable is stored in the class
// 1 pixel image, only 1 color to set
consoleBackground = new Texture2D(1, 1, TextureFormat.RGBAFloat, false);
consoleBackground.SetPixel(0, 0, new Color(1, 1, 1, 0.25f));
consoleBackground.Apply(); // not sure if this is necessary
// basically just create a copy of the "none style"
// and then change the properties as desired
debugStyle = new GUIStyle(GUIStyle.none);
debugStyle.fontSize = 24;
debugStyle.normal.textColor = Color.white;
debugStyle.normal.background = consoleBackground;
}
REVISION - 17 July 2022 - GUI Style Creation and Storage
Prelude
Style creation through the methods provided by others are certainly functional methods of providing your custom editors with a unique look. They have some fundamental issues I should point out, which my method doesn't outright correct, just alleviate. This method still needs to be expanded upon and is still a partly experimental progression from a personal plugin.
Creating styles every OnGUI Call creates unnecessary, extra instructions for your editor window. This doesn't scale well past a handful (4~) styles.
By creating styles every time OnGUI is called, you're creating textures repeatedly for the background colour (not good). Over prolonged use of this method, memory leaks can occur although unlikely.
What does my method do differently?
Creates GUIStyle and Texture2D files. GUIStyles are saved as .JSON files, which is best compatible for [JSON <-> GUIStyle] conversion and storage.
Texture2Ds are encoded from raw data to PNG format through UnityEngine.
Checks if a style file is null before fetching or creating any missing styles again.
Contains a list of all styles through the use of a Style Manifest (struct) to store the names of all textures and styles to iteratively load on fetch.
Only creates styles if they are missing. Does not spend resources on creating pre-existing styles and pre-existing styles.
GUIStyles (as JSONs) and Texture2D files are stored in a Resources folder within the Plugin folder.
It should be noted that my style methods are done with the express understanding and consideration of GUISkins existing. They are not suitable for my UI/UX needs.
How is this done?
Plugin Style Handing Diagram
I separate Style Loading into a unique namespace for style handling and contain functions, as well as public variables for global plugin access, within. This namespace creates, loads and can send back styles on the requests sent by other scripts.
A call to a function is made when the plugin is opened to load the style manifest and subsequently all styles and textures are loaded, to be relinked for use.
If the styles manifest is missing then it is recreated along with all GUIStyle files. If the styles manifest is not missing but a style is then that style is recreated and the style manifest is modified to reference the new style.
Textures are handled separately from GUIStyle loading and are collected in a separate array. They are independently checked to see if they still exist and missing textures are recreated and encoded from raw data to PNG format, with the style manifest being modified when necessary.
Instead of repeatedly creating all styles or repeatedly loading them each frame, the plugin sends a request to fetch the first style from memory and checks if the result is null. If the first style returns as null then the plugin assumes all styles have been dereferenced and calls a reload or recreation of the relevant GUIStyle files (this can happen because of the engine entering/exiting play mode and is necessary to preserve UI/UX legibility).
If the style returns as a valid reference, plugins of mine do use it but this is risky. It's a good idea to also check at least one texture because textures are at risk of being dereferenced from the Texture2D array.
Once each check is done, the plugin renders the layout as normal and the next cycle begins. Using this method overall requires extra processing time and extra storage space for the plugin but in turn:
Quicker over a longer period of time due to styles being created or loaded only when necessary
Easier to modify themes for plugins, allowing individuals to customize the tools to their preferred theme. This can also be expanded on custom "theme packs" for a plugin.
Scalable for large amounts of styles to an extent.
This method still requires experience in GUI Styles, Data Saving, JSON Utilisation and C#.

GTK ignores any type of window positioning

I've been trying to position a splash screen at the center of the screen. In Windows, such a request is easy using SetWindowPos and a bit of geometric arithmetic. I found out that all requests to move a window are ignored by the windowing manager. So my question is, how come I see so many applications with pretty splash screens properly centered? I started with GTK_WINDOW_TOPLEVEL BTW and just switch to popup trying a few things. Setting the gravity and position do not fail, they are just ignored. Even defined in a .glade file, the window is ignored.
{
GtkWidget *pNewWindow = gtk_window_new(GTK_WINDOW_POPUP);
gtk_window_move(GTK_WINDOW(pNewWindow), 0, 0);
gtk_widget_show_all(pNewWindow);
while (gtk_events_pending())
gtk_main_iteration();
gtk_widget_set_size_request(pNewWindow, width, height);
gtk_window_set_decorated(GTK_WINDOW(pNewWindow), FALSE);
// gtk_window_set_position(GTK_WINDOW(pNewWindow), GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_set_resizable(GTK_WINDOW(pNewWindow), FALSE);
// gtk_window_set_gravity(GTK_WINDOW(pNewWindow), GDK_GRAVITY_CENTER);
gtk_window_move(GTK_WINDOW(pNewWindow), 0, 0);
while (gtk_events_pending())
gtk_main_iteration();
return pNewWindow;
}

Gtk - draw event fired for wrong widget, and widget not redrawn

I'm trying to create a custom scrollable text area. I created a DrawingArea and a ScrollBar inside a Grid. I have attached the draw event of DrawingArea to this.on_draw method which simply looks at ScrollBar's value and moves the Cairo.Context appropriately before drawing the Pango.Layout.
The first problem is that this.on_draw is getting invoked whenever the ScrollBar is touched even though I have not registered any events with ScrollBar. How do I prevent this, or check this?
The second problem is that even though this.on_draw is invoked, the changes made to the Context is not displayed unless the ScrollBar value is near 0 or 100 (100 is the upper value of Adjustment). Why is this happening?
I did find out that if I connect the value_changed event of ScrollBar to a method that calls queue_redraw of DrawingArea, it would invoke this.on_draw and display it properly after it. But due to the second problem, I think this.on_draw is getting invoked too many times unnecessarily. So, what is the "proper" way of accomplishing this?
using Cairo;
using Gdk;
using Gtk;
using Pango;
public class Texter : Gtk.Window {
private Gtk.DrawingArea darea;
private Gtk.Scrollbar scroll;
private string text = "Hello\nWorld!";
public Texter () {
GLib.Object (type: Gtk.WindowType.TOPLEVEL);
Gtk.Grid grid = new Gtk.Grid();
this.add (grid);
var drawing_area = new Gtk.DrawingArea ();
drawing_area.set_size_request (200, 200);
drawing_area.expand = true;
drawing_area.draw.connect (this.on_draw);
grid.attach (drawing_area, 0, 0);
var scrollbar = new Gtk.Scrollbar (Gtk.Orientation.VERTICAL,
new Gtk.Adjustment(0, 0, 100, 0, 0, 1));
grid.attach (scrollbar, 1, 0);
this.darea = drawing_area;
this.scroll = scrollbar;
this.destroy.connect (Gtk.main_quit);
}
private bool on_draw (Gtk.Widget sender, Cairo.Context ctx) {
ctx.set_source_rgb (0.9, 0.9, 0.9);
ctx.paint ();
var y_offset = this.scroll.get_value();
stdout.printf("%f\n", y_offset);
ctx.set_source_rgb (0.25, 0.25, 0.25);
ctx.move_to(0, 100 - y_offset);
var layout = Pango.cairo_create_layout(ctx);
layout.set_font_description(Pango.FontDescription.from_string("Sans 12"));
layout.set_auto_dir(false);
layout.set_text(this.text, this.text.length);
Pango.cairo_show_layout(ctx, layout);
return false;
}
static int main (string[] args) {
Gtk.init (ref args);
var window = new Texter ();
window.show_all ();
Gtk.main ();
return 0;
}
}
Also, please point out any (possibly unrelated) mistake if you find one in the above code.
The part that you are missing is that a draw signal does not mean "redraw everything". Instead, GTK+ sets the clip region of the cairo context to the part that needs to be redrawn, so everything else you do doesn't have any effect. The cairo function cairo_clip_extents() will tell you what that region is. The queue_draw_area() method on GtkWidget will allow you to explicitly mark a certain area for drawing, instead of the entire widget.
But your approach to scrollbars is wrong anyway: you're trying to build the entire infrastructure from scratch! Consider using a GtkScrolledWindow instead. This automatically takes care of all the details of scrolling for you, and will give you the overlay scrollbars I mentioned. All you need to do is set the size of the GtkDrawingArea to the size you want it to be, and GtkScrolledWindow will do the rest. The best way to do this is to subclass GtkDrawingArea and override the get_preferred_height() and/or get_preferred_width() virtual functions (being sure to set both minimum and natural sizes to the sizes you want for that particular dimension). If you ever need to change this size later, call the queue_resize() method of GtkWidget. (You probably could get away with just using set_size_request(), but what I described is the preferred way of doing this.) Doing this also gives you the advantage of not having to worry about transforming your cairo coordinates; GtkScrolledWindow does this for you.

Erasing parts of a bitmap in EaselJS using destination-out compositing

I'm having a bit of difficulty getting some functionality to work. I'm trying to create an eraser and erase parts of an image using easelJS. I've seen other people do this, but only erasing other graphics - and when I try to erase an image, I can't get anything to work. If I wanted to erase a bitmap instead of other graphics, is that possible?
I also tried to use the AlphaMaskFilter, but it's giving me the exact opposite of what I'm looking for (it's masking everything, and only revealing what I paint).
var c = createjs, stage, art;
var x, y, listener, color, hue=0;
stage = new c.Stage("test");
var testImg = new c.Bitmap("http://lorempixel.com/output/animals-q-c-640-480-5.jpg");
art = stage.addChild(testImg, new c.Shape());
art.cache(0,0,600,400);
stage.on("stagemousedown", startDraw, this);
function startDraw(evt) {
listener = stage.on("stagemousemove", draw, this);
stage.on("stagemouseup", endDraw, this);
color = c.Graphics.getHSL(hue+=85, 50, 50);
x = evt.stageX-0.001; // offset so we draw an initial dot
y = evt.stageY-0.001;
draw(evt); // draw the initial dot
}
function draw(evt) {
art.graphics.ss(20,1).s(color).mt(x,y).lt(evt.stageX, evt.stageY);
// the composite operation is the secret sauce.
// we'll either draw or erase what the user drew.
art.updateCache(erase.checked ? "destination-out" : "source-over");
art.graphics.clear();
x = evt.stageX;
y = evt.stageY;
stage.update();
}
function endDraw(evt) {
stage.off("stagemousemove", listener);
evt.remove();
}
http://jsfiddle.net/17xec9y5/8/
Your example is only affecting the Shape instance that you have cached. When you use multiple arguments in addChild(), it returns the last added item, so in your sample, the art variable just references the shape. So the image is just below the "painted area" that you are drawing to.
To fix this, create and cache a container instead. A few minor additions:
Once the image loads, update the cache one time (to apply the image).
Then remove the image so it is no longer applied every time you update the cache while drawing.
That's it!
Here is a fiddle:
http://jsfiddle.net/lannymcnie/17xec9y5/9/
Relevant Code:
// Listen for the image load
testImg.image.onload = function() {
cont.updateCache("source-over"); // Update cache once
cont.removeChild(testImg); // Remove image
stage.update(); // Draw the stage to see the image
}
// Create a sub-container that will hold the art and image
var cont = stage.addChild(new c.Container());
art = new c.Shape(); // Art is just the shape
cont.cache(0,0,600,400); // Cache the container instead
cont.addChild(testImg, art);
// Then, later update the container's cache (instead of the art)
cont.updateCache(erase.checked ? "destination-out" : "source-over");