1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
5 * Copyright (C) 2002 Cyrille Chepelov
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
35 #include "connectionpoint.h"
36 #include "diarenderer.h"
37 #include "attributes.h"
41 #include "properties.h"
42 #include "dynamic_obj.h"
44 #include "pixmaps/analog_clock.xpm"
46 typedef struct _Chronoline
{
49 ConnectionPoint hours
[12];
50 ConnectionPoint hour_tip
, min_tip
, sec_tip
;
51 ConnectionPoint center_cp
;
54 real border_line_width
;
56 gboolean show_background
;
58 real arrow_line_width
;
59 Color sec_arrow_color
;
60 real sec_arrow_line_width
;
63 Point centre
; /* computed */
64 real radius
; /* computed */
68 static real
analog_clock_distance_from(Analog_Clock
*analog_clock
,
71 static void analog_clock_select(Analog_Clock
*analog_clock
,
73 DiaRenderer
*interactive_renderer
);
74 static ObjectChange
* analog_clock_move_handle(Analog_Clock
*analog_clock
,
75 Handle
*handle
, Point
*to
,
76 ConnectionPoint
*cp
, HandleMoveReason reason
,
77 ModifierKeys modifiers
);
78 static ObjectChange
* analog_clock_move(Analog_Clock
*analog_clock
, Point
*to
);
79 static void analog_clock_draw(Analog_Clock
*analog_clock
, DiaRenderer
*renderer
);
80 static void analog_clock_update_data(Analog_Clock
*analog_clock
);
81 static DiaObject
*analog_clock_create(Point
*startpoint
,
85 static void analog_clock_destroy(Analog_Clock
*analog_clock
);
86 static DiaObject
*analog_clock_load(ObjectNode obj_node
, int version
,
87 const char *filename
);
88 static PropDescription
*analog_clock_describe_props(
89 Analog_Clock
*analog_clock
);
90 static void analog_clock_get_props(Analog_Clock
*analog_clock
,
92 static void analog_clock_set_props(Analog_Clock
*analog_clock
,
95 static ObjectTypeOps analog_clock_type_ops
=
97 (CreateFunc
) analog_clock_create
,
98 (LoadFunc
) analog_clock_load
/*using properties*/,
99 (SaveFunc
) object_save_using_properties
,
100 (GetDefaultsFunc
) NULL
,
101 (ApplyDefaultsFunc
) NULL
104 DiaObjectType analog_clock_type
=
106 "Misc - Analog Clock", /* name */
108 (char **) analog_clock_xpm
, /* pixmap */
110 &analog_clock_type_ops
/* ops */
113 static ObjectOps analog_clock_ops
= {
114 (DestroyFunc
) analog_clock_destroy
,
115 (DrawFunc
) analog_clock_draw
,
116 (DistanceFunc
) analog_clock_distance_from
,
117 (SelectFunc
) analog_clock_select
,
118 (CopyFunc
) object_copy_using_properties
,
119 (MoveFunc
) analog_clock_move
,
120 (MoveHandleFunc
) analog_clock_move_handle
,
121 (GetPropertiesFunc
) object_create_props_dialog
,
122 (ApplyPropertiesFunc
) object_apply_props_from_dialog
,
123 (ObjectMenuFunc
) NULL
,
124 (DescribePropsFunc
) analog_clock_describe_props
,
125 (GetPropsFunc
) analog_clock_get_props
,
126 (SetPropsFunc
) analog_clock_set_props
129 static PropDescription analog_clock_props
[] = {
130 ELEMENT_COMMON_PROPERTIES
,
132 PROP_STD_LINE_COLOUR
,
133 PROP_STD_FILL_COLOUR
,
134 PROP_STD_SHOW_BACKGROUND
,
136 { "arrow_colour", PROP_TYPE_COLOUR
, PROP_FLAG_VISIBLE
,
137 N_("Arrow color"), NULL
, NULL
},
138 { "arrow_line_width", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
,
139 N_("Arrow line width"), NULL
,NULL
},
140 { "sec_arrow_colour", PROP_TYPE_COLOUR
, PROP_FLAG_VISIBLE
,
141 N_("Seconds arrow color"), NULL
, NULL
},
142 { "sec_arrow_line_width", PROP_TYPE_REAL
, PROP_FLAG_VISIBLE
,
143 N_("Seconds arrow line width"), NULL
,NULL
},
144 { "show_ticks", PROP_TYPE_BOOL
, PROP_FLAG_VISIBLE
,
145 N_("Show hours"), NULL
, NULL
},
147 PROP_STD_NOTEBOOK_END
,
151 static PropDescription
*
152 analog_clock_describe_props(Analog_Clock
*analog_clock
)
154 if (analog_clock_props
[0].quark
== 0) {
155 prop_desc_list_calculate_quarks(analog_clock_props
);
157 return analog_clock_props
;
160 static PropOffset analog_clock_offsets
[] = {
161 ELEMENT_COMMON_PROPERTIES_OFFSETS
,
162 { "line_width", PROP_TYPE_REAL
, offsetof(Analog_Clock
, border_line_width
) },
163 { "line_colour", PROP_TYPE_COLOUR
, offsetof(Analog_Clock
, border_color
) },
164 { "fill_colour", PROP_TYPE_COLOUR
, offsetof(Analog_Clock
,inner_color
) },
165 { "show_background", PROP_TYPE_BOOL
,offsetof(Analog_Clock
,show_background
) },
166 { "arrow_colour", PROP_TYPE_COLOUR
, offsetof(Analog_Clock
, arrow_color
) },
167 { "arrow_line_width", PROP_TYPE_REAL
, offsetof(Analog_Clock
,
169 { "sec_arrow_colour", PROP_TYPE_COLOUR
,
170 offsetof(Analog_Clock
, sec_arrow_color
) },
171 { "sec_arrow_line_width", PROP_TYPE_REAL
,
172 offsetof(Analog_Clock
, sec_arrow_line_width
) },
174 { "show_ticks", PROP_TYPE_BOOL
,offsetof(Analog_Clock
,show_ticks
) },
180 analog_clock_get_props(Analog_Clock
*analog_clock
, GPtrArray
*props
)
182 object_get_props_from_offsets(&analog_clock
->element
.object
,
183 analog_clock_offsets
,props
);
187 analog_clock_set_props(Analog_Clock
*analog_clock
, GPtrArray
*props
)
189 object_set_props_from_offsets(&analog_clock
->element
.object
,
190 analog_clock_offsets
,props
);
191 analog_clock_update_data(analog_clock
);
195 analog_clock_distance_from(Analog_Clock
*analog_clock
, Point
*point
)
197 DiaObject
*obj
= &analog_clock
->element
.object
;
198 return distance_rectangle_point(&obj
->bounding_box
, point
);
202 analog_clock_select(Analog_Clock
*analog_clock
, Point
*clicked_point
,
203 DiaRenderer
*interactive_renderer
)
205 element_update_handles(&analog_clock
->element
);
209 analog_clock_move_handle(Analog_Clock
*analog_clock
, Handle
*handle
,
210 Point
*to
, ConnectionPoint
*cp
,
211 HandleMoveReason reason
, ModifierKeys modifiers
)
213 g_assert(analog_clock
!=NULL
);
214 g_assert(handle
!=NULL
);
217 element_move_handle(&analog_clock
->element
, handle
->id
, to
, cp
,
219 analog_clock_update_data(analog_clock
);
225 analog_clock_move(Analog_Clock
*analog_clock
, Point
*to
)
227 analog_clock
->element
.corner
= *to
;
228 analog_clock_update_data(analog_clock
);
233 static void make_angle(const Point
*centre
, real degrees
, real radius
,
236 real radians
= ((90 - degrees
) * M_PI
) / 180.0;
237 pt
->x
= centre
->x
+ radius
* cos( radians
);
238 pt
->y
= centre
->y
- radius
* sin( radians
);
241 static void make_hours(const Point
*centre
, unsigned hours
, real radius
,
244 while (hours
> 11) hours
-= 12;
246 make_angle(centre
,((real
)hours
) * 360.0 / 12.0,radius
,pt
);
249 static void make_minutes(const Point
*centre
, unsigned minutes
,
250 real radius
, Point
*pt
)
252 make_angle(centre
,((real
)minutes
) * 360.0 / 60.0,radius
,pt
);
256 analog_clock_update_arrow_tips(Analog_Clock
*analog_clock
)
262 local
= localtime(&now
);
263 analog_clock
->hour_tip
.directions
= DIR_ALL
;
264 analog_clock
->min_tip
.directions
= DIR_ALL
;
265 analog_clock
->sec_tip
.directions
= DIR_ALL
;
267 make_hours(&analog_clock
->centre
,local
->tm_hour
,
268 0.50 * analog_clock
->radius
, &analog_clock
->hour_tip
.pos
);
269 make_minutes(&analog_clock
->centre
,local
->tm_min
,
270 0.80 * analog_clock
->radius
, &analog_clock
->min_tip
.pos
);
271 make_minutes(&analog_clock
->centre
,local
->tm_sec
,
272 0.85 * analog_clock
->radius
, &analog_clock
->sec_tip
.pos
);
274 /* Highly unlikely */
275 point_copy(&analog_clock
->hour_tip
.pos
,&analog_clock
->centre
);
276 point_copy(&analog_clock
->min_tip
.pos
,&analog_clock
->centre
);
277 point_copy(&analog_clock
->sec_tip
.pos
,&analog_clock
->centre
);
283 analog_clock_update_data(Analog_Clock
*analog_clock
)
285 Element
*elem
= &analog_clock
->element
;
286 DiaObject
*obj
= &elem
->object
;
288 ElementBBExtras
*extra
= &elem
->extra_spacing
;
290 extra
->border_trans
= analog_clock
->border_line_width
/ 2;
291 element_update_boundingbox(elem
);
293 obj
->position
= elem
->corner
;
295 element_update_handles(elem
);
297 analog_clock
->centre
.x
= obj
->position
.x
+ elem
->width
/2;
298 analog_clock
->centre
.y
= obj
->position
.y
+ elem
->height
/2;
300 analog_clock
->radius
= MIN(elem
->width
/2,elem
->height
/2);
302 /* Update connections: */
303 for (i
= 0; i
< 12; ++i
)
305 make_hours(&analog_clock
->centre
, i
+1, analog_clock
->radius
,
306 &analog_clock
->hours
[i
].pos
);
307 analog_clock
->hours
[i
].directions
= DIR_ALL
;
309 analog_clock
->center_cp
.pos
.x
= elem
->corner
.x
+ elem
->width
/2;
310 analog_clock
->center_cp
.pos
.y
= elem
->corner
.y
+ elem
->height
/2;
312 analog_clock_update_arrow_tips(analog_clock
);
316 analog_clock_draw(Analog_Clock
*analog_clock
, DiaRenderer
*renderer
)
318 DiaRendererClass
*renderer_ops
= DIA_RENDERER_GET_CLASS (renderer
);
321 g_assert(analog_clock
!= NULL
);
322 g_assert(renderer
!= NULL
);
324 elem
= &analog_clock
->element
;
326 renderer_ops
->set_linejoin(renderer
, LINEJOIN_MITER
);
327 renderer_ops
->set_linestyle(renderer
, LINESTYLE_SOLID
);
328 renderer_ops
->set_linewidth(renderer
, analog_clock
->border_line_width
);
330 if (analog_clock
->show_background
)
331 renderer_ops
->fill_ellipse(renderer
,&analog_clock
->centre
,
332 2*analog_clock
->radius
,2*analog_clock
->radius
,
333 &analog_clock
->inner_color
);
334 renderer_ops
->draw_ellipse(renderer
,&analog_clock
->centre
,
335 2*analog_clock
->radius
,2*analog_clock
->radius
,
336 &analog_clock
->border_color
);
337 if (analog_clock
->show_ticks
)
342 for (i
= 0; i
< 12; ++i
) {
346 ticklen
= 3.5 * analog_clock
->border_line_width
; break;
347 case 3: case 6: case 9:
348 ticklen
= 3 * analog_clock
->border_line_width
; break;
350 ticklen
= 2 * analog_clock
->border_line_width
; break;
352 make_hours(&analog_clock
->centre
, i
,
353 analog_clock
->radius
, &out
);
354 make_hours(&analog_clock
->centre
, i
,
355 analog_clock
->radius
-ticklen
, &in
);
356 renderer_ops
->draw_line(renderer
,&out
,&in
,&analog_clock
->border_color
);
360 analog_clock_update_arrow_tips(analog_clock
);
362 renderer_ops
->set_linewidth(renderer
, analog_clock
->arrow_line_width
);
363 renderer_ops
->draw_line(renderer
,
364 &analog_clock
->hour_tip
.pos
, &analog_clock
->centre
,
365 &analog_clock
->arrow_color
);
366 renderer_ops
->draw_line(renderer
,
367 &analog_clock
->min_tip
.pos
, &analog_clock
->centre
,
368 &analog_clock
->arrow_color
);
370 renderer_ops
->set_linewidth(renderer
, analog_clock
->sec_arrow_line_width
);
371 renderer_ops
->draw_line(renderer
,
372 &analog_clock
->sec_tip
.pos
, &analog_clock
->centre
,
373 &analog_clock
->sec_arrow_color
);
374 renderer_ops
->fill_ellipse(renderer
,&analog_clock
->centre
,
375 analog_clock
->arrow_line_width
*2.25,
376 analog_clock
->arrow_line_width
*2.25,
377 &analog_clock
->sec_arrow_color
);
383 analog_clock_create(Point
*startpoint
,
388 Analog_Clock
*analog_clock
;
393 analog_clock
= g_new0(Analog_Clock
,1);
394 elem
= &(analog_clock
->element
);
396 obj
= &(analog_clock
->element
.object
);
397 obj
->type
= &analog_clock_type
;
398 obj
->ops
= &analog_clock_ops
;
400 elem
->corner
= *startpoint
;
404 element_init(elem
, 8, 16);
406 analog_clock
->border_color
= attributes_get_foreground();
407 analog_clock
->border_line_width
= attributes_get_default_linewidth();
408 analog_clock
->inner_color
= attributes_get_background();
409 analog_clock
->show_background
= TRUE
;
410 analog_clock
->arrow_color
.red
= 0.0;
411 analog_clock
->arrow_color
.green
= 0.0;
412 analog_clock
->arrow_color
.blue
= 0.5;
413 analog_clock
->arrow_line_width
= attributes_get_default_linewidth();
414 analog_clock
->sec_arrow_color
.red
= 1.0;
415 analog_clock
->sec_arrow_color
.green
= 0.0;
416 analog_clock
->sec_arrow_color
.blue
= 0.0;
417 analog_clock
->sec_arrow_line_width
= attributes_get_default_linewidth()/3;
418 analog_clock
->show_ticks
= TRUE
;
420 for (i
= 0; i
< 12; ++i
)
422 obj
->connections
[i
] = &analog_clock
->hours
[i
];
423 analog_clock
->hours
[i
].object
= obj
;
424 analog_clock
->hours
[i
].connected
= NULL
;
426 obj
->connections
[12] = &analog_clock
->hour_tip
;
427 analog_clock
->hour_tip
.object
= obj
;
428 analog_clock
->hour_tip
.connected
= NULL
;
429 obj
->connections
[13] = &analog_clock
->min_tip
;
430 analog_clock
->min_tip
.object
= obj
;
431 analog_clock
->min_tip
.connected
= NULL
;
432 obj
->connections
[14] = &analog_clock
->sec_tip
;
433 analog_clock
->sec_tip
.object
= obj
;
434 analog_clock
->sec_tip
.connected
= NULL
;
435 obj
->connections
[15] = &analog_clock
->center_cp
;
436 analog_clock
->center_cp
.object
= obj
;
437 analog_clock
->center_cp
.connected
= NULL
;
438 analog_clock
->center_cp
.flags
= CP_FLAGS_MAIN
;
440 analog_clock
->hours
[0].directions
= DIR_NORTH
;
441 analog_clock
->hours
[1].directions
= DIR_NORTH
|DIR_EAST
;
442 analog_clock
->hours
[2].directions
= DIR_NORTH
|DIR_EAST
;
443 analog_clock
->hours
[3].directions
= DIR_EAST
;
444 analog_clock
->hours
[4].directions
= DIR_EAST
|DIR_SOUTH
;
445 analog_clock
->hours
[5].directions
= DIR_EAST
|DIR_SOUTH
;
446 analog_clock
->hours
[6].directions
= DIR_SOUTH
;
447 analog_clock
->hours
[7].directions
= DIR_SOUTH
|DIR_WEST
;
448 analog_clock
->hours
[8].directions
= DIR_SOUTH
|DIR_WEST
;
449 analog_clock
->hours
[9].directions
= DIR_WEST
;
450 analog_clock
->hours
[10].directions
= DIR_WEST
|DIR_NORTH
;
451 analog_clock
->hours
[11].directions
= DIR_WEST
|DIR_NORTH
;
452 analog_clock
->center_cp
.directions
= DIR_ALL
;
454 analog_clock_update_data(analog_clock
);
457 *handle2
= obj
->handles
[7];
459 /* We are an animated object -- special case ! */
460 dynobj_list_add_object(&analog_clock
->element
.object
,1000);
462 return &analog_clock
->element
.object
;
466 analog_clock_destroy(Analog_Clock
*analog_clock
)
468 /* We are an animated object -- special case ! */
469 dynobj_list_remove_object(&analog_clock
->element
.object
);
470 element_destroy(&analog_clock
->element
);
474 analog_clock_load(ObjectNode obj_node
, int version
, const char *filename
)
476 return object_load_using_properties(&analog_clock_type
,
477 obj_node
,version
,filename
);