// flower.c
// Copyright (c) 2005 BenBear
// Flower 0.2
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2, or (at
// your option) any later version.
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with GNU Emacs; see the file COPYING. If not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
// This program needs GTK+ 2.0.
#include <gtk/gtk.h>
#include <math.h>
#ifndef M_PI
# define M_PI 3.1415926535898
#endif
GtkWidget *big; // a widget for big circle
GtkWidget *small; // a widget for small circle
GtkWidget *pen; // position of the pen
GtkWidget *outer; // check if small out big
GtkWidget *fill; // check if fill all drawarea
GtkWidget *drawarea; // the client will drawing
// "value-changed" event of the big circle, small circle and pen
void value_changed (GtkSpinButton *spinbutton,
gpointer data)
{
GdkRectangle rect;
rect.x = 0;
rect.y = 0;
rect.width = drawarea->allocation.width;
rect.height = drawarea->allocation.height;
gdk_window_invalidate_rect (drawarea->window,
&rect, FALSE);
}
// "toggled" event of the outer and fill
void toggled (GtkToggleButton *toggle,
gpointer data)
{
GdkRectangle rect;
rect.x = 0;
rect.y = 0;
rect.width = drawarea->allocation.width;
rect.height = drawarea->allocation.height;
gdk_window_invalidate_rect (drawarea->window,
&rect, FALSE);
}
GtkWidget *create_adjustment_entry(float cur, float min, float max)
{
GtkAdjustment *adj;
GtkWidget *entry;
adj = (GtkAdjustment *)gtk_adjustment_new (cur, min, max,
1.0, 5.0, 0.0);
entry = gtk_spin_button_new (adj, 0, 0);
g_signal_connect (G_OBJECT (entry), "value-changed",
G_CALLBACK (value_changed), entry);
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (entry), FALSE);
return entry;
}
void show_adjustment_entry (GtkWidget *entry, const char *str,
GtkWidget *vbox)
{
GtkWidget *label;
GtkWidget *hbox;
label = gtk_label_new (str);
hbox = gtk_hbox_new (TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show (label);
gtk_widget_show (entry);
gtk_widget_show (hbox);
}
// redraw event of drawing area
// draw the flower
gboolean
expose_event_callback (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
int b, s, p; // big, small and pen
int ns; // -small or small
int w, h, x, y; // width and height
int d;
int a, f; // outer and fill
double t;
GdkGC *gc;
GdkDrawable *canvas;
GdkColor color;
b = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(big));
s = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(small));
p = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(pen));
canvas = widget->window;
gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
w = widget->allocation.width;
h = widget->allocation.height;
a = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (outer));
f = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fill));
if (f)
{
// zoom
double r, m;
m = ((w < h) ? w : h) / 2 - 2;
r = (a ? (b + s + p)
: ((b < s) ? (s - b + p) : (b - s + p)));
if (r == 0)
f = 0; // if r == 0, then need not zoom
t = m / r;
}
if (f == 0)
{
t = 1.0;
}
ns = a ? s : -s;
//gdk_gc_offset (gc, 0, 0);
gdk_draw_rectangle (canvas, gc, TRUE, 0, 0, w, h);
color.red = 65535;
color.green = 65535;
color.blue = 65535;
gdk_gc_set_rgb_fg_color (gc, &color);
//
x = w / 2 + (int)((b + ns + p) * t);
y = h / 2;
for (d = 1; (d % 360 != 0) || (d / 360 * b % s != 0); ++d)
{
double dp, xp, yp, x1, y1;
int xx, yy;
dp = M_PI * d / 180 * b / -ns;
xp = b + ns + p * cos(dp);
yp = p * sin(dp);
x1 = xp * cos(-M_PI * d / 180) - yp * sin(-M_PI * d / 180);
y1 = xp * sin(-M_PI * d / 180) + yp * cos(-M_PI * d / 180);
xx = w / 2 + (int)(x1 * t);
yy = h / 2 - (int)(y1 * t);
gdk_draw_line (canvas, gc, x, y, xx, yy);
x = xx;
y = yy;
}
gdk_draw_line (canvas, gc, x, y,
w / 2 + (int)((b + ns + p) * t),
h / 2);
color.red = 0;
color.green = 0;
color.blue = 0;
gdk_gc_set_rgb_fg_color (gc, &color);
return TRUE;
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *align;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width (GTK_CONTAINER (window), 5);
gtk_window_set_title (GTK_WINDOW (window), "Flower");
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), 0);
g_signal_connect_swapped (G_OBJECT (window), "delete_event",
G_CALLBACK (gtk_widget_destroy),
window);
vbox = gtk_vbox_new (FALSE, 0);
// create big circle
big = create_adjustment_entry (100, 1.0, 1000.0);
show_adjustment_entry (big, "big ", vbox);
// create small circle
small = create_adjustment_entry (60, 1.0, 1000.0);
show_adjustment_entry (small, "small", vbox);
// create pen
pen = create_adjustment_entry (40, 0.0, 1000.0);
show_adjustment_entry (pen, "pen ", vbox);
// create check outer
outer = gtk_toggle_button_new_with_label ("small outer of big");
gtk_box_pack_start (GTK_BOX (vbox), outer, TRUE, TRUE, 5);
g_signal_connect (G_OBJECT (outer), "toggled",
G_CALLBACK (toggled), outer);
gtk_widget_show (outer);
// create check fill
fill = gtk_toggle_button_new_with_label ("auto zoom");
gtk_box_pack_start (GTK_BOX (vbox), fill, TRUE, TRUE, 0);
g_signal_connect (G_OBJECT (fill), "toggled",
G_CALLBACK (toggled), fill);
gtk_widget_show (fill);
align = gtk_alignment_new (1.0, 0.0, 0.0, 0.0);
gtk_container_add (GTK_CONTAINER (align), vbox);
drawarea = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawarea, 200, 200);
g_signal_connect (G_OBJECT (drawarea), "expose_event",
G_CALLBACK (expose_event_callback), NULL);
hbox = gtk_hbox_new (FALSE, 10);
gtk_box_pack_start (GTK_BOX (hbox), drawarea, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), hbox);
gtk_widget_show (drawarea);
gtk_widget_show (vbox);
gtk_widget_show (align);
gtk_widget_show (hbox);
gtk_widget_show (window);
gtk_main ();
return 0;
}
下面是 Makefile:
# Makefile for Flower
flower: flower.c
gcc flower.c -o flower `pkg-config --cflags --libs gtk+-2.0`