作図ソフト dia の改良版
修訂 | 2946acb4b603dfe5abe2b2dce056f439d3c0752a (tree) |
---|---|
時間 | 2014-06-08 17:58:11 |
作者 | Hans Breuer <hans@breu...> |
Commiter | Hans Breuer |
Misc - Ngon: add density parameter for mote star variants
The n-gon density value depends on num_rays. Only a limited set of values
can be supported, where min/max/step is not enough to reflect it.
So this object is the first user of PropEventHandler to keep density in
valid range (or better it's edit control).
@@ -200,8 +200,23 @@ property_signal_handler(GObject *obj, | ||
200 | 200 | for (j = 0; j < dialog->prop_widgets->len; j++) { |
201 | 201 | PropWidgetAssoc *pwa = |
202 | 202 | &g_array_index(dialog->prop_widgets,PropWidgetAssoc,j); |
203 | + /* The event handler above might have changed every property | |
204 | + * so we would have to mark them all as set (aka. to be applied). | |
205 | + * But doing so would not work well with multiple/grouped objects | |
206 | + * with unchanged and unequal object properties. Idea: keep as | |
207 | + * set, what was before calling reset (but it's too late after get_props). | |
208 | + * | |
209 | + * See also commonprop_reset_widget() for more information | |
210 | + */ | |
211 | + gboolean was_set = (pwa->prop->experience & PXP_NOTSET == 0); | |
203 | 212 | pwa->prop->ops->reset_widget(pwa->prop,pwa->widget); |
213 | + if (was_set) | |
214 | + pwa->prop->experience &= ~PXP_NOTSET; | |
204 | 215 | } |
216 | + /* once more at least for _this_ property otherwise a property with | |
217 | + * signal handler attached would not be changed at all ... | |
218 | + */ | |
219 | + prop->experience &= ~PXP_NOTSET; | |
205 | 220 | } else { |
206 | 221 | g_assert_not_reached(); |
207 | 222 | } |
@@ -24,6 +24,7 @@ | ||
24 | 24 | #include "diarenderer.h" |
25 | 25 | #include "attributes.h" |
26 | 26 | #include "properties.h" |
27 | +#include "prop_inttypes.h" /* PropEventHandler needs internals */ | |
27 | 28 | #include "boundingbox.h" |
28 | 29 | #include "element.h" |
29 | 30 | #include "pattern.h" |
@@ -55,6 +56,9 @@ struct _Ngon { | ||
55 | 56 | |
56 | 57 | int num_rays; |
57 | 58 | NgonKind kind; |
59 | + int density; | |
60 | + int last_density; /*!< last value to decide direction */ | |
61 | + | |
58 | 62 | LineStyle line_style; |
59 | 63 | LineJoin line_join; |
60 | 64 | real dashlength; |
@@ -102,6 +106,10 @@ static PropEnumData _ngon_type_data[] = { | ||
102 | 106 | { NULL, } |
103 | 107 | }; |
104 | 108 | static PropNumData _num_rays_range_data = { 3, 360, 1 }; |
109 | +static PropNumData _density_range_data = { 2, 180, 1 }; | |
110 | + | |
111 | +/* PropEventHandler to keep the density property valid */ | |
112 | +static gboolean _ngon_density_constraints_handler (DiaObject *obj, Property *prop); | |
105 | 113 | |
106 | 114 | static PropDescription _ngon_props[] = { |
107 | 115 | ELEMENT_COMMON_PROPERTIES, |
@@ -109,6 +117,9 @@ static PropDescription _ngon_props[] = { | ||
109 | 117 | N_("N-gon kind"), NULL, &_ngon_type_data }, |
110 | 118 | { "num_rays", PROP_TYPE_INT, PROP_FLAG_VISIBLE, |
111 | 119 | N_("Number of rays"), NULL, &_num_rays_range_data }, |
120 | + { "density", PROP_TYPE_INT, PROP_FLAG_VISIBLE|PROP_FLAG_OPTIONAL, | |
121 | + N_("Density"), N_("Winding number for Crossing"), &_density_range_data, | |
122 | + &_ngon_density_constraints_handler }, | |
112 | 123 | { "center", PROP_TYPE_POINT, PROP_FLAG_NO_DEFAULTS, /* no property widget, but still to be serialized */ |
113 | 124 | N_("Center position"), NULL, NULL }, |
114 | 125 | { "ray_len", PROP_TYPE_REAL, PROP_FLAG_NO_DEFAULTS, /* no property widget, but still to be serialized */ |
@@ -136,6 +147,7 @@ static PropOffset _ngon_offsets[] = { | ||
136 | 147 | ELEMENT_COMMON_PROPERTIES_OFFSETS, |
137 | 148 | { "ngon_kind", PROP_TYPE_ENUM, offsetof(Ngon, kind) }, |
138 | 149 | { "num_rays", PROP_TYPE_INT, offsetof(Ngon, num_rays) }, |
150 | + { "density", PROP_TYPE_INT, offsetof(Ngon, density) }, | |
139 | 151 | { "center", PROP_TYPE_POINT, offsetof(Ngon, center) }, |
140 | 152 | { "ray_len", PROP_TYPE_REAL, offsetof(Ngon, ray_len) }, |
141 | 153 | { PROP_STDNAME_LINE_WIDTH, PROP_STDTYPE_LINE_WIDTH, offsetof(Ngon, line_width) }, |
@@ -150,12 +162,13 @@ static PropOffset _ngon_offsets[] = { | ||
150 | 162 | }; |
151 | 163 | static void |
152 | 164 | _ngon_get_props(Ngon *ng, GPtrArray *props) |
153 | -{ | |
165 | +{ | |
154 | 166 | object_get_props_from_offsets(&ng->element.object, _ngon_offsets, props); |
155 | 167 | } |
156 | 168 | static void |
157 | 169 | _ngon_set_props(Ngon *ng, GPtrArray *props) |
158 | 170 | { |
171 | + ng->last_density = ng->density; | |
159 | 172 | object_set_props_from_offsets(&ng->element.object, _ngon_offsets, props); |
160 | 173 | _ngon_update_data(ng); |
161 | 174 | } |
@@ -254,10 +267,46 @@ _gcd (int a, int b) | ||
254 | 267 | static int |
255 | 268 | _calc_step (int a, int b) |
256 | 269 | { |
270 | + if (b > a / 2) | |
271 | + b = a / 2; | |
257 | 272 | while (_gcd (a, b) != 1) |
258 | 273 | --b; |
259 | 274 | return b; |
260 | 275 | } |
276 | +static int | |
277 | +_calc_step_up (int a, int b) | |
278 | +{ | |
279 | + while (_gcd (a, b) != 1) | |
280 | + ++b; | |
281 | + return b; | |
282 | +} | |
283 | + | |
284 | +/*! | |
285 | + * \brief Event handler called for property change by user | |
286 | + * | |
287 | + * The n-gon density value depends on num_rays. Only a limited set of values | |
288 | + * can be supported, where min/max/step is not enough to reflect it. | |
289 | + * | |
290 | + * This function gets called between Ngon::set_props() and | |
291 | + * Ngon::get_props(). It does need to do anything cause Ngon::update_data() | |
292 | + * already ensured data consistency. The pure existance of this of this | |
293 | + * property handler leads to bidirectional communication between property | |
294 | + * dialog and object's property change. | |
295 | + */ | |
296 | +static gboolean | |
297 | +_ngon_density_constraints_handler (DiaObject *obj, Property *prop) | |
298 | +{ | |
299 | + Ngon *ng = (Ngon *)obj; | |
300 | + IntProperty *p = (IntProperty *)prop; | |
301 | + int maxDensity = _calc_step (ng->num_rays, ng->num_rays / 2); | |
302 | + | |
303 | + g_return_val_if_fail (strcmp(prop->descr->type, PROP_TYPE_INT) == 0, FALSE); | |
304 | + | |
305 | + if (p->int_data > maxDensity) { | |
306 | + ng->density = maxDensity; | |
307 | + } | |
308 | + return TRUE; | |
309 | +} | |
261 | 310 | |
262 | 311 | static void |
263 | 312 | _ngon_make_name (Ngon *ng) |
@@ -309,8 +358,7 @@ _ngon_make_name (Ngon *ng) | ||
309 | 358 | if (ng->kind == NGON_CONVEX) |
310 | 359 | ng->name = g_strdup_printf ("%s {%d}", name, ng->num_rays); |
311 | 360 | else |
312 | - ng->name = g_strdup_printf ("%s {%d/%d}", name, ng->num_rays, | |
313 | - _calc_step (ng->num_rays, ng->num_rays / 2)); | |
361 | + ng->name = g_strdup_printf ("%s {%d/%d}", name, ng->num_rays, ng->density); | |
314 | 362 | } |
315 | 363 | |
316 | 364 | /*! |
@@ -324,7 +372,7 @@ _ngon_make_name (Ngon *ng) | ||
324 | 372 | static void |
325 | 373 | _ngon_adjust_for_crossing (Ngon *ng) |
326 | 374 | { |
327 | - int n = ng->points->len, i, step = _calc_step (ng->points->len, ng->points->len / 2); | |
375 | + int n = ng->points->len, i, step = _calc_step (ng->num_rays, ng->density); | |
328 | 376 | GArray *points = g_array_new (FALSE /* zero_terminated */, |
329 | 377 | FALSE /* clear_ */, sizeof(Point)); |
330 | 378 |
@@ -356,6 +404,12 @@ _ngon_update_data (Ngon *ng) | ||
356 | 404 | else |
357 | 405 | n = ng->num_rays * 2; |
358 | 406 | |
407 | + /* ensure density stays in range */ | |
408 | + if (ng->last_density > ng->density) | |
409 | + ng->density = _calc_step (ng->num_rays, ng->density); | |
410 | + else | |
411 | + ng->density = _calc_step_up (ng->num_rays, ng->density); | |
412 | + | |
359 | 413 | _ngon_make_name (ng); |
360 | 414 | if (1 || n != ng->points->len) { |
361 | 415 | /* recalculate all points */ |
@@ -454,7 +508,7 @@ static ObjectOps _ngon_ops = { | ||
454 | 508 | DiaObjectType _ngon_type = |
455 | 509 | { |
456 | 510 | "Misc - Ngon", /* name */ |
457 | - 0, /* version */ | |
511 | + 1, /* version */ | |
458 | 512 | n_gon_xpm, /* pixmap */ |
459 | 513 | &_ngon_type_ops, /* ops */ |
460 | 514 | NULL, /* pixmap_file */ |
@@ -498,6 +552,7 @@ _ngon_create (Point *startpoint, | ||
498 | 552 | FALSE /* clear_ */, sizeof(Point)); |
499 | 553 | ng->kind = NGON_CONVEX; |
500 | 554 | ng->num_rays = 5; |
555 | + ng->last_density = ng->density = _calc_step (ng->num_rays, ng->num_rays / 2); | |
501 | 556 | ng->ray_len = 1.0; /* for intial object size */ |
502 | 557 | ng->center = *startpoint; |
503 | 558 |
@@ -520,7 +575,14 @@ _ngon_load (ObjectNode obj_node, int version, DiaContext *ctx) | ||
520 | 575 | Ngon *ng; |
521 | 576 | |
522 | 577 | obj = object_load_using_properties (&_ngon_type, obj_node, version, ctx); |
523 | - /* XXX: do some sanity check? */ | |
578 | + ng = (Ngon *)obj; | |
579 | + if (version == 0) { /* default to maximum */ | |
580 | + ng->last_density = ng->density = _calc_step (ng->num_rays, ng->num_rays/2); | |
581 | + _ngon_update_data(ng); | |
582 | + } | |
583 | + /* the density value is optional, so calculate if not valid */ | |
584 | + if (_calc_step (ng->num_rays, ng->density) != ng->density) | |
585 | + ng->density = _calc_step (ng->num_rays, ng->num_rays/2); | |
524 | 586 | return obj; |
525 | 587 | } |
526 | 588 |