Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
graph-tool
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
40
Issues
40
List
Boards
Labels
Service Desk
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tiago Peixoto
graph-tool
Commits
04572376
Commit
04572376
authored
Jun 15, 2015
by
Tiago Peixoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
GraphWidget: Implement progressive drawing to improve interactive responsiveness
parent
406d7c4a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
215 additions
and
92 deletions
+215
-92
src/graph/draw/graph_cairo_draw.cc
src/graph/draw/graph_cairo_draw.cc
+117
-31
src/graph_tool/draw/cairo_draw.py
src/graph_tool/draw/cairo_draw.py
+22
-7
src/graph_tool/draw/gtk_draw.py
src/graph_tool/draw/gtk_draw.py
+76
-54
No files found.
src/graph/draw/graph_cairo_draw.cc
View file @
04572376
...
...
@@ -28,8 +28,13 @@
#include "graph_properties.hh"
#include <iostream>
#include <array>
#include <chrono>
#include <unordered_map>
#ifdef HAVE_SPARSEHASH
#include SPARSEHASH_INCLUDE(dense_hash_map)
#endif
#include <cairommconfig.h>
#include <cairomm/context.h>
...
...
@@ -42,6 +47,10 @@ using namespace std;
using
namespace
boost
;
using
namespace
graph_tool
;
#ifdef HAVE_SPARSEHASH
using
google
::
dense_hash_map
;
#endif
enum
vertex_attr_t
{
VERTEX_SHAPE
=
100
,
VERTEX_COLOR
,
...
...
@@ -118,7 +127,11 @@ enum edge_marker_t {
typedef
pair
<
double
,
double
>
pos_t
;
typedef
std
::
tuple
<
double
,
double
,
double
,
double
>
color_t
;
typedef
std
::
unordered_map
<
int
,
boost
::
any
>
attrs_t
;
#ifdef HAVE_SPARSEHASH
typedef
dense_hash_map
<
int
,
boost
::
any
,
std
::
hash
<
int
>>
attrs_t
;
#else
typedef
std
::
unordered_map
<
int
,
boost
::
any
>
attrs_t
;
#endif
typedef
boost
::
mpl
::
map41
<
boost
::
mpl
::
pair
<
boost
::
mpl
::
int_
<
VERTEX_SHAPE
>
,
vertex_shape_t
>
,
...
...
@@ -411,7 +424,7 @@ public:
template
<
class
Value
>
Value
get
(
int
k
)
{
typeof
(
_attrs
.
begin
())
iter
=
_attrs
.
find
(
k
);
auto
iter
=
_attrs
.
find
(
k
);
if
(
iter
!=
_attrs
.
end
())
{
typedef
DynamicPropertyMapWrap
<
Value
,
Descriptor
,
Converter
>
pmap_t
;
...
...
@@ -777,6 +790,13 @@ public:
color_t
color
,
fillcolor
;
double
size
,
pw
,
aspect
;
size
=
get_size
(
cr
);
std
::
array
<
double
,
4
>
clip
;
cr
.
get_clip_extents
(
clip
[
0
],
clip
[
1
],
clip
[
2
],
clip
[
3
]);
if
((
_pos
.
first
+
2
*
size
<
clip
[
0
]
&&
_pos
.
second
+
2
*
size
<
clip
[
1
])
||
(
_pos
.
first
-
2
*
size
>
clip
[
2
]
&&
_pos
.
second
-
2
*
size
>
clip
[
3
]))
return
;
aspect
=
_attrs
.
template
get
<
double
>(
VERTEX_ASPECT
);
if
(
!
outline
)
...
...
@@ -997,7 +1017,7 @@ public:
EdgeShape
(
VertexShape
&
s
,
VertexShape
&
t
,
AttrDict
<
Descriptor
>
attrs
)
:
_s
(
s
),
_t
(
t
),
_attrs
(
attrs
)
{}
void
draw
(
Cairo
::
Context
&
cr
)
void
draw
(
Cairo
::
Context
&
cr
,
double
res
=
0.
)
{
pos_t
pos_begin
,
pos_end
;
...
...
@@ -1030,6 +1050,11 @@ public:
marker_size
=
get_user_dist
(
cr
,
marker_size
);
bool
sloppy
=
_attrs
.
template
get
<
uint8_t
>(
EDGE_SLOPPY
);
if
(
marker_size
<
get_user_dist
(
cr
,
res
))
{
sloppy
=
true
;
}
pos_begin
=
_s
.
get_pos
();
pos_end
=
_t
.
get_pos
();
...
...
@@ -1441,14 +1466,21 @@ private:
AttrDict
<
Descriptor
>
_attrs
;
};
template
<
class
Graph
,
class
VertexIterator
,
class
PosMap
>
void
draw_vertices
(
Graph
&
,
pair
<
VertexIterator
,
VertexIterator
>
v_range
,
template
<
class
Graph
,
class
VertexIterator
,
class
PosMap
,
class
Time
>
void
draw_vertices
(
Graph
&
,
pair
<
VertexIterator
,
VertexIterator
>
v_range
,
PosMap
pos_map
,
attrs_t
&
attrs
,
attrs_t
&
defaults
,
size_t
offset
,
Time
max_time
,
size_t
&
count
,
Cairo
::
Context
&
cr
)
{
typedef
typename
graph_traits
<
Graph
>::
vertex_descriptor
vertex_t
;
for
(
VertexIterator
v
=
v_range
.
first
;
v
!=
v_range
.
second
;
++
v
)
{
if
(
count
<
offset
)
{
count
++
;
continue
;
}
pos_t
pos
;
if
(
pos_map
[
*
v
].
size
()
>=
2
)
{
...
...
@@ -1457,18 +1489,29 @@ void draw_vertices(Graph&, pair<VertexIterator,VertexIterator> v_range,
}
VertexShape
<
vertex_t
>
vs
(
pos
,
AttrDict
<
vertex_t
>
(
*
v
,
attrs
,
defaults
));
vs
.
draw
(
cr
);
count
++
;
if
(
chrono
::
high_resolution_clock
::
now
()
>
max_time
)
break
;
}
}
template
<
class
Graph
,
class
EdgeIterator
,
class
PosMap
>
template
<
class
Graph
,
class
EdgeIterator
,
class
PosMap
,
class
Time
>
void
draw_edges
(
Graph
&
g
,
pair
<
EdgeIterator
,
EdgeIterator
>
e_range
,
PosMap
pos_map
,
attrs_t
&
eattrs
,
attrs_t
&
edefaults
,
attrs_t
&
vattrs
,
attrs_t
&
vdefaults
,
Cairo
::
Context
&
cr
)
attrs_t
&
vattrs
,
attrs_t
&
vdefaults
,
double
res
,
size_t
offset
,
Time
max_time
,
size_t
&
count
,
Cairo
::
Context
&
cr
)
{
typedef
typename
graph_traits
<
Graph
>::
vertex_descriptor
vertex_t
;
typedef
typename
graph_traits
<
Graph
>::
edge_descriptor
edge_t
;
for
(
EdgeIterator
e
=
e_range
.
first
;
e
!=
e_range
.
second
;
++
e
)
{
if
(
count
<
offset
)
{
count
++
;
continue
;
}
vertex_t
s
,
t
;
s
=
source
(
*
e
,
g
);
t
=
target
(
*
e
,
g
);
...
...
@@ -1486,7 +1529,10 @@ void draw_edges(Graph& g, pair<EdgeIterator, EdgeIterator> e_range,
}
if
(
spos
==
tpos
&&
t
!=
s
)
{
count
++
;
continue
;
}
VertexShape
<
vertex_t
>
ss
(
spos
,
AttrDict
<
vertex_t
>
(
s
,
vattrs
,
vdefaults
));
VertexShape
<
vertex_t
>
ts
(
tpos
,
AttrDict
<
vertex_t
>
(
t
,
vattrs
,
vdefaults
));
...
...
@@ -1494,7 +1540,11 @@ void draw_edges(Graph& g, pair<EdgeIterator, EdgeIterator> e_range,
EdgeShape
<
edge_t
,
VertexShape
<
vertex_t
>
>
es
(
ss
,
ts
,
AttrDict
<
edge_t
>
(
*
e
,
eattrs
,
edefaults
));
es
.
draw
(
cr
);
es
.
draw
(
cr
,
res
);
count
++
;
if
(
chrono
::
high_resolution_clock
::
now
()
>
max_time
)
break
;
}
}
...
...
@@ -1546,29 +1596,31 @@ struct ordered_range
struct
do_cairo_draw_edges
{
template
<
class
Graph
,
class
PosMap
,
class
EdgeOrder
>
void
operator
()(
Graph
&
g
,
PosMap
pos
,
EdgeOrder
edge_order
,
attrs_t
&
vattrs
,
attrs_t
&
eattrs
,
attrs_t
&
vdefaults
,
attrs_t
&
edefaults
,
Cairo
::
Context
&
cr
)
const
template
<
class
Graph
,
class
PosMap
,
class
EdgeOrder
,
class
Time
>
void
operator
()(
Graph
&
g
,
PosMap
pos
,
EdgeOrder
edge_order
,
attrs_t
&
vattrs
,
attrs_t
&
eattrs
,
attrs_t
&
vdefaults
,
attrs_t
&
edefaults
,
double
res
,
size_t
offset
,
Time
max_time
,
size_t
&
count
,
Cairo
::
Context
&
cr
)
const
{
ordered_range
<
typename
graph_traits
<
Graph
>::
edge_iterator
>
edge_range
(
edges
(
g
));
draw_edges
(
g
,
edge_range
.
get_range
(
edge_order
),
pos
,
eattrs
,
edefaults
,
vattrs
,
vdefaults
,
cr
);
draw_edges
(
g
,
edge_range
.
get_range
(
edge_order
),
pos
,
eattrs
,
edefaults
,
vattrs
,
vdefaults
,
res
,
offset
,
max_time
,
count
,
cr
);
}
};
struct
do_cairo_draw_vertices
{
template
<
class
Graph
,
class
PosMap
,
class
VertexOrder
>
template
<
class
Graph
,
class
PosMap
,
class
VertexOrder
,
class
Time
>
void
operator
()(
Graph
&
g
,
PosMap
pos
,
VertexOrder
vertex_order
,
attrs_t
&
vattrs
,
attrs_t
&
,
attrs_t
&
vdefaults
,
attrs_t
&
,
Cairo
::
Context
&
cr
)
const
attrs_t
&
vattrs
,
attrs_t
&
,
attrs_t
&
vdefaults
,
attrs_t
&
,
size_t
offset
,
Time
max_time
,
size_t
&
count
,
Cairo
::
Context
&
cr
)
const
{
ordered_range
<
typename
graph_traits
<
Graph
>::
vertex_iterator
>
vertex_range
(
vertices
(
g
));
draw_vertices
(
g
,
vertex_range
.
get_range
(
vertex_order
),
pos
,
vattrs
,
vdefaults
,
cr
);
vdefaults
,
offset
,
max_time
,
count
,
cr
);
}
};
...
...
@@ -1655,18 +1707,28 @@ struct populate_edge_attrs
};
void
cairo_draw
(
GraphInterface
&
gi
,
boost
::
any
pos
,
boost
::
any
vorder
,
boost
::
any
eorder
,
bool
nodesfirst
,
boost
::
python
::
dict
ovattrs
,
boost
::
python
::
dict
oeattrs
,
boost
::
python
::
dict
ovdefaults
,
boost
::
python
::
dict
oedefaults
,
boost
::
python
::
object
ocr
)
size_t
cairo_draw
(
GraphInterface
&
gi
,
boost
::
any
pos
,
boost
::
any
vorder
,
boost
::
any
eorder
,
bool
nodesfirst
,
boost
::
python
::
dict
ovattrs
,
boost
::
python
::
dict
oeattrs
,
boost
::
python
::
dict
ovdefaults
,
boost
::
python
::
dict
oedefaults
,
double
res
,
size_t
offset
,
int64_t
max_time
,
boost
::
python
::
object
ocr
)
{
attrs_t
vattrs
,
eattrs
,
vdefaults
,
edefaults
;
#ifdef HAVE_SPARSEHASH
vattrs
.
set_empty_key
(
numeric_limits
<
int
>::
max
());
eattrs
.
set_empty_key
(
numeric_limits
<
int
>::
max
());
vdefaults
.
set_empty_key
(
numeric_limits
<
int
>::
max
());
edefaults
.
set_empty_key
(
numeric_limits
<
int
>::
max
());
#endif
typedef
graph_traits
<
GraphInterface
::
multigraph_t
>::
vertex_descriptor
vertex_t
;
populate_attrs
<
vertex_t
,
vertex_properties
>
(
ovattrs
,
vattrs
);
...
...
@@ -1685,31 +1747,55 @@ void cairo_draw(GraphInterface& gi,
if
(
eorder
.
empty
())
eorder
=
no_order
();
size_t
count
=
0
;
auto
mtime
=
chrono
::
high_resolution_clock
::
now
();
if
(
max_time
<
0
)
mtime
=
chrono
::
high_resolution_clock
::
time_point
::
max
();
else
mtime
+=
chrono
::
milliseconds
(
max_time
);
Cairo
::
Context
cr
(
PycairoContext_GET
(
ocr
.
ptr
()));
if
(
nodesfirst
)
run_action
<
graph_tool
::
detail
::
always_directed
>
()
(
gi
,
std
::
bind
(
do_cairo_draw_vertices
(),
placeholders
::
_1
,
placeholders
::
_2
,
placeholders
::
_3
,
std
::
ref
(
vattrs
),
std
::
ref
(
eattrs
),
std
::
ref
(
vdefaults
),
std
::
ref
(
edefaults
),
std
::
ref
(
cr
)),
std
::
ref
(
edefaults
),
offset
,
mtime
,
std
::
ref
(
count
),
std
::
ref
(
cr
)),
vertex_scalar_vector_properties
(),
vorder_t
())(
pos
,
vorder
);
if
(
chrono
::
high_resolution_clock
::
now
()
>
mtime
)
return
count
;
run_action
<
graph_tool
::
detail
::
always_directed
>
()
(
gi
,
std
::
bind
(
do_cairo_draw_edges
(),
placeholders
::
_1
,
placeholders
::
_2
,
placeholders
::
_3
,
std
::
ref
(
vattrs
),
std
::
ref
(
eattrs
),
std
::
ref
(
vdefaults
),
std
::
ref
(
edefaults
),
std
::
ref
(
cr
)),
std
::
ref
(
vdefaults
),
std
::
ref
(
edefaults
),
res
,
offset
,
mtime
,
std
::
ref
(
count
),
std
::
ref
(
cr
)),
vertex_scalar_vector_properties
(),
eorder_t
())(
pos
,
eorder
);
if
(
!
nodesfirst
)
{
if
(
chrono
::
high_resolution_clock
::
now
()
>
mtime
)
return
count
;
run_action
<
graph_tool
::
detail
::
always_directed
>
()
(
gi
,
std
::
bind
(
do_cairo_draw_vertices
(),
placeholders
::
_1
,
placeholders
::
_2
,
placeholders
::
_3
,
std
::
ref
(
vattrs
),
std
::
ref
(
eattrs
),
std
::
ref
(
vdefaults
),
std
::
ref
(
edefaults
),
std
::
ref
(
cr
)),
std
::
ref
(
edefaults
),
offset
,
mtime
,
std
::
ref
(
count
),
std
::
ref
(
cr
)),
vertex_scalar_vector_properties
(),
vorder_t
())(
pos
,
vorder
);
}
if
(
chrono
::
high_resolution_clock
::
now
()
<
mtime
)
count
=
0
;
return
count
;
}
struct
do_apply_transforms
...
...
src/graph_tool/draw/cairo_draw.py
View file @
04572376
...
...
@@ -427,9 +427,9 @@ def parse_props(prefix, args):
def
cairo_draw
(
g
,
pos
,
cr
,
vprops
=
None
,
eprops
=
None
,
vorder
=
None
,
eorder
=
None
,
nodesfirst
=
False
,
vcmap
=
default_cm
,
ecmap
=
default_cm
,
loop_angle
=
float
(
"nan"
)
,
parallel_distance
=
None
,
fit_view
=
False
,
**
kwargs
):
nodesfirst
=
False
,
vcmap
=
default_cm
,
ecmap
=
default_cm
,
loop_angle
=
float
(
"nan"
),
parallel_distance
=
None
,
fit_view
=
False
,
res
=
0
,
render_offset
=
0
,
max_render_time
=-
1
,
**
kwargs
):
r
"""
Draw a graph to a :mod:`cairo` context.
...
...
@@ -474,6 +474,15 @@ def cairo_draw(g, pos, cr, vprops=None, eprops=None, vorder=None, eorder=None,
specify the view in user coordinates.
bg_color : str or sequence (optional, default: ``None``)
Background color. The default is transparent.
res : float (optional, default: ``0.``):
If shape sizes fall below this value, simplified drawing is used.
render_offset : int (optional, default: ``0``):
If supplied, the rendering will skip the specified initial amount of
vertices / edges.
max_render_time : int (optional, default: ``-1``):
Maximum allowed time (in milliseconds) for rendering. If exceeded, the
rendering will return unfinished. If negative values are given, the
rendering will always complete.
vertex_* : :class:`~graph_tool.PropertyMap` or arbitrary types (optional, default: ``None``)
Parameters following the pattern ``vertex_<prop-name>`` specify the
vertex property with name ``<prop-name>``, as an alternative to the
...
...
@@ -483,6 +492,11 @@ def cairo_draw(g, pos, cr, vprops=None, eprops=None, vorder=None, eorder=None,
property with name ``<prop-name>``, as an alternative to the ``eprops``
parameter.
Returns
-------
offset : int
The offset into the completed rendering. If this value is zero, the
rendering was complete.
"""
vprops
=
{}
if
vprops
is
None
else
copy
.
copy
(
vprops
)
...
...
@@ -551,11 +565,12 @@ def cairo_draw(g, pos, cr, vprops=None, eprops=None, vorder=None, eorder=None,
eprops
[
"control_points"
]
=
position_parallel_edges
(
g
,
pos
,
loop_angle
,
parallel_distance
)
g
=
GraphView
(
g
,
directed
=
True
)
libgraph_tool_draw
.
cairo_draw
(
g
.
_Graph__graph
,
_prop
(
"v"
,
g
,
pos
),
_prop
(
"v"
,
g
,
vorder
),
_prop
(
"e"
,
g
,
eorder
),
nodesfirst
,
vattrs
,
eattrs
,
vdefs
,
edefs
,
cr
)
count
=
libgraph_tool_draw
.
cairo_draw
(
g
.
_Graph__graph
,
_prop
(
"v"
,
g
,
pos
),
_prop
(
"v"
,
g
,
vorder
),
_prop
(
"e"
,
g
,
eorder
),
nodesfirst
,
vattrs
,
eattrs
,
vdefs
,
edefs
,
res
,
render_offset
,
max_render_time
,
cr
)
cr
.
restore
()
return
count
def
color_contrast
(
color
):
c
=
np
.
asarray
(
color
)
...
...
src/graph_tool/draw/gtk_draw.py
View file @
04572376
...
...
@@ -131,7 +131,8 @@ class GraphWidget(Gtk.DrawingArea):
eorder
=
None
,
nodesfirst
=
False
,
update_layout
=
False
,
layout_K
=
1.
,
multilevel
=
False
,
display_props
=
None
,
display_props_size
=
11
,
fit_area
=
0.95
,
bg_color
=
None
,
layout_callback
=
None
,
key_press_callback
=
None
,
**
kwargs
):
max_render_time
=
300
,
layout_callback
=
None
,
key_press_callback
=
None
,
**
kwargs
):
r
"""Interactive GTK+ widget displaying a given graph.
Parameters
...
...
@@ -169,6 +170,9 @@ class GraphWidget(Gtk.DrawingArea):
Fraction of the drawing area to fit the graph initially.
bg_color : str or sequence (optional, default: ``None``)
Background color. The default is white.
max_render_time : int (optional, default: ``300``)
Maximum amount of time (in milliseconds) spent rendering portions of
the graph.
layout_callback : function (optional, default: ``Node``)
User-supplied callback to be called whenever the positions of the layout
have changed. It needs to have the following signature:
...
...
@@ -260,6 +264,7 @@ class GraphWidget(Gtk.DrawingArea):
self
.
pointer
=
[
0
,
0
]
self
.
picked
=
False
self
.
selected
=
g
.
new_vertex_property
(
"bool"
)
self
.
sel_edge_filt
=
g
.
new_edge_property
(
"bool"
,
False
)
self
.
srect
=
None
self
.
drag_begin
=
None
self
.
moved_picked
=
False
...
...
@@ -275,7 +280,9 @@ class GraphWidget(Gtk.DrawingArea):
self
.
base_geometry
=
None
self
.
background
=
None
self
.
bg_color
=
bg_color
if
bg_color
is
not
None
else
[
1
,
1
,
1
,
1
]
self
.
surface_callback
=
None
self
.
regenerate_offset
=
0
self
.
regenerate_max_time
=
max_render_time
self
.
max_render_time
=
max_render_time
self
.
layout_callback_id
=
None
self
.
layout_K
=
layout_K
...
...
@@ -359,7 +366,7 @@ class GraphWidget(Gtk.DrawingArea):
self
.
layout_step
*=
0.9
if
self
.
vertex_matrix
is
not
None
:
self
.
vertex_matrix
.
update
()
self
.
regenerate_surface
(
lazy
=
Fals
e
)
self
.
regenerate_surface
(
reset
=
True
,
complete
=
Tru
e
)
self
.
queue_draw
()
ps
=
ungroup_vector_property
(
self
.
pos
,
[
0
,
1
])
delta
=
np
.
sqrt
((
pos_temp
[
0
].
fa
-
ps
[
0
].
fa
)
**
2
+
...
...
@@ -390,7 +397,7 @@ class GraphWidget(Gtk.DrawingArea):
adjust_default_sizes
(
self
.
g
,
geometry
,
self
.
vprops
,
self
.
eprops
,
force
=
True
)
self
.
fit_to_window
(
ink
=
False
)
self
.
regenerate_surface
(
lazy
=
Fals
e
)
self
.
regenerate_surface
(
reset
=
True
,
complete
=
Tru
e
)
except
StopIteration
:
self
.
g
=
self
.
ag
self
.
pos
=
self
.
apos
...
...
@@ -410,48 +417,48 @@ class GraphWidget(Gtk.DrawingArea):
# Actual drawing
def
regenerate_surface
(
self
,
lazy
=
True
,
timeout
=
350
):
r
"""Redraw the graph surface. If lazy is True, the actual redrawing will
be performed after the specified timeout."""
if
lazy
:
if
self
.
surface_callback
is
not
None
:
gobject
.
source_remove
(
self
.
surface_callback
)
f
=
lambda
:
self
.
regenerate_surface
(
lazy
=
False
)
self
.
surface_callback
=
gobject
.
timeout_add
(
timeout
,
f
)
else
:
geometry
=
[
self
.
get_allocated_width
()
*
3
,
self
.
get_allocated_height
()
*
3
]
def
regenerate_surface
(
self
,
reset
=
False
,
complete
=
False
):
r
"""Redraw the graph surface."""
if
reset
:
self
.
regenerate_offset
=
0
geometry
=
[
self
.
get_allocated_width
()
*
3
,
self
.
get_allocated_height
()
*
3
]
if
(
self
.
base
is
None
or
self
.
base_geometry
[
0
]
!=
geometry
[
0
]
or
self
.
base_geometry
[
1
]
!=
geometry
[
1
]
or
reset
):
# self.base = cairo.ImageSurface(cairo.FORMAT_ARGB32,
# *geometry)
w
=
self
.
get_window
()
if
w
is
None
:
return
False
self
.
base
=
w
.
create_similar_surface
(
cairo
.
CONTENT_COLOR_ALPHA
,
*
geometry
)
self
.
base_geometry
=
geometry
self
.
regenerate_offset
=
0
m
=
cairo
.
Matrix
()
m
.
translate
(
self
.
get_allocated_width
(),
self
.
get_allocated_height
())
self
.
smatrix
=
self
.
smatrix
*
m
self
.
tmatrix
=
self
.
tmatrix
*
self
.
smatrix
if
(
self
.
base
is
None
or
self
.
base_geometry
[
0
]
!=
geometry
[
0
]
or
self
.
base_geometry
[
1
]
!=
geometry
[
1
]):
# self.base = cairo.ImageSurface(cairo.FORMAT_ARGB32,
# *geometry)
w
=
self
.
get_window
()
if
w
is
None
:
return
False
self
.
base
=
w
.
create_similar_surface
(
cairo
.
CONTENT_COLOR_ALPHA
,
*
geometry
)
self
.
base_geometry
=
geometry
cr
=
cairo
.
Context
(
self
.
base
)
cr
.
set_source_rgba
(
*
self
.
bg_color
)
cr
.
paint
()
cr
.
set_matrix
(
self
.
tmatrix
)
cairo_draw
(
self
.
g
,
self
.
pos
,
cr
,
self
.
vprops
,
self
.
eprops
,
self
.
vorder
,
self
.
eorder
,
self
.
nodesfirst
,
**
self
.
kwargs
)
self
.
smatrix
=
cairo
.
Matrix
()
self
.
smatrix
.
translate
(
-
self
.
get_allocated_width
(),
-
self
.
get_allocated_height
())
if
self
.
surface_callback
is
not
None
:
gobject
.
source_remove
(
self
.
surface_callback
)
self
.
surface_callback
=
None
self
.
queue_draw
()
return
False
cr
=
cairo
.
Context
(
self
.
base
)
if
self
.
regenerate_offset
==
0
:
cr
.
set_source_rgba
(
*
self
.
bg_color
)
cr
.
paint
()
cr
.
set_matrix
(
self
.
tmatrix
)
mtime
=
-
1
if
complete
else
self
.
regenerate_max_time
count
=
cairo_draw
(
self
.
g
,
self
.
pos
,
cr
,
self
.
vprops
,
self
.
eprops
,
self
.
vorder
,
self
.
eorder
,
self
.
nodesfirst
,
res
=
1
,
render_offset
=
self
.
regenerate_offset
,
max_render_time
=
mtime
,
**
self
.
kwargs
)
self
.
regenerate_offset
=
count
def
draw
(
self
,
da
,
cr
):
r
"""Redraw the widget."""
...
...
@@ -462,17 +469,24 @@ class GraphWidget(Gtk.DrawingArea):
if
self
.
geometry
is
None
:
adjust_default_sizes
(
self
.
g
,
geometry
,
self
.
vprops
,
self
.
eprops
)
self
.
fit_to_window
(
ink
=
False
)
self
.
regenerate_surface
(
lazy
=
False
)
self
.
regenerate_surface
()
self
.
geometry
=
geometry
cr
.
save
()
cr
.
set_matrix
(
self
.
smatrix
)
ul
=
self
.
pos_to_device
((
0
,
0
),
surface
=
True
,
cr
=
cr
)
lr
=
self
.
pos_to_device
(
self
.
base_geometry
,
surface
=
True
,
cr
=
cr
)
c1
=
self
.
pos_to_device
((
0
,
0
),
surface
=
True
,
cr
=
cr
)
c2
=
self
.
pos_to_device
((
0
,
self
.
base_geometry
[
1
]),
surface
=
True
,
cr
=
cr
)
c3
=
self
.
pos_to_device
((
self
.
base_geometry
[
0
],
0
),
surface
=
True
,
cr
=
cr
)
c4
=
self
.
pos_to_device
(
self
.
base_geometry
,
surface
=
True
,
cr
=
cr
)
c
=
[
c1
,
c2
,
c3
,
c4
]
ul
=
[
min
([
x
[
0
]
for
x
in
c
]),
min
([
x
[
1
]
for
x
in
c
])]
lr
=
[
max
([
x
[
0
]
for
x
in
c
]),
max
([
x
[
1
]
for
x
in
c
])]
cr
.
restore
()
if
(
ul
[
0
]
>
0
or
lr
[
0
]
<
geometry
[
0
]
or
ul
[
1
]
>
0
or
lr
[
1
]
<
geometry
[
1
]):
self
.
regenerate_surface
(
reset
=
True
)
elif
self
.
regenerate_offset
>
0
:
self
.
regenerate_surface
()
if
self
.
background
is
None
:
...
...
@@ -513,10 +527,9 @@ class GraphWidget(Gtk.DrawingArea):
vprops
[
"text_color"
]
=
[
1.
,
1.
,
1.
,
0.
]
eprops
=
{}
eprops
.
update
(
self
.
eprops
)
eprops
[
"color"
]
=
[
1.
,
1.
,
1.
,
0.
]
u
=
GraphView
(
self
.
g
,
vfilt
=
self
.
selected
)
u
=
GraphView
(
self
.
g
,
vfilt
=
self
.
selected
,
efilt
=
self
.
sel_edge_filt
)
cr
.
save
()
cr
.
set_matrix
(
self
.
tmatrix
*
self
.
smatrix
)
...
...
@@ -534,7 +547,7 @@ class GraphWidget(Gtk.DrawingArea):
cr
.
set_source_rgba
(
0
,
0
,
1
,
0.3
)
cr
.
fill
()
if
self
.
surface_callback
is
not
None
:
if
self
.
regenerate_offset
>
0
:
icon
=
self
.
render_icon
(
Gtk
.
STOCK_EXECUTE
,
Gtk
.
IconSize
.
BUTTON
)
Gdk
.
cairo_set_source_pixbuf
(
cr
,
icon
,
10
,
10
)
cr
.
paint
()
...
...
@@ -560,6 +573,8 @@ class GraphWidget(Gtk.DrawingArea):
cr
.
set_source_rgba
(
0
,
0
,
0
,
1.0
)
cr
.
show_text
(
txt
)
if
self
.
regenerate_offset
>
0
:
self
.
queue_draw
()
return
False
# Position and transforms
...
...
@@ -721,7 +736,7 @@ class GraphWidget(Gtk.DrawingArea):
self
.
pos
,
self
.
vprops
,
self
.
eprops
)
self
.
moved_picked
=
False
self
.
regenerate_surface
(
timeout
=
100
)
self
.
regenerate_surface
(
complete
=
True
)
self
.
queue_draw
()
elif
event
.
button
==
2
:
self
.
panning
=
None
...
...
@@ -789,6 +804,14 @@ class GraphWidget(Gtk.DrawingArea):
def
scroll_event
(
self
,
widget
,
event
):
r
"""Handle scrolling."""
self
.
regenerate_max_time
=
50
def
restore_render_time
():
self
.
regenerate_max_time
=
self
.
max_render_time
return
False
self
.
surface_callback
=
gobject
.
timeout_add
(
2000
,
restore_render_time
)
state
=
event
.
state
angle
=
0
...
...
@@ -812,16 +835,16 @@ class GraphWidget(Gtk.DrawingArea):
# keep centered
if
zoom
!=
1
:
center
=
self
.
pointer
cpos
=
self
.
pos_from_device
(
center
,
surface
=
True
)
cpos
=
self
.
pos_from_device
(
center
)
m
=
cairo
.
Matrix
()
m
.
scale
(
zoom
,
zoom
)
self
.
smatrix
=
self
.
s
matrix
.
multiply
(
m
)
self
.
tmatrix
=
self
.
t
matrix
.
multiply
(
m
)
ncpos
=
self
.
pos_from_device
(
center
,
surface
=
True
)
self
.
s
matrix
.
translate
(
ncpos
[
0
]
-
cpos
[
0
],
ncpos
=
self
.
pos_from_device
(
center
)
self
.
t
matrix
.
translate
(
ncpos
[
0
]
-
cpos
[
0
],
ncpos
[
1
]
-
cpos
[
1
])
self
.
regenerate_surface
()
self
.
regenerate_surface
(
reset
=
True
)
if
angle
!=
0
:
if
not
isinstance
(
self
.
picked
,
PropertyMap
):
center
=
(
self
.
pointer
[
0
],
self
.
pointer
[
1
])
...
...
@@ -830,7 +853,6 @@ class GraphWidget(Gtk.DrawingArea):
m
.
rotate
(
angle
)
m
.
translate
(
-
center
[
0
],
-
center
[
1
])
self
.
smatrix
=
self
.
smatrix
.
multiply
(
m
)
self
.
regenerate_surface
()
else
:
center
=
self
.
pos_from_device
(
self
.
pointer
)
u
=
GraphView
(
self
.
g
,
vfilt
=
self
.
picked
)
...
...
@@ -862,7 +884,7 @@ class GraphWidget(Gtk.DrawingArea):
#print event.keyval
if
event
.
keyval
==
ord
(
'r'
):
self
.
fit_to_window
()
self
.
regenerate_surface
(
timeout
=
50
)
self
.
regenerate_surface
(
reset
=
True
)
self
.
queue_draw
()
elif
event
.
keyval
==
ord
(
's'
):
self
.
reset_layout
()
...
...
@@ -880,7 +902,7 @@ class GraphWidget(Gtk.DrawingArea):
if
isinstance
(
self
.
picked
,
PropertyMap
):
u
=
GraphView
(
self
.
g
,
vfilt
=
self
.
picked
)
self
.
fit_to_window
(
g
=
u
)
self
.
regenerate_surface
(
timeout
=
50
)
self
.
regenerate_surface
(
reset
=
True
)
self
.
queue_draw
()
def
key_release_event
(
self
,
widget
,
event
):
...
...
@@ -895,7 +917,7 @@ class GraphWidget(Gtk.DrawingArea):
if
event
.
keyval
==
65507
:
# Control_L
if
self
.
moved_picked
: