*** empty log message ***

This commit is contained in:
Marc Lehmann 1999-09-06 23:31:51 +00:00
parent 09e5838351
commit 9ebe7bbe09
18 changed files with 7086 additions and 0 deletions

View File

@ -1,3 +1,8 @@
Tue Sep 7 00:35:19 CEST 1999 Marc Lehmann <pcg@goof.com>
* plug-ins/gflare: new directory, lotsa files!
* configure.in, plug-ins/Makefile.am, re-added gflare plug-in.
Mon Sep 6 23:35:18 CEST 1999 Marc Lehmann <pcg@goof.com>
* plug-ins/common/sel_gauss.c: new plug-in.

View File

@ -692,6 +692,7 @@ plug-ins/gap/Makefile
plug-ins/gdyntext/Makefile
plug-ins/gfig/Makefile
plug-ins/gfig/gfig-examples/Makefile
plug-ins/gflare/Makefile
plug-ins/gfli/Makefile
plug-ins/gimpressionist/Makefile
plug-ins/gimpressionist/Brushes/Makefile

View File

@ -48,6 +48,7 @@ SUBDIRS = \
gap \
gdyntext \
gfig \
gflare \
gfli \
gimpressionist \
ifscompose \

View File

@ -0,0 +1,38 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = gflares
libexecdir = $(gimpplugindir)/plug-ins
libexec_PROGRAMS = gflare
gflare_SOURCES = \
asupsample.h \
asupsample.c \
gtkmultioptionmenu.h \
gtkmultioptionmenu.c \
gflare.c
INCLUDES = \
-I$(top_srcdir) \
$(GTK_CFLAGS) \
-I$(includedir)
LDADD = \
$(top_builddir)/libgimp/libgimpui.la \
$(top_builddir)/libgimp/libgimp.la \
$(GTK_LIBS) \
$(INTLLIBS)
.PHONY: files
files:
@files=`ls $(DISTFILES) 2> /dev/null`; for p in $$files; do \
echo $$p; \
done
@for subdir in $(SUBDIRS); do \
files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \
for file in $$files; do \
echo $$subdir/$$file; \
done; \
done

99
plug-ins/gflare/README Normal file
View File

@ -0,0 +1,99 @@
==========================================================================
GFlare plug-in ver 0.25
Eiichi Takamori <taka@ma1.seikyou.ne.jp>
==========================================================================
GFlare is a plug-in for the GIMP. The name "GFlare" is short for
"Gradient Flare". It renders lense flare effect using custom
gradients. The basic idea is suggested by Marcelo Malheiros,
originally based on a 3DStudio MAX plug-in called LenZFX:
http://www.digimation.com/techsupp/lzfxfeat.htm
INSTALL:
1) Edit Makefile, if needed.
2) Type "make install".
3) Type "make install-data" if needed. (It copies sample gradients and
gflares under ~/.gimp)
3) Add new entry to ~/.gimp/gimprc as
(gflare-path "${gimp_dir}/gflares:${gimp_data_dir}/gflares")
3) Run the GIMP. The menu path is <Image>/Filters/Effects/GFlare.
HOW TO USE IT:
The document is not yet done. Try and see.
Main Dialog:
- Preview
click on it changes the position of GFlare
- Settings page
- Center, Radius (pixel), Rotation (degree), Hue Rotation (degree)
- Vector Angle (degree) and Vector Length (percentage to Radius)
- adaptive supersampling ... same as "Blend tool"
- Selector page
- ListBox
- New, Edit, Copy, Delete buttons. Edit button invokes GFlare Editor.
GFlare Editor:
- General page:
- Glow page:
- Rays page:
- Second Flares page:
WARNING: This plug-in is in development stage, and the code is very
alpha. The GFlare datafile format may be changed in future version.
Suggestions and ideas for user interface, flare algorithm, etc. are
very welcome.
KNOWN BUGS:
There are still lots of bugs, of course. ;-)
They seem related to GTK, and I don't know exactly how I can fix them.
* It warns at startup as:
** WARNING **: file gdkwindow.c: line 422 (gdk_window_move_resize): "window != NULL"
If you are annoyed, accompanying "gtkviewport.c.patch" will shut up
the warning.
* Edit button remains prelighted when GFlare Editor dialog is done.
* Dialogs are not shown quickly at startup.
* Sometimes note tab labels are disappeared.
* Sometimes it crashes, but I don't know yet why it happens.
TODO:
* Random hue scattering for Second Flares.
* Improve internal gradients.
* Currently number of Second Flares is fixed(30).
* Change opacity for one second flare dynamically, in inverse
proportion to the size of it.
* Reduce dialog size
* Add tweak ability "How to combine Glow, Rays, Second Flares in
what order"
CREDITS:
Marcelo Marheiros and Federico Mena Quintero suggested a lot of
ideas. Very Thanks!!
Marcelo made gradients whose names end with _1, _2, etc. The
gradients whose names end with _101, _102 etc. are mine.
Quartic did awful Gradient Editor, and gradients PDB procedures.
A fair proportion of this code was taken from:
The GIMP -- an image manipulation program
Copyright (C) 1995 Spencer Kimball and Peter Mattis
Gradient editor module copyight (C) 1996-1997 Federico Mena Quintero
federico@nuclecu.unam.mx

View File

@ -0,0 +1,335 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* General, non-jittered adaptive supersampling library
* Copyright (C) 1997 Federico Mena Quintero
*
* 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 of the License, 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/* This code is *largely* based on the sources for POV-Ray 3.0. I am
* grateful to the POV-Team for such a great program and for making
* their sources available. All comments / bug reports /
* etc. regarding this library should be addressed to me, not to the
* POV-Ray team. Any bugs are my responsibility, not theirs.
*/
#include <math.h>
#include <string.h>
#include <gtk/gtk.h>
#include "asupsample.h"
/***** Types *****/
typedef struct {
char ready;
color_t color;
} sample_t;
/***** Local functions *****/
static unsigned long render_sub_pixel(int max_depth, int depth, sample_t **block,
int x, int y, int x1, int y1, int x3, int y3,
double threshold, int sub_pixel_size, render_func_t render_func,
color_t *color, void *render_data);
static double color_dist(color_t c1, color_t c2);
/***** Functions *****/
/*****/
unsigned long
adaptive_supersample_area(int x1, int y1, int x2, int y2, int max_depth, double threshold,
render_func_t render_func, void *render_data,
put_pixel_func_t put_pixel_func, void *put_pixel_data,
progress_func_t progress_func, void *progress_data)
{
int x, y, width; /* Counters, width of region */
int xt, xtt, yt; /* Temporary counters */
int sub_pixel_size; /* Numbe of samples per pixel (1D) */
size_t row_size; /* Memory needed for one row */
color_t color; /* Rendered pixel's color */
sample_t tmp_sample; /* For swapping samples */
sample_t *top_row, *bot_row, *tmp_row; /* Sample rows */
sample_t **block; /* Sample block matrix */
unsigned long num_samples;
/* Initialize color */
color.r = 0.0;
color.g = 0.0;
color.b = 0.0;
color.a = 0.0;
/* Calculate sub-pixel size */
sub_pixel_size = 1 << max_depth; /* 2**max_depth */
/* Create row arrays */
width = x2 - x1 + 1;
row_size = (sub_pixel_size * width + 1) * sizeof(sample_t);
top_row = g_malloc(row_size);
bot_row = g_malloc(row_size);
for (x = 0; x < (sub_pixel_size * width + 1); x++) {
top_row[x].ready = 0;
top_row[x].color.r = 0.0;
top_row[x].color.g = 0.0;
top_row[x].color.b = 0.0;
top_row[x].color.a = 0.0;
bot_row[x].ready = 0;
bot_row[x].color.r = 0.0;
bot_row[x].color.g = 0.0;
bot_row[x].color.b = 0.0;
bot_row[x].color.a = 0.0;
} /* for */
/* Allocate block matrix */
block = g_malloc((sub_pixel_size + 1) * sizeof(sample_t *)); /* Rows */
for (y = 0; y < (sub_pixel_size + 1); y++)
block[y] = g_malloc((sub_pixel_size + 1) * sizeof(sample_t)); /* Columns */
for (y = 0; y < (sub_pixel_size + 1); y++)
for (x = 0; x < (sub_pixel_size + 1); x++) {
block[y][x].ready = 0;
block[y][x].color.r = 0.0;
block[y][x].color.g = 0.0;
block[y][x].color.b = 0.0;
block[y][x].color.a = 0.0;
} /* for */
/* Render region */
num_samples = 0;
for (y = y1; y <= y2; y++) {
/* Clear the bottom row */
for (xt = 0; xt < (sub_pixel_size * width + 1); xt++)
bot_row[xt].ready = 0;
/* Clear first column */
for (yt = 0; yt < (sub_pixel_size + 1); yt++)
block[yt][0].ready = 0;
/* Render row */
for (x = x1; x <= x2; x++) {
/* Initialize block by clearing all but first row/column */
for (yt = 1; yt < (sub_pixel_size + 1); yt++)
for (xt = 1; xt < (sub_pixel_size + 1); xt++)
block[yt][xt].ready = 0;
/* Copy samples from top row to block */
for (xtt = 0, xt = (x - x1) * sub_pixel_size;
xtt < (sub_pixel_size + 1);
xtt++, xt++)
block[0][xtt] = top_row[xt];
/* Render pixel on (x, y) */
num_samples += render_sub_pixel(max_depth, 1, block, x, y, 0, 0,
sub_pixel_size, sub_pixel_size,
threshold, sub_pixel_size, render_func, &color,
render_data);
if (put_pixel_func)
(*put_pixel_func)(x, y, color, put_pixel_data);
/* Copy block information to rows */
top_row[((x - x1) + 1) * sub_pixel_size] = block[0][sub_pixel_size];
for (xtt = 0, xt = (x - x1) * sub_pixel_size;
xtt < (sub_pixel_size + 1);
xtt++, xt++)
bot_row[xt] = block[sub_pixel_size][xtt];
/* Swap first and last columns */
for (yt = 0; yt < (sub_pixel_size + 1); yt++) {
tmp_sample = block[yt][0];
block[yt][0] = block[yt][sub_pixel_size];
block[yt][sub_pixel_size] = tmp_sample;
} /* for */
} /* for */
/* Swap rows */
tmp_row = top_row;
top_row = bot_row;
bot_row = tmp_row;
/* Call progress display function */
if (progress_func)
(*progress_func)(y1, y2, y, progress_data);
} /* for */
/* Free memory */
for (y = 0; y < (sub_pixel_size + 1); y++)
g_free(block[y]);
g_free(block);
g_free(top_row);
g_free(bot_row);
return num_samples;
} /* adaptive_supersample_area */
/*****/
static unsigned long
render_sub_pixel(int max_depth, int depth, sample_t **block,
int x, int y, int x1, int y1, int x3, int y3,
double threshold, int sub_pixel_size, render_func_t render_func,
color_t *color, void *render_data)
{
int x2, y2; /* Coords of center sample */
double dx1, dy1; /* Delta to upper left sample */
double dx3, dy3; /* Delta to lower right sample */
color_t c1, c2, c3, c4; /* Sample colors */
unsigned long num_samples;
/* Get offsets for corners */
dx1 = (double) (x1 - sub_pixel_size / 2) / sub_pixel_size;
dx3 = (double) (x3 - sub_pixel_size / 2) / sub_pixel_size;
dy1 = (double) (y1 - sub_pixel_size / 2) / sub_pixel_size;
dy3 = (double) (y3 - sub_pixel_size / 2) / sub_pixel_size;
num_samples = 0;
/* Render upper left sample */
if (!block[y1][x1].ready) {
num_samples++;
(*render_func)(x + dx1, y + dy1, &c1, render_data);
block[y1][x1].ready = 1;
block[y1][x1].color = c1;
} else
c1 = block[y1][x1].color;
/* Render upper right sample */
if (!block[y1][x3].ready) {
num_samples++;
(*render_func)(x + dx3, y + dy1, &c2, render_data);
block[y1][x3].ready = 1;
block[y1][x3].color = c2;
} else
c2 = block[y1][x3].color;
/* Render lower left sample */
if (!block[y3][x1].ready) {
num_samples++;
(*render_func)(x + dx1, y + dy3, &c3, render_data);
block[y3][x1].ready = 1;
block[y3][x1].color = c3;
} else
c3 = block[y3][x1].color;
/* Render lower right sample */
if (!block[y3][x3].ready) {
num_samples++;
(*render_func)(x + dx3, y + dy3, &c4, render_data);
block[y3][x3].ready = 1;
block[y3][x3].color = c4;
} else
c4 = block[y3][x3].color;
/* Check for supersampling */
if (depth <= max_depth) {
/* Check whether we have tu supersample */
if ((color_dist(c1, c2) >= threshold) ||
(color_dist(c1, c3) >= threshold) ||
(color_dist(c1, c4) >= threshold) ||
(color_dist(c2, c3) >= threshold) ||
(color_dist(c2, c4) >= threshold) ||
(color_dist(c3, c4) >= threshold)) {
/* Calc coordinates of center subsample */
x2 = (x1 + x3) / 2;
y2 = (y1 + y3) / 2;
/* Render sub-blocks */
num_samples += render_sub_pixel(max_depth, depth + 1, block, x, y, x1, y1, x2, y2,
threshold, sub_pixel_size, render_func, &c1,
render_data);
num_samples += render_sub_pixel(max_depth, depth + 1, block, x, y, x2, y1, x3, y2,
threshold, sub_pixel_size, render_func, &c2,
render_data);
num_samples += render_sub_pixel(max_depth, depth + 1, block, x, y, x1, y2, x2, y3,
threshold, sub_pixel_size, render_func, &c3,
render_data);
num_samples += render_sub_pixel(max_depth, depth + 1, block, x, y, x2, y2, x3, y3,
threshold, sub_pixel_size, render_func, &c4,
render_data);
} /* if */
} /* if */
color->r = 0.25 * (c1.r + c2.r + c3.r + c4.r);
color->g = 0.25 * (c1.g + c2.g + c3.g + c4.g);
color->b = 0.25 * (c1.b + c2.b + c3.b + c4.b);
color->a = 0.25 * (c1.a + c2.a + c3.a + c4.a);
return num_samples;
} /* render_sub_pixel */
/*****/
static double
color_dist(color_t c1, color_t c2)
{
return fabs(c1.r - c2.r) +
fabs(c1.g - c2.g) +
fabs(c1.b - c2.b) +
fabs(c1.a - c2.a);
} /* color_dist */

View File

@ -0,0 +1,47 @@
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* General, non-jittered adaptive supersampling library
* Copyright (C) 1997 Federico Mena Quintero
*
* 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 of the License, 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __ASUPSAMPLE_H__
#define __ASUPSAMPLE_H__
/***** Types *****/
typedef struct {
double r, g, b, a; /* Range is [0, 1] */
} color_t;
typedef void (*render_func_t) (double x, double y, color_t *color, void *render_data);
typedef void (*put_pixel_func_t) (int x, int y, color_t color, void *put_pixel_data);
typedef void (*progress_func_t) (int y1, int y2, int curr_y, void *progress_data);
/***** Functions *****/
unsigned long adaptive_supersample_area(int x1, int y1, int x2, int y2, int max_depth, double threshold,
render_func_t render_func, void *render_data,
put_pixel_func_t put_pixel_func, void *put_pixel_data,
progress_func_t progress_func, void *progress_data);
#endif

5666
plug-ins/gflare/gflare.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
GIMP GFlare 0.25
100.000000 NORMAL
100.000000 NORMAL
75.000000 SCREEN
Flare_Glow_Radial_1
%white
%white
75.000000 0.000000 0.000000
Flare_Rays_Radial_1
%white
Flare_Rays_Size_1
100.000000 -75.000000 0.000000
16 20.000000
%blue_grad
%random
%random
16.000000 0.000000 13.600000
POLYGON 6 1

View File

@ -0,0 +1,18 @@
GIMP GFlare 0.25
100.000000 NORMAL
40.000000 SCREEN
20.000000 SCREEN
Flare_Glow_Radial_3
%white
%white
85.000000 0.000000 0.000000
%white_grad
%white
%random
125.000000 0.000000 0.000000
85 60.000000
Flare_Glow_Radial_4
%random
%random
20.000000 0.000000 0.000000
CIRCLE 6 1

View File

@ -0,0 +1,18 @@
GIMP GFlare 0.25
95.300003 NORMAL
23.000000 ADDITION
20.900000 SCREEN
Radial_Glow_1
%white
%white
100.000000 0.000000 -145.899994
%white_grad
%white_grad
%random
70.400002 0.000000 0.000000
21 87.300003
Flare_Radial_103
Flare_Sizefac_101
%random
40.000000 0 0
CIRCLE 6 1

View File

@ -0,0 +1,18 @@
GIMP GFlare 0.25
100.000000 NORMAL
90.000000 ADDITION
50.000000 SCREEN
Flare_Radial_102
%white
%white
136.000000 0.000000 55.000000
%yellow_grad
Flare_Glow_Angular_1
%random
110.000000 140.000000 -12.000000
63 90.000000
Flare_Glow_Radial_4
Flare_Rays_Size_1
%yellow_grad
30.000000 30.000000 40.000000
POLYGON 6 1

View File

@ -0,0 +1,18 @@
GIMP GFlare 0.25
100.000000 NORMAL
50.000000 NORMAL
35.500000 NORMAL
Flare_Radial_101
%white
%white
100.000000 0.000000 0.000000
%white_grad
%random
%random
100.000000 0.000000 0.000000
40 50.000000
Flare_Glow_Radial_1
%random
%random
40.000000 0 0
CIRCLE 6 1

View File

@ -0,0 +1,18 @@
GIMP GFlare 0.25
100.000000 NORMAL
62.799999 NORMAL
37.900002 SCREEN
Flare_Radial_102
%white
%white
100.000000 0.000000 -85.300003
%red_grad
%random
%random
100.000000 0.000000 -155.899994
40 20.000000
Flare_Radial_102
%random
Skyline
40.000000 0 0
CIRCLE 6 3

View File

@ -0,0 +1,18 @@
GIMP GFlare 0.25
100.000000 NORMAL
100.000000 NORMAL
100.000000 NORMAL
Flare_Glow_Radial_2
Flare_Glow_Angular_1
%white
100.000000 0.000000 0.000000
Flare_Rays_Radial_2
%white
%white
50.000000 90.000000 0.000000
2 85.000000
%white
%white
%white
0.000000 0.000000 0.000000
CIRCLE 6 1

View File

@ -0,0 +1,19 @@
## Process this file with automake to produce Makefile.in
gflaredir = $(gimpdatadir)/gflare
gflare_DATA = \
Bright_Star \
Classic \
Distant_Sun \
Default \
GFlare_101 \
GFlare_102 \
Hidden_Planet
EXTRA_DIST = $(gflare_DATA)
files:
@files=`ls $(DISTFILES) 2> /dev/null`; for p in $$files; do \
echo $$p; \
done

View File

@ -0,0 +1,671 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
Modified 97-06-26 Eiichi Takamori <taka@ma1.seikyou.ne.jp>
GtkMultiOptionMenu, taken from GtkOptionMenu, can work with
hierarchal menus.
*/
#include "gtk/gtkmenu.h"
#include "gtk/gtkmenuitem.h"
#include "gtkmultioptionmenu.h"
#include "gtk/gtksignal.h"
#define CHILD_LEFT_SPACING 5
#define CHILD_RIGHT_SPACING 1
#define CHILD_TOP_SPACING 1
#define CHILD_BOTTOM_SPACING 1
#define MULTI_OPTION_INDICATOR_WIDTH 12
#define MULTI_OPTION_INDICATOR_HEIGHT 8
#define MULTI_OPTION_INDICATOR_SPACING 2
static void gtk_multi_option_menu_class_init (GtkMultiOptionMenuClass *klass);
static void gtk_multi_option_menu_init (GtkMultiOptionMenu *multi_option_menu);
static void gtk_multi_option_menu_destroy (GtkObject *object);
static void gtk_multi_option_menu_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_multi_option_menu_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_multi_option_menu_paint (GtkWidget *widget,
GdkRectangle *area);
static void gtk_multi_option_menu_draw (GtkWidget *widget,
GdkRectangle *area);
static gint gtk_multi_option_menu_expose (GtkWidget *widget,
GdkEventExpose *event);
static gint gtk_multi_option_menu_button_press (GtkWidget *widget,
GdkEventButton *event);
static void gtk_multi_option_menu_deactivate (GtkMenuShell *menu_shell,
GtkMultiOptionMenu *multi_option_menu);
static void gtk_multi_option_menu_update_contents (GtkMultiOptionMenu *multi_option_menu);
static void gtk_multi_option_menu_remove_contents (GtkMultiOptionMenu *multi_option_menu);
static void gtk_multi_option_menu_calc_size (GtkMultiOptionMenu *multi_option_menu);
static void gtk_multi_option_menu_calc_size_recursive (GtkMultiOptionMenu *multi_option_menu, GtkWidget *menu);
static void gtk_multi_option_menu_position (GtkMenu *menu,
gint *x,
gint *y,
gpointer user_data);
static void gtk_multi_option_menu_show_all (GtkWidget *widget);
static void gtk_multi_option_menu_hide_all (GtkWidget *widget);
static GtkButtonClass *parent_class = NULL;
guint
gtk_multi_option_menu_get_type ()
{
static guint multi_option_menu_type = 0;
if (!multi_option_menu_type)
{
GtkTypeInfo multi_option_menu_info =
{
"GtkMultiOptionMenu",
sizeof (GtkMultiOptionMenu),
sizeof (GtkMultiOptionMenuClass),
(GtkClassInitFunc) gtk_multi_option_menu_class_init,
(GtkObjectInitFunc) gtk_multi_option_menu_init,
NULL,
NULL,
(GtkClassInitFunc) NULL,
};
multi_option_menu_type = gtk_type_unique (gtk_button_get_type (), &multi_option_menu_info);
}
return multi_option_menu_type;
}
static void
gtk_multi_option_menu_class_init (GtkMultiOptionMenuClass *class)
{
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkButtonClass *button_class;
object_class = (GtkObjectClass*) class;
widget_class = (GtkWidgetClass*) class;
button_class = (GtkButtonClass*) class;
parent_class = gtk_type_class (gtk_button_get_type ());
object_class->destroy = gtk_multi_option_menu_destroy;
widget_class->draw = gtk_multi_option_menu_draw;
widget_class->draw_focus = NULL;
widget_class->size_request = gtk_multi_option_menu_size_request;
widget_class->size_allocate = gtk_multi_option_menu_size_allocate;
widget_class->expose_event = gtk_multi_option_menu_expose;
widget_class->button_press_event = gtk_multi_option_menu_button_press;
widget_class->show_all = gtk_multi_option_menu_show_all;
widget_class->hide_all = gtk_multi_option_menu_hide_all;
}
static void
gtk_multi_option_menu_init (GtkMultiOptionMenu *multi_option_menu)
{
GTK_WIDGET_UNSET_FLAGS (multi_option_menu, GTK_CAN_FOCUS);
multi_option_menu->menu = NULL;
multi_option_menu->menu_item = NULL;
multi_option_menu->width = 0;
multi_option_menu->height = 0;
}
GtkWidget*
gtk_multi_option_menu_new ()
{
return GTK_WIDGET (gtk_type_new (gtk_multi_option_menu_get_type ()));
}
GtkWidget*
gtk_multi_option_menu_get_menu (GtkMultiOptionMenu *multi_option_menu)
{
g_return_val_if_fail (multi_option_menu != NULL, NULL);
g_return_val_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu), NULL);
return multi_option_menu->menu;
}
static void
gtk_multi_option_menu_detacher (GtkWidget *widget,
GtkMenu *menu)
{
GtkMultiOptionMenu *multi_option_menu;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (widget));
multi_option_menu = GTK_MULTI_OPTION_MENU (widget);
g_return_if_fail (multi_option_menu->menu == (GtkWidget*) menu);
gtk_multi_option_menu_remove_contents (multi_option_menu);
gtk_signal_disconnect_by_data (GTK_OBJECT (multi_option_menu->menu),
multi_option_menu);
multi_option_menu->menu = NULL;
}
void
gtk_multi_option_menu_set_menu (GtkMultiOptionMenu *multi_option_menu,
GtkWidget *menu)
{
g_return_if_fail (multi_option_menu != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu));
g_return_if_fail (menu != NULL);
g_return_if_fail (GTK_IS_MENU (menu));
if (multi_option_menu->menu != menu)
{
gtk_multi_option_menu_remove_menu (multi_option_menu);
multi_option_menu->menu = menu;
gtk_menu_attach_to_widget (GTK_MENU (menu),
GTK_WIDGET (multi_option_menu),
gtk_multi_option_menu_detacher);
gtk_multi_option_menu_calc_size (multi_option_menu);
gtk_signal_connect (GTK_OBJECT (multi_option_menu->menu), "deactivate",
(GtkSignalFunc) gtk_multi_option_menu_deactivate,
multi_option_menu);
if (GTK_WIDGET (multi_option_menu)->parent)
gtk_widget_queue_resize (GTK_WIDGET (multi_option_menu)->parent);
gtk_multi_option_menu_update_contents (multi_option_menu);
}
}
void
gtk_multi_option_menu_remove_menu (GtkMultiOptionMenu *multi_option_menu)
{
g_return_if_fail (multi_option_menu != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu));
if (multi_option_menu->menu)
gtk_menu_detach (GTK_MENU (multi_option_menu->menu));
}
void
gtk_multi_option_menu_set_history (GtkMultiOptionMenu *multi_option_menu,
gint index)
{
GtkWidget *menu_item;
g_return_if_fail (multi_option_menu != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu));
if (multi_option_menu->menu)
{
gtk_menu_set_active (GTK_MENU (multi_option_menu->menu), index);
menu_item = gtk_menu_get_active (GTK_MENU (multi_option_menu->menu));
if (menu_item != multi_option_menu->menu_item)
{
gtk_multi_option_menu_remove_contents (multi_option_menu);
gtk_multi_option_menu_update_contents (multi_option_menu);
}
}
}
static void
gtk_multi_option_menu_destroy (GtkObject *object)
{
GtkMultiOptionMenu *multi_option_menu;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (object));
multi_option_menu = GTK_MULTI_OPTION_MENU (object);
if (multi_option_menu->menu)
gtk_widget_destroy (multi_option_menu->menu);
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
static void
gtk_multi_option_menu_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
GtkMultiOptionMenu *multi_option_menu;
gint tmp;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (widget));
g_return_if_fail (requisition != NULL);
multi_option_menu = GTK_MULTI_OPTION_MENU (widget);
requisition->width = ((GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->klass->xthickness) * 2 +
multi_option_menu->width +
MULTI_OPTION_INDICATOR_WIDTH +
MULTI_OPTION_INDICATOR_SPACING * 5 +
CHILD_LEFT_SPACING + CHILD_RIGHT_SPACING);
requisition->height = ((GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->klass->ythickness) * 2 +
multi_option_menu->height +
CHILD_TOP_SPACING + CHILD_BOTTOM_SPACING);
tmp = (requisition->height - multi_option_menu->height +
MULTI_OPTION_INDICATOR_HEIGHT + MULTI_OPTION_INDICATOR_SPACING * 2);
requisition->height = MAX (requisition->height, tmp);
}
static void
gtk_multi_option_menu_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkWidget *child;
GtkAllocation child_allocation;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (widget));
g_return_if_fail (allocation != NULL);
widget->allocation = *allocation;
if (GTK_WIDGET_REALIZED (widget))
gdk_window_move_resize (widget->window,
allocation->x, allocation->y,
allocation->width, allocation->height);
child = GTK_BUTTON (widget)->child;
if (child && GTK_WIDGET_VISIBLE (child))
{
child_allocation.x = (GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->klass->xthickness);
child_allocation.y = (GTK_CONTAINER (widget)->border_width +
GTK_WIDGET (widget)->style->klass->ythickness);
child_allocation.width = (allocation->width - child_allocation.x * 2 -
MULTI_OPTION_INDICATOR_WIDTH - MULTI_OPTION_INDICATOR_SPACING * 5 -
CHILD_LEFT_SPACING - CHILD_RIGHT_SPACING);
child_allocation.height = (allocation->height - child_allocation.y * 2 -
CHILD_TOP_SPACING - CHILD_BOTTOM_SPACING);
child_allocation.x += CHILD_LEFT_SPACING;
child_allocation.y += CHILD_RIGHT_SPACING;
gtk_widget_size_allocate (child, &child_allocation);
}
}
static void
gtk_multi_option_menu_paint (GtkWidget *widget,
GdkRectangle *area)
{
GdkRectangle restrict_area;
GdkRectangle new_area;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (widget));
g_return_if_fail (area != NULL);
if (GTK_WIDGET_DRAWABLE (widget))
{
restrict_area.x = GTK_CONTAINER (widget)->border_width;
restrict_area.y = GTK_CONTAINER (widget)->border_width;
restrict_area.width = widget->allocation.width - restrict_area.x * 2;
restrict_area.height = widget->allocation.height - restrict_area.y * 2;
if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
{
gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget));
gdk_window_clear_area (widget->window,
new_area.x, new_area.y,
new_area.width, new_area.height);
gtk_draw_shadow (widget->style, widget->window,
GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
restrict_area.x, restrict_area.y,
restrict_area.width, restrict_area.height);
gtk_draw_shadow (widget->style, widget->window,
GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
restrict_area.x + restrict_area.width - restrict_area.x -
MULTI_OPTION_INDICATOR_WIDTH - MULTI_OPTION_INDICATOR_SPACING * 4,
restrict_area.y + (restrict_area.height - MULTI_OPTION_INDICATOR_HEIGHT) / 2,
MULTI_OPTION_INDICATOR_WIDTH, MULTI_OPTION_INDICATOR_HEIGHT);
}
}
}
static void
gtk_multi_option_menu_draw (GtkWidget *widget,
GdkRectangle *area)
{
GtkWidget *child;
GdkRectangle child_area;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (widget));
g_return_if_fail (area != NULL);
if (GTK_WIDGET_DRAWABLE (widget))
{
gtk_multi_option_menu_paint (widget, area);
child = GTK_BUTTON (widget)->child;
if (child && gtk_widget_intersect (child, area, &child_area))
gtk_widget_draw (child, &child_area);
}
}
static gint
gtk_multi_option_menu_expose (GtkWidget *widget,
GdkEventExpose *event)
{
GtkWidget *child;
GdkEventExpose child_event;
gint remove_child;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_MULTI_OPTION_MENU (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
if (GTK_WIDGET_DRAWABLE (widget))
{
gtk_multi_option_menu_paint (widget, &event->area);
remove_child = FALSE;
child = GTK_BUTTON (widget)->child;
if (!child)
{
if (!GTK_MULTI_OPTION_MENU (widget)->menu)
return FALSE;
gtk_multi_option_menu_update_contents (GTK_MULTI_OPTION_MENU (widget));
child = GTK_BUTTON (widget)->child;
remove_child = TRUE;
}
child_event = *event;
if (GTK_WIDGET_NO_WINDOW (child) &&
gtk_widget_intersect (child, &event->area, &child_event.area))
gtk_widget_event (child, (GdkEvent*) &child_event);
if (remove_child)
gtk_multi_option_menu_remove_contents (GTK_MULTI_OPTION_MENU (widget));
}
return FALSE;
}
static gint
gtk_multi_option_menu_button_press (GtkWidget *widget,
GdkEventButton *event)
{
GtkMultiOptionMenu *multi_option_menu;
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_MULTI_OPTION_MENU (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
if ((event->type == GDK_BUTTON_PRESS) &&
(event->button == 1))
{
multi_option_menu = GTK_MULTI_OPTION_MENU (widget);
gtk_multi_option_menu_remove_contents (multi_option_menu);
gtk_menu_popup (GTK_MENU (multi_option_menu->menu), NULL, NULL,
gtk_multi_option_menu_position, multi_option_menu,
event->button, event->time);
}
return FALSE;
}
static void
gtk_multi_option_menu_deactivate (GtkMenuShell *menu_shell,
GtkMultiOptionMenu *multi_option_menu)
{
g_return_if_fail (menu_shell != NULL);
g_return_if_fail (multi_option_menu != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu));
gtk_multi_option_menu_update_contents (multi_option_menu);
}
static void
gtk_multi_option_menu_update_contents (GtkMultiOptionMenu *multi_option_menu)
{
GtkWidget *child;
GtkWidget *submenu;
GtkWidget *menu_item;
g_return_if_fail (multi_option_menu != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu));
if (multi_option_menu->menu)
{
gtk_multi_option_menu_remove_contents (multi_option_menu);
menu_item = gtk_menu_get_active (GTK_MENU (multi_option_menu->menu));
while (menu_item && GTK_IS_MENU_ITEM (menu_item) && GTK_MENU_ITEM (menu_item)->submenu)
{
submenu = GTK_MENU_ITEM (menu_item)->submenu;
menu_item = gtk_menu_get_active (GTK_MENU (submenu));
}
multi_option_menu->menu_item = menu_item;
if (multi_option_menu->menu_item)
{
gtk_widget_ref (multi_option_menu->menu_item);
child = GTK_BIN (multi_option_menu->menu_item)->child;
if (child)
{
/*gtk_container_block_resize (GTK_CONTAINER (multi_option_menu));*/
if (GTK_WIDGET (multi_option_menu)->state != child->state)
gtk_widget_set_state (child, GTK_WIDGET (multi_option_menu)->state);
gtk_widget_reparent (child, GTK_WIDGET (multi_option_menu));
/*gtk_container_unblock_resize (GTK_CONTAINER (multi_option_menu));*/
}
gtk_widget_size_request (child, &child->requisition);
gtk_widget_size_allocate (GTK_WIDGET (multi_option_menu),
&(GTK_WIDGET (multi_option_menu)->allocation));
if (GTK_WIDGET_DRAWABLE (multi_option_menu))
gtk_widget_queue_draw (GTK_WIDGET (multi_option_menu));
}
}
}
static void
gtk_multi_option_menu_remove_contents (GtkMultiOptionMenu *multi_option_menu)
{
g_return_if_fail (multi_option_menu != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu));
if (GTK_BUTTON (multi_option_menu)->child)
{
/*gtk_container_block_resize (GTK_CONTAINER (multi_option_menu));*/
if (GTK_WIDGET (multi_option_menu->menu_item)->state != GTK_BUTTON (multi_option_menu)->child->state)
gtk_widget_set_state (GTK_BUTTON (multi_option_menu)->child,
GTK_WIDGET (multi_option_menu->menu_item)->state);
gtk_widget_unrealize (GTK_BUTTON (multi_option_menu)->child);
gtk_widget_reparent (GTK_BUTTON (multi_option_menu)->child, multi_option_menu->menu_item);
gtk_widget_unref (multi_option_menu->menu_item);
multi_option_menu->menu_item = NULL;
/*gtk_container_unblock_resize (GTK_CONTAINER (multi_option_menu));*/
}
}
static void
gtk_multi_option_menu_calc_size (GtkMultiOptionMenu *multi_option_menu)
{
g_return_if_fail (multi_option_menu != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu));
multi_option_menu->width = 0;
multi_option_menu->height = 0;
if (multi_option_menu->menu)
{
gtk_multi_option_menu_calc_size_recursive (multi_option_menu, multi_option_menu->menu);
}
}
static void
gtk_multi_option_menu_calc_size_recursive (GtkMultiOptionMenu *multi_option_menu, GtkWidget *menu)
{
GtkWidget *child;
GList *children;
g_return_if_fail (multi_option_menu != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (multi_option_menu));
g_return_if_fail (menu != NULL);
g_return_if_fail (GTK_IS_MENU (menu));
children = GTK_MENU_SHELL (menu)->children;
while (children)
{
child = children->data;
children = children->next;
if (GTK_WIDGET_VISIBLE (child))
{
gtk_widget_size_request (child, &child->requisition);
multi_option_menu->width = MAX (multi_option_menu->width, child->requisition.width);
multi_option_menu->height = MAX (multi_option_menu->height, child->requisition.height);
if (GTK_IS_MENU_ITEM (child) && GTK_MENU_ITEM (child)->submenu)
gtk_multi_option_menu_calc_size_recursive (multi_option_menu, GTK_MENU_ITEM (child)->submenu);
}
}
}
static void
gtk_multi_option_menu_position (GtkMenu *menu,
gint *x,
gint *y,
gpointer user_data)
{
GtkMultiOptionMenu *multi_option_menu;
GtkWidget *active;
GtkWidget *child;
GList *children;
gint shift_menu;
gint screen_width;
gint screen_height;
gint menu_xpos;
gint menu_ypos;
gint width;
gint height;
g_return_if_fail (user_data != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (user_data));
multi_option_menu = GTK_MULTI_OPTION_MENU (user_data);
width = GTK_WIDGET (menu)->allocation.width;
height = GTK_WIDGET (menu)->allocation.height;
active = gtk_menu_get_active (GTK_MENU (multi_option_menu->menu));
children = GTK_MENU_SHELL (multi_option_menu->menu)->children;
gdk_window_get_origin (GTK_WIDGET (multi_option_menu)->window, &menu_xpos, &menu_ypos);
menu_ypos += (GTK_WIDGET (multi_option_menu)->allocation.height) / 2 - 2;
if (active != NULL)
menu_ypos -= active->requisition.height / 2;
while (children)
{
child = children->data;
if (active == child)
break;
menu_ypos -= child->allocation.height;
children = children->next;
}
screen_width = gdk_screen_width ();
screen_height = gdk_screen_height ();
shift_menu = FALSE;
if (menu_ypos < 0)
{
menu_ypos = 0;
shift_menu = TRUE;
}
else if ((menu_ypos + height) > screen_height)
{
menu_ypos -= ((menu_ypos + height) - screen_height);
shift_menu = TRUE;
}
if (shift_menu)
{
if ((menu_xpos + GTK_WIDGET (multi_option_menu)->allocation.width + width) <= screen_width)
menu_xpos += GTK_WIDGET (multi_option_menu)->allocation.width;
else
menu_xpos -= width;
}
if (menu_xpos < 0)
menu_xpos = 0;
else if ((menu_xpos + width) > screen_width)
menu_xpos -= ((menu_xpos + width) - screen_width);
*x = menu_xpos;
*y = menu_ypos;
}
static void
gtk_multi_option_menu_show_all (GtkWidget *widget)
{
GtkContainer *container;
GtkMultiOptionMenu *multi_option_menu;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (widget));
container = GTK_CONTAINER (widget);
multi_option_menu = GTK_MULTI_OPTION_MENU (widget);
gtk_widget_show (widget);
gtk_container_foreach (container, (GtkCallback) gtk_widget_show_all, NULL);
if (multi_option_menu->menu)
gtk_widget_show_all (multi_option_menu->menu);
if (multi_option_menu->menu_item)
gtk_widget_show_all (multi_option_menu->menu_item);
}
static void
gtk_multi_option_menu_hide_all (GtkWidget *widget)
{
GtkContainer *container;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_MULTI_OPTION_MENU (widget));
container = GTK_CONTAINER (widget);
gtk_widget_hide (widget);
gtk_container_foreach (container, (GtkCallback) gtk_widget_hide_all, NULL);
}

