For the purpose of mine gstreamer application I tought about simple loader before I give a handle of DrawingArea widget to sink element.The basic idea was to load an animated .gif inside Gtk.DrawingArea but I run on the problem with documentation.I found out about PixbufAnimation and I used it with Gtk.Image widget but the same logic doesn't work for Gtk.DrawingArea and since it doesn't have add method I don't know what to do so as my last resort I came here to get a help.
This is what I did with Gtk.Image:
from gi.repository import Gdk,Gtk,GdkPixbuf
class animatedWin(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self,width_request=640,height_request=480)
self.canvas=Gtk.Image()
self.add(self.canvas)
self.load_file()
self.connect("delete-event",self.Gtk.main_quit)
def load_file(self):
self.loader=GdkPixbuf.PixbufAnimation.new_from_file("loader.gif")
self.canvas.set_from_animation(self.loader)
app=animatedWin()
app.show_all()
Gtk.main()
is it possible to achieve the same thing with DrawingArea ?
DrawingArea like most widgets in gtk3 uses cairo for drawing on them. Cairo draws on surfaces using context. You can convert pixbuf into surface by
public Surface Gdk.cairo_surface_create_from_pixbuf (Pixbuf pixbuf, int scale, Window? for_window)
And back by
public Pixbuf? Gdk.pixbuf_get_from_surface (Surface surface, int src_x, int src_y, int width, int height)
(taken from valadoc.org)
Example code snippet from my drawing app (I'm learning Vala while I writing it, so it may not be best implementation):
private void on_scale (Gtk.Button button) { // on button press
var my_pixbuf = Gdk.pixbuf_get_from_surface (this.buf_surface, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
var tmp_surface = Gdk.cairo_surface_create_from_pixbuf (my_pixbuf, 2, null);
var ctx = this.ccc; //this.ccc is context of drawing surface
ctx.set_source_surface (tmp_surface, 0, 0);
ctx.paint();
drawing_area.queue_draw(); // ask drawing_area to redraw, on redraw I have function/method that will paint drawing_area widget surface with drawing surface
}
PS. see http://valadoc.org/#!api=cairo/Cairo for more info on cairo. As I see it, cairo used for vector graphics and pixbuf for raster.
Related
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.
I've been working on switching my applications from Swing to JavaFX. I've been working on a room escape game which displays a description of the item on which the user clicks. In Swing, I'd subclass JComponent and override the paintComponent(Graphics) method. I could draw the text there, knowing that the method is constantly called to update the screen. However, using the JavaFX Canvas, there is no method that is called constantly, which makes this task harder. I attempted save()ing the GraphicsContext after I drew the images and called restore() when I wanted to remove the text, but to no avail. Here's the important code:
package me.nrubin29.jescape;
import javafx.application.Platform;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.shape.Rectangle;
import java.util.Timer;
import java.util.TimerTask;
public class RoomPane extends Canvas {
private Room room;
private Toast toast;
public RoomPane() {
super(640, 480);
setOnMouseClicked(e -> {
for (JObject o : room.getObjects()) {
if (o.getBounds().contains(e.getX(), e.getY())) {
toast = new Toast(o.getDescription());
}
}
});
new Timer().schedule(new TimerTask() {
#Override
public void run() {
if (toast == null) {
return;
}
if (toast.decrement()) { // Decrements the internal counter. If the count is 0, this method returns true.
toast = null;
Platform.runLater(() -> getGraphicsContext2D().restore());
}
else {
Platform.runLater(() -> getGraphicsContext2D().strokeText(toast.getText(), 300, 100));
}
}
}, 0, 1000);
}
public void changeRoom(Room room) {
this.room = room;
GraphicsContext g = getGraphicsContext2D();
g.drawImage(room.getBackground(), 0, 0);
for (JObject o : room.getObjects()) {
g.drawImage(o.getImage(), getCenterX(o.getBounds()), getCenterY(o.getBounds()));
}
g.save();
}
}
I attempted save()ing the GraphicsContext after I drew the images and called restore() when I wanted to remove the text, but to no avail.
save and restore have nothing to with removing things like text, what they do is save in a stack the state of various settings like a stroke or fill to use to draw shapes and allow them to be popped off the stack for application later. Those routines don't effect the pixels drawn on the canvas at all.
To remove something from a GraphicsContext, you can either draw over the of it, or clear it. For your code, what you could do is snapshot the canvas node where you are trying to save it, then draw your snapshot image onto the canvas where you are trying to restore it. It is probably not the most efficient way of handling drawing (a smarter routine which just draws only damaged area where the text is would be better, but probably not required for your simple game).
However, using the JavaFX Canvas, there is no method that is called constantly
Rather than using a timer to trigger canvas calls, use a AnimationTimer or a Timeline. The AnimationTimer has a callback method which is invoked every pulse (60 times a second, or as fast as JavaFX can render frames, whichever is the lesser), so it gives you an efficient hook into the JavaFX pulse based rendering system. The Timeline can have keyframes which are invoked at user specified durations and each keyframe can have an event handler callback which is invoked at that duration.
Using the built-in JavaFX animation framework, you don't have to worry about multi-threading issues and doing things like Platform.runLater which overly complicate your code and can easily lead to subtle and serious errors.
On a kind of unrelated note, for a simple game like this, IMO you are probably better off recoding it completely to use the JavaFX scene graph rather than a canvas. That way you will be working at a higher level of abstraction rather than clip areas and repainting damaged paint components.
I just wanted to ask what is the proper way to create and display a view on Unity. I'm just a beginner on this and just watched recently tutorials on how to script and learned about creating GUI on the fly which includes buttons, edit text boxes and other view but not sure on how should I really implement it the way it is optimized and won't affect the applications performance. What I tried so far is to create an editText wherein I set it on the MainCamera for display which is I targeted to be reusable so that in case I need to add more editText on the app I can just drag and drop the script. Here's the code so far:
using UnityEngine;
using System.Collections;
public class EditText : MonoBehaviour {
public int width = 150;
public int height = 25;
public int x_position = 0;
public int y_position = 0;
public string text = "Hello World";
public Position position = Position.unset;
public int text_size = 15;
public enum Position{unset,center_screen, center_vertical, center_horizontal};
void OnGUI () {
setPosition ();
GUI.skin.textArea.fontSize = text_size;
GUI.color = Color.red;
}
private void setPosition(){
switch (position) {
case Position.center_screen:
GUI.TextArea (new Rect (Screen.width/2 - width/2, Screen.height/2 - height/2, width, height), text);
GUI.backgroundColor = Color.white;
break;
case Position.center_vertical:
GUI.TextArea (new Rect (x_position, Screen.height/2 - height/2, width, height), text);
GUI.backgroundColor = Color.white;
break;
case Position.center_horizontal:
GUI.TextArea (new Rect (Screen.width/2 - width/2, y_position, width, height), text);
GUI.backgroundColor = Color.white;
break;
default:
GUI.TextArea (new Rect (x_position, y_position, width, height), text);
GUI.backgroundColor = Color.white;
break;
}
}
}
Question is am I doing this right or should I stop and use other implementation? Since I really intended it to be as reusable just like the Android Views. Also if there is any other library or scripts I can use to achieve this so that I'm not reinventing the wheel for this?
On the side note I also searched the NGUI although I'm not that sure on if this will fit my needs or not. Since when I tried creating a UILabel the component has only few options where I am not really sure on how I supposed to use it.
Question: Am I doing this right or should I stop and use other implementation?
It depends. Your implementation is simple but working. If you need more fancy UI, you might consider:
NGUI
NoesisGUI
Unity 4.6+ or Unity 5
According to Unity official blog, the "new GUI system is getting really close and it’ll be included in Unity 4.6, which will also be the last major update in the Unity 4 cycle".
I would prefer the last one, Unity 4.6 or Unity 5, as it is free and official from Unity, and the support and community are the big asset for you!
For your current implementation, I think you can make it even better, without using:
GUI.TextArea (new Rect (...)); // Not the best way
Instead try using:
GUILayout.BeginHorizontal ();
{
GUILayout.FlexibleSpace ();
//label etc., this guarantees centered in your UI and resolution independent.
GUILayout.XXX (...);
GUILayout.FlexibleSpace ();
}
GUILayout.EndHorizontal ();
Interesting links:
http://docs.unity3d.com/ScriptReference/GUILayout.html
GUI Layout tutorial
Unity's GUI system is far from perfect, but it's being improved incrementally. It's a good solution for interfaces with few simple elements. When using Unity's GUI system, i've generally set up each menu or 'display' separately. I never designed the UI elements in a modular fashion in the Unity system. I've not been in a situation where setting the 'Rect' of an element hasn't met my needs of manipulation. I can't say much about the performance of Unity's GUI system apart from that i've never noticed it's impact.
NGUI, like Unity is designed to be modular. To create the ui element that you desire might require you to piece together various scripts. For example an input field would require UILabel, UIInput script and a BoxCollider. Using all the scripts included in NGUI i've been able to create some pretty impressive interface prefabs. Being able to structure my interface visually in the scene view has been helpful as well.
These are the two UI systems i've used and have found uses for both.
I'm looking for best solution - I'm drawing a hexagonal map (Civilization like :) ) for my browser based game in GWT. Currently I'm drawing it on canvas which basically works.
However - I'm also able to slide map left,right,down and up to see another fragment of the map. In such situation I'm forced to redraw the whole map - which doesn't look too good, and will probaly cause preformance issues when the map gets more complex.
Is there a better approach for that? Some library? Or maybe I should make every hex a button like widget. so I could be able to move it instead creating from the scratch... but what about different resolutions then... I'm affraid the map could tear apart sometimes...
You could try doing it will simple DIVs (FlowPanel, HTMLPanel, etc) and style the hexagons using CSS. See this tutorial: http://jtauber.github.com/articles/css-hexagon.html
There are some neat suggestions here as well: html/css hexagon with image inside and hexagonal shaped cells in html
You could draw the entire map (usually just the relatively static background, not the animations!) in a hidden canvas, and then copy the parts you need to your visible canvas:
final Canvas hiddenCanvas = buildCanvas(1000, 1000);
drawHexPattern(hiddenCanvas);
// don't add the hiddenCanvas to your DOM
final Canvas visibleCanvas = buildCanvas(320, 200);
RootPanel.get().add(visibleCanvas); // add the visibleCanvas to the DOM
showArea(hiddenCanvas, visibleCanvas, 0, 0);
...
showArea(hiddenCanvas, visibleCanvas, 20, 10);
...
With a showArea() method like
private void showArea(final Canvas hiddenCanvas, final Canvas visibleCanvas,
final double x, final double y) {
final Context2d hiddenCtx = hiddenCanvas.getContext2d();
final Context2d visibleCtx = visibleCanvas.getContext2d();
final ImageData imageData = hiddenCtx.getImageData(x, y,
visibleCanvas.getCoordinateSpaceWidth(),
visibleCanvas.getCoordinateSpaceHeight());
visibleCtx.putImageData(imageData, 0, 0);
}
I created a pastebin with a working example: http://pastebin.com/tPN2093a
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);