This package provides an interactive canvas, on which the user can put items, move them with the mouse, etc. The items can be connected together, and the connections remain active while the items are moved.
It also supports scrolling if put in a Gtk_Scrolled_Window. The canvas will be scrolled (and the selected items moved) if an item is selected and the mouse is dragged on a small area on the side of the canvas or even directly outside of the canvas. Scrolling will continue until the mouse is either released or moved back inside the canvas.
The scrolling speed will slightly increase over time if the mouse is kept outside of the canvas. This makes the canvas much more comfortable to use for the user.
All items put in this canvas must inherit from the type Canvas_Item_Record. However, it is your responsability, as a programmer, to provide drawing routines. In fact, all these items should draw in a pixmap, which is then copied automatically to the screen whenever the canvas needs to redraw itself.
The items can also react to mouse events: mouse clicks are transmitted to the item if the mouse did not move more than a given amount of pixels. To decide what their reaction should be, you should override the On_Button_Click subprogram.
This canvas is not intended for cases where you want to put hundreds of items on the screen. For instance, it does not provide any smart double-buffering other than the one provided by gtk+ itself, and thus you would get some flicker if there are too many items.
There are three coordinate systems used by widget. All the subprograms expect a specific coordinate system as input or output. Here are the three systems:
Signals |
---|
procedure Handler (Canvas : access Interactive_Canvas_Record'Class;
Event : Gdk.Event.Gdk_Event);
Called every time the user clicks in the background (ie not on an item, or On_Button_Click would be called). This is called both on Button_Release and Button_Press events. The coordinates (X, Y) in the Event are relative to the top-left corner of Canvas.
procedure Handler (Canvas : access Interactive_Canvas_Record'Class;
Item : Canvas_Item);
Emitted when Item has been moved. New coordinates have been assigned to Item. However, the canvas hasn't been refreshed yet. This signal might be called multiple time when the user finishes a drag action, in case there were several selected items.
procedure Handler (Canvas : access Interactive_Canvas_Record'Class;
Item : Canvas_Item);
Emitted when the user has clicked on an item to select it, ie before any drag even has occured. This is a good time to add other items to the selection if you need. At thee same time, the primitive operation Selected is called for the item.
procedure Handler (Canvas : access Interactive_Canvas_Record'Class;
Item : Canvas_Item);
Emitted when the Item was unselected. At the same time, the primitive operation Selected is called for the item.
procedure Handler (Canvas : access Interactive_Canvas_Record'Class);
Emitted when the canvas has been zoomed in or out. You do not need to redraw the items yourself, since this will be handled by calls to Draw
Types |
---|
| |
Indicate whether the links have an arrow or not.
| |
| |
| |
| |
Each side of an item, along its rectangle bounding box
| |
| |
| |
| |
Subprograms |
---|
Creating a canvas | ||
procedure Gtk_New (Canvas : out Interactive_Canvas; Auto_Layout : Boolean := True); | ||
Create a new empty Canvas. If Auto_Layout is True, then the items are automatically positioned as they are put in the canvas, if no coordinates are specified. | ||
procedure Configure (Canvas : access Interactive_Canvas_Record; Grid_Size : Glib.Guint := Default_Grid_Size; Annotation_Font : Pango.Font.Pango_Font_Description := Pango.Font.From_String (Default_Annotation_Font); | ||
function Get_Vadj (Canvas : access Interactive_Canvas_Record'Class) return Gtk.Adjustment.Gtk_Adjustment; | ||
Return the vertical adjustment associated with Canvas | ||
function Get_Hadj (Canvas : access Interactive_Canvas_Record'Class) return Gtk.Adjustment.Gtk_Adjustment; | ||
Return the horizontal adjustment associated with Canvas | ||
procedure Draw_Area (Canvas : access Interactive_Canvas_Record'Class; Rect : Gdk.Rectangle.Gdk_Rectangle); | ||
Draw in Canvas the specified area. | ||
procedure Draw_Background (Canvas : access Interactive_Canvas_Record; Screen_Rect : Gdk.Rectangle.Gdk_Rectangle); | ||
Draw the background of the canvas. This procedure should be overriden if you want to draw something else on the background. It must first clear the area on the screen. Screen_Rect is the rectangle on the screen that needs to be refreshed. These are canvas coordinates, therefore you must take into account the current zoom level while drawing. The default implementation draws a grid. An example implementation that draws a background image is shown at the end of this file. | ||
procedure Draw_Grid (Canvas : access Interactive_Canvas_Record; GC : Gdk.GC.Gdk_GC; Screen_Rect : Gdk.Rectangle.Gdk_Rectangle); | ||
Helper function that can be called from Draw_Background. It cannot be used directly as Draw_Background, since it doesn't clear the area first. | ||
procedure Set_Orthogonal_Links (Canvas : access Interactive_Canvas_Record; Orthogonal : Boolean); | ||
If Orthogonal is True, then all the links will be drawn only with vertical and horizontal lines. This is not applied for the second or more link between two items. | ||
function Get_Orthogonal_Links (Canvas : access Interactive_Canvas_Record) return Boolean; | ||
Return True if the links are only drawn horizontally and vertically. | ||
procedure Align_On_Grid (Canvas : access Interactive_Canvas_Record; Align : Boolean := True); | ||
Choose whether the items should be aligned on the grid when moved. Existing items are not moved even if you set this parameter to True, this will only take effect the next time the items are moved. | ||
function Get_Align_On_Grid (Canvas : access Interactive_Canvas_Record) return Boolean; | ||
Return True if items are currently aligned on grid. | ||
procedure Move_To (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class; X, Y : Glib.Gint := Glib.Gint'First); | ||
Move the item in the canvas, to world coordinates (X, Y). Item is assumed to be already in the canvas. If you leave both coordinates X and Y to their default value, then the item's location will be automatically computed when you layout the canvas (it is your responsability to call Layout). | ||
procedure Set_Items (Canvas : access Interactive_Canvas_Record; Items : Glib.Graphs.Graph); | ||
Set the items and links to display in the canvas from Items. All items previously in the canvas are removed, and replaced by the vertices in Items. Note that the vertices in Items must be in Canvas_Item_Record'Class, and the links must be in Canvas_Link_Record'Class. If you do not have an automatic layout set up in Canvas, you need to set the coordinates of all the vertices by calling Move_To separately. You mustn't destroy items yourself, this is done automatically when the canvas is destroyed. | ||
procedure Put (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class; X, Y : Glib.Gint := Glib.Gint'First); | ||
Add a new item to the canvas, at world coordinates (X, Y). The item is added at a specific location. If you leave both X and Y to their default value, the item's location will be computed automatically when you call Layout on the canvas, unless Auto_Layout has been set, in which case the position will be computed immediately. | ||
function Item_At_Coordinates (Canvas : access Interactive_Canvas_Record; X, Y : Glib.Gint) return Canvas_Item; | ||
Return the item at world coordinates (X, Y) which is on top of all others. null is returned if there is no such item. | ||
function Item_At_Coordinates (Canvas : access Interactive_Canvas_Record; Event : Gdk.Event.Gdk_Event) return Canvas_Item; | ||
Same as above, but using the canvas coordinates of the event, taking into account the current zoom level and current scrolling | ||
procedure Remove (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class); | ||
Remove an item and all the links to and from it from the canvas. The item itself is not freed, but the links are. Nothing is done if the item is not part of the canvas. | ||
procedure Item_Updated (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class); | ||
This should be called when Item has changed the contents of its pixmap, and thus the Canvas should be updated. | ||
procedure Refresh_Canvas (Canvas : access Interactive_Canvas_Record); | ||
Redraw the whole canvas (both in the double buffer and on the screen). | ||
procedure Raise_Item (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class); | ||
Raise the item so that it is displayed on top of all the others The canvas is refreshed as needed to reflect the change. Nothing happens if Item is not part of the canvas. | ||
procedure Lower_Item (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class); | ||
Lower the item so that it is displayed below all the others. The canvas is refreshed as needed to reflect the change. Nothing happens if Item is not part of the canvas. | ||
function Is_On_Top (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class) return Boolean; | ||
Return True if Item is displayed on top of all the others in the canvas. | ||
procedure Show_Item (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class); | ||
Scroll the canvas so that Item is visible. Nothing is done if the item is already visible | ||
procedure Align_Item (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class; X_Align : Float := 0.5; Y_Align : Float := 0.5); | ||
Scroll the canvas so that the Item appears at the given location in the canvas. If X_Align is 0.0, the item is align on the left. With 0.5, it is centered horizontally. If 1.0, it is aligned on the right. | ||
function Get_Arrow_Angle (Canvas : access Interactive_Canvas_Record'Class) return Float; | ||
Return the angle of arrows in the canvas. | ||
function Get_Arrow_Length (Canvas : access Interactive_Canvas_Record'Class) return Glib.Gint; | ||
Return the length of arrows in the canvas. | ||
Iterating over items | ||
procedure For_Each_Item (Canvas : access Interactive_Canvas_Record; Execute : Item_Processor; Linked_From_Or_To : Canvas_Item := null); | ||
Execute an action on each of the items contained in the canvas. If Execute returns False, we stop traversing the list of children. It is safe to remove the items in Item_Processor. If Linked_From_Or_To is not null, then only the items linked to this one will be processed. It is possible that a given item will be returned twice, if it is both linked to and from the item. | ||
function Start (Canvas : access Interactive_Canvas_Record; Linked_From_Or_To : Canvas_Item := null) return Item_Iterator; | ||
Return the first item in the canvas. The same restriction as above applies if Linked_From_Or_To is not null. | ||
procedure Next (Iter : in out Item_Iterator); | ||
Move the iterator to the next item. All items will eventually be returned if you do not add new items during the iteration and none are removed. However, it is safe to remove items at any time, except the current item | ||
function Get (Iter : Item_Iterator) return Canvas_Item; | ||
Return the item pointed to by the iterator. null is returned when there are no more item in the canvas. | ||
function Is_Linked_From (Iter : Item_Iterator) return Boolean; | ||
Return True if there is a link from: Get (Iter) -> Linked_From_Or_To Linked_From_Or_To is the item passed to Start. False is returned if this item was null. | ||
Zooming | ||
procedure Zoom (Canvas : access Interactive_Canvas_Record; Percent : Glib.Guint := 100; Steps : Glib.Guint := 1); | ||
Zoom in or out in the canvas. Steps is the number of successive zooms that will be done to provide smooth scrolling. Note that one possible use for this function is to refresh the canvas and emit the "zoomed" signal, which might redraw all the items. This can be accomplished by keeping the default 100 value for Percent. | ||
function Get_Zoom (Canvas : access Interactive_Canvas_Record) return Glib.Guint; | ||
Return the current zoom level | ||
function To_Canvas_Coordinates (Canvas : access Interactive_Canvas_Record'Class; X : Glib.Gint) return Glib.Gint; | ||
Scale the scalar X depending by the zoom level (map from world coordinates to canvas coordinates). Substract the coordinates of the top-left corner if you are converting coordinates instead of lengths. | ||
function Top_World_Coordinates (Canvas : access Interactive_Canvas_Record'Class) return Glib.Gint; | ||
Return the world coordinates for the y=0 canvas coordinates (ie for the upper-left corner). | ||
function Left_World_Coordinates (Canvas : access Interactive_Canvas_Record'Class) return Glib.Gint; | ||
Return the world coordinates for the x=0 canvas coordinates (ie for the upper-left corner). | ||
function To_World_Coordinates (Canvas : access Interactive_Canvas_Record'Class; X : Glib.Gint) return Glib.Gint; | ||
Scale the scalar X depending by the zoom level (map from canvas coordinates to world coordinates) | ||
procedure Get_World_Coordinates (Canvas : access Interactive_Canvas_Record'Class; X, Y : out Glib.Gint; Width : out Glib.Gint; Height : out Glib.Gint); | ||
Return the world coordinates of Canvas. | ||
Layout of items | ||
procedure Set_Layout_Algorithm (Canvas : access Interactive_Canvas_Record; Algorithm : Layout_Algorithm); | ||
Set the layout algorithm to use to compute the position of the items. Algorithm mustn't be null. | ||
procedure Default_Layout_Algorithm (Canvas : access Interactive_Canvas_Record'Class; Graph : Glib.Graphs.Graph; Force : Boolean; Vertical_Layout : Boolean); | ||
The default algorithm used in the canvas. Basically, items are put next to each other, unless there is a link between two items. In that case, the second item is put below the first, as space allows. | ||
procedure Set_Auto_Layout (Canvas : access Interactive_Canvas_Record; Auto_Layout : Boolean); | ||
If Auto_Layout is true, then every time an item is inserted in the canvas, the layout algorithm is called. If set to False, it is the responsability of the caller to call Layout below to force a recomputation of the layout, preferably after inserting a number of items. | ||
procedure Set_Layout_Orientation (Canvas : access Interactive_Canvas_Record; Vertical_Layout : Boolean := False); | ||
Specify the layout orientation to use for this canvas. The setting is passed as a parameter to the layout algorithm | ||
procedure Layout (Canvas : access Interactive_Canvas_Record; Force : Boolean := False); | ||
Recompute the layout of the canvas. Force can be used to control the layout algorithm, as described above for Layout_Algorithm. | ||
Links | ||
procedure Configure (Link : access Canvas_Link_Record; Arrow : in Arrow_Type := End_Arrow; Descr : in Glib.UTF8_String := ""); | ||
Configure a link. The link is an oriented bound between two items on the canvas. If Descr is not the empty string, it will be displayed in the middle of the link, and should indicate what the link means. Arrow indicates whether some arrows should be printed as well. | ||
function Get_Descr (Link : access Canvas_Link_Record) return Glib.UTF8_String; | ||
Return the description for the link, or "" if there is none | ||
function Get_Arrow_Type (Link : access Canvas_Link_Record) return Arrow_Type; | ||
Return the location of the arrows on Link | ||
procedure Set_Src_Pos (Link : access Canvas_Link_Record; X_Pos, Y_Pos : Glib.Gfloat := 0.5); | ||
Set the position of the link's attachment in its source item. X_Pos and Y_Pos should be given between 0.0 and 1.0 (from left to right or top to bottom).. By default, all links are considered to be attached to the center of items. However, in some cases it is more convenient to attach it to a specific part of the item. For instance, you can force a link to always start from the top of the item by setting Y_Pos to 0.0. | ||
procedure Set_Dest_Pos (Link : access Canvas_Link_Record; X_Pos, Y_Pos : Glib.Gfloat := 0.5); | ||
Same as Set_Src_Pos for the destination item | ||
procedure Get_Src_Pos (Link : access Canvas_Link_Record; X, Y : out Glib.Gfloat); | ||
Return the attachment position of the link along its source item | ||
procedure Get_Dest_Pos (Link : access Canvas_Link_Record; X, Y : out Glib.Gfloat); | ||
Return the attachment position of the link along its destination item | ||
function Has_Link (Canvas : access Interactive_Canvas_Record; From, To : access Canvas_Item_Record'Class; Name : Glib.UTF8_String := "") return Boolean; | ||
Test whether there is a link from From to To, with the same name. If Name is the empty string "", then no check is done on the name, and True if returned if there is any link between the two items. | ||
procedure Add_Link (Canvas : access Interactive_Canvas_Record; Link : access Canvas_Link_Record'Class; Src : access Canvas_Item_Record'Class; Dest : access Canvas_Item_Record'Class; Arrow : in Arrow_Type := End_Arrow; Descr : in Glib.UTF8_String := ""); | ||
Add Link in the canvas. This connects the two items Src and Dest. Simpler procedure to add a standard link. This takes care of memory allocation, as well as adding the link to the canvas. | ||
procedure Remove_Link (Canvas : access Interactive_Canvas_Record; Link : access Canvas_Link_Record'Class); | ||
Remove a link from the canvas. It also destroys the link itself, and free the memory allocated to it. Nothing is done if Link does not belong to canvas. | ||
procedure For_Each_Link (Canvas : access Interactive_Canvas_Record; Execute : Link_Processor; From, To : Canvas_Item := null); | ||
Execute an action on each of the links contained in the canvas. If Execute returns False, we stop traversing the list of links. It is safe to remove the link from the list in Link_Processor. (From, To) can be used to limit what links are looked for. ??? Would be nicer to give direct access to the Graph iterators | ||
procedure Destroy (Link : in out Canvas_Link_Record); | ||
Method called every time a link is destroyed. You should override this if you define your own link types. Note that the link might already have been removed from the canvas when this subprogram is called. This shouldn't free the link itself, only its fields. | ||
Drawing links | ||
Drawing of links can be controlled at several levels:
| ||
procedure Update_Links (Canvas : access Interactive_Canvas_Record; GC : Gdk.GC.Gdk_GC; Invert_Mode : Boolean; From_Selection : Boolean); | ||
Redraw all the links in the canvas, after the items have been laid out. GC is a default graphic context that can be used for drawing. However, any other graphic context will do. If Invert_Mode is true, this graphic context must draw in xor mode. If From_Selection is true, then only the links to or from one of the selected items need to be drawn. | ||
procedure Draw_Link (Canvas : access Interactive_Canvas_Record'Class; Link : access Canvas_Link_Record; Invert_Mode : Boolean; GC : Gdk.GC.Gdk_GC; Edge_Number : Glib.Gint); | ||
Redraw the link on the canvas. Note that this is a primitive procedure of Link, not of Canvas, and thus can easily be overrided for specific links. The default version draws either straight or arc links (the latter when there are multiple links between two given items). This function shouldn't be called if one of the two ends of the link is invisible. The link should be drawn directly in Get_Window (Canvas). GC is a possible graphic context that could be used to draw the link. You shouldn't destroy it or modify its attributes. However, you can use any other graphic context specific to your application, for instance if you want to draw the link in various colors or shapes. The graphic context you use must be in Invert mode (see Gdk.GC.Set_Function) if and only if Invert_Mode is true, so that when items are moved on the canvas, the links properly follow the items they are attached to. This graphic context is only used to draw links, so you don't need to restore it on exit if your Draw_Link function always sets it at the beginning. Edge_Number indicates the index of link in the list of links that join the same source to the same destination. It should be used so that two links do not overlap (for instance, the default is to draw the first link straight, and the others as arcs). | ||
procedure Clip_Line (Src : access Canvas_Item_Record; To_X : Glib.Gint; To_Y : Glib.Gint; X_Pos : Glib.Gfloat; Y_Pos : Glib.Gfloat; Side : out Item_Side; X_Out : out Glib.Gint; Y_Out : out Glib.Gint); | ||
Clip the line that goes from Src at pos (X_Pos, Y_Pos) to (To_X, To_Y) in world coordinates. The intersection between that line and the border of Rect is returned in (X_Out, Y_Out). The result should be in world coordinates. X_Pos and Y_Pos have the same meaning as Src_X_Pos and Src_Y_Pos in the link record. This procedure is called when computing the position for the links within the default Draw_Link procedure. The default implementation only works with rectangular items. The computed coordinates are then passed on directly to Draw_Straight_Line. | ||
procedure Draw_Straight_Line (Link : access Canvas_Link_Record; Window : Gdk.Window.Gdk_Window; GC : Gdk.GC.Gdk_GC; Src_Side : Item_Side; X1, Y1 : Glib.Gint; Dest_Side : Item_Side; X2, Y2 : Glib.Gint); | ||
Draw a straight link between two points. This could be overriden if you need to draw an something along the link. The links goes from (Src, X1, Y1) to (Dest, X2, Y2), in canvas coordinates. The coordinates have already been clipped so that they do not override the item. | ||
Selection | ||
procedure Clear_Selection (Canvas : access Interactive_Canvas_Record); | ||
Clear the list of currently selected items. | ||
procedure Add_To_Selection (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class); | ||
Add Item to the selection. This is only meaningful during a drag operation (ie during a button press and the matching button release). Item will be moved at the same time that the selection is moved. Item is not added again if it is already in the selection. This function can be called from the Button_Click subprogram to force moving items. This emits the "item_selected" signal. | ||
procedure Remove_From_Selection (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class); | ||
Remove Item from the selection. This emits the "item_unselected" signal. | ||
procedure Select_All (Canvas : access Interactive_Canvas_Record); | ||
Select all the Item in the canvas. | ||
function Is_Selected (Canvas : access Interactive_Canvas_Record; Item : access Canvas_Item_Record'Class) return Boolean; | ||
Return True if the item is currently selected | ||
function Start (Canvas : access Interactive_Canvas_Record) return Selection_Iterator; | ||
Return the first selected item | ||
function Next (Iterator : Selection_Iterator) return Selection_Iterator; | ||
Move to the next selected item | ||
function Get (Iterator : Selection_Iterator) return Canvas_Item; | ||
Return the current item, or null if there is no more selected item. | ||
Items manipulation | ||
procedure Selected (Item : access Canvas_Item_Record; Canvas : access Interactive_Canvas_Record'Class; Is_Selected : Boolean); | ||
Called when the item is selected or unselected. The default is to do nothing | ||
function Point_In_Item (Item : access Canvas_Item_Record; X, Y : Glib.Gint) return Boolean; | ||
This function should return True if (X, Y) is inside the item. X and Y are in world coordinates. This function is meant to be overriden for non-rectangular items, since the default behavior works for rectangular items. This function is never called for invisible items | ||
procedure Set_Screen_Size (Item : access Canvas_Item_Record; Width : Glib.Gint; Height : Glib.Gint); | ||
Set the size of bounding box for the item in world coordinates. The item itself needn't occupy the whole area of this bounding box, see Point_In_Item. You need to redraw the item, and call Item_Updated to force the canvas to refresh the screen. | ||
procedure Draw (Item : access Canvas_Item_Record; Canvas : access Interactive_Canvas_Record'Class; GC : Gdk.GC.Gdk_GC; Xdest, Ydest : Glib.Gint); | ||
This subprogram, that must be overridden, should draw the item on Get_Pixmap (Canvas), at the specific location (Xdest, Ydest). The item must also be drawn at the appropriate zoom level. If you need to change the contents of the item, you should call Item_Updated after having done the drawing. | ||
procedure Destroy (Item : in out Canvas_Item_Record); | ||
Free the memory occupied by the item (not the item itself). You should override this function if you define your own widget type, but always call the parent's Destroy subprogram. | ||
procedure On_Button_Click (Item : access Canvas_Item_Record; Event : Gdk.Event.Gdk_Event_Button); | ||
Function called whenever the item was clicked on. Note that this function is not called when the item is moved, and thus is only called when the click was short. The coordinates (X, Y) in the Event are relative to the top-left corner of Item. | ||
function Get_Coord (Item : access Canvas_Item_Record) return Gdk.Rectangle.Gdk_Rectangle; | ||
Return the coordinates and size of the bounding box for item, in world coordinates. If the item has never been resized, it initially has a width and height of 1. | ||
procedure Set_Visibility (Item : access Canvas_Item_Record; Visible : Boolean); | ||
Set the visibility status of the item. An invisible item will not be visible on the screen, and will not take part in the computation of the the scrollbars for the canvas. The canvas is not refreshed (this is your responsibility to do it after you have finished doing all the modifications). | ||
function Is_Visible (Item : access Canvas_Item_Record) return Boolean; | ||
Return True if the item is currently visible. | ||
function Is_From_Auto_Layout (Item : access Canvas_Item_Record) return Boolean; | ||
Return True if the current location of the item is the result from the auto layout algorithm. False is returned if the item was moved manually by the user. | ||
Buffered items | ||
function Pixmap (Item : access Buffered_Item_Record) return Gdk.Pixmap.Gdk_Pixmap; | ||
Return the double-buffer. All the drawing on this pixmap must be done at zoom level 100% | ||
Signals | ||
procedure Set_Screen_Size (Item : access Buffered_Item_Record; Width, Height : Glib.Gint); | ||
See documentation from inherited subprogram | ||
procedure Draw (Item : access Buffered_Item_Record; Canvas : access Interactive_Canvas_Record'Class; GC : Gdk.GC.Gdk_GC; Xdest, Ydest : Glib.Gint); | ||
Draw the item's double-buffer onto Dest. | ||
procedure Destroy (Item : in out Buffered_Item_Record); | ||
Free the double-buffer allocated for the item |
Example |
---|
-- The following example shows a possible Draw_Background procedure, -- that draws a background image on the canvas's background. It fully -- handles zooming and tiling of the image. Note that drawing a large -- image will dramatically slow down the performances. Background : Gdk.Pixbuf.Gdk_Pixbuf := ...; procedure Draw_Background (Canvas : access Image_Canvas_Record; Screen_Rect : Gdk.Rectangle.Gdk_Rectangle) is X_Left : constant Glib.Gint := Left_World_Coordinates (Canvas); Y_Top : constant Glib.Gint := Top_World_Coordinates (Canvas); X, Y, W, H, Ys : Gint; Xs : Gint := Screen_Rect.X; Bw : constant Gint := Get_Width (Background) * Gint (Get_Zoom (Canvas)) / 100; Bh : constant Gint := Get_Height (Background) * Gint (Get_Zoom (Canvas)) / 100; Scaled : Gdk_Pixbuf := Background; begin if Get_Zoom (Canvas) /= 100 then Scaled := Scale_Simple (Background, Bw, Bh); end if; while Xs < Screen_Rect.X + Screen_Rect.Width loop Ys := Screen_Rect.Y; X := (X_Left + Xs) mod Bw; W := Gint'Min (Screen_Rect.Width + Screen_Rect.X- Xs, Bw - X); while Ys < Screen_Rect.Y + Screen_Rect.Height loop Y := (Y_Top + Ys) mod Bh; H := Gint'Min (Screen_Rect.Height + Screen_Rect.Y - Ys, Bh - Y); Render_To_Drawable (Pixbuf => Scaled, Drawable => Get_Window (Canvas), Gc => Get_Black_GC (Get_Style (Canvas)), Src_X => X, Src_Y => Y, Dest_X => Xs, Dest_Y => Ys, Width => W, Height => H); Ys := Ys + H; end loop; Xs := Xs + W; end loop; if Get_Zoom (Canvas) /= 100 then Unref (Scaled); end if; end Draw_Background;