View File

@ -0,0 +1,78 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
Modified 97-06-26 Eiichi Takamori <taka@ma1.seikyou.ne.jp>
GtkMultiOptionMenu, taken from GtkOptionMenu, can work with
hierarchal menus.
*/
#ifndef __GTK_MULTI_OPTION_MENU_H__
#define __GTK_MULTI_OPTION_MENU_H__
#include <gdk/gdk.h>
#include <gtk/gtkbutton.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define GTK_MULTI_OPTION_MENU(obj) GTK_CHECK_CAST (obj, gtk_multi_option_menu_get_type (), GtkMultiOptionMenu)
#define GTK_MULTI_OPTION_MENU_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_multi_option_menu_get_type (), GtkMultiOptionMenuClass)
#define GTK_IS_MULTI_OPTION_MENU(obj) GTK_CHECK_TYPE (obj, gtk_multi_option_menu_get_type ())
typedef struct _GtkMultiOptionMenu GtkMultiOptionMenu;
typedef struct _GtkMultiOptionMenuClass GtkMultiOptionMenuClass;
struct _GtkMultiOptionMenu
{
GtkButton button;
GtkWidget *menu;
GtkWidget *menu_item;
guint16 width;
guint16 height;
};
struct _GtkMultiOptionMenuClass
{
GtkButtonClass parent_class;
};
guint gtk_multi_option_menu_get_type (void);
GtkWidget* gtk_multi_option_menu_new (void);
GtkWidget* gtk_multi_option_menu_get_menu (GtkMultiOptionMenu *multi_option_menu);
void gtk_multi_option_menu_set_menu (GtkMultiOptionMenu *multi_option_menu,
GtkWidget *menu);
void gtk_multi_option_menu_remove_menu (GtkMultiOptionMenu *multi_option_menu);
void gtk_multi_option_menu_set_history (GtkMultiOptionMenu *multi_option_menu,
gint index);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GTK_MULTI_OPTION_MENU_H__ */