1
/* Copyright (C) 2000-2004 Thomas Bopp, Thorsten Hampel, Ludger Merkens
3
* This program is free software; you can redistribute it and/or modify
4
* it under the terms of the GNU General Public License as published by
5
* the Free Software Foundation; either version 2 of the License, or
6
* (at your option) any later version.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program; if not, write to the Free Software
15
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
* $Id: button.pike,v 1.1.1.1 2005/02/23 14:47:21 cvs Exp $
20
constant cvs_version="$Id: button.pike,v 1.1.1.1 2005/02/23 14:47:21 cvs Exp $";
22
inherit "/kernel/module";
27
Image.Layer layer_slice( Image.Layer l, int from, int to )
29
return Image.Layer( ([
30
"image":l->image()->copy( from,0, to-1, l->ysize()-1 ),
31
"alpha":l->alpha()->copy( from,0, to-1, l->ysize()-1 ),
35
Image.Layer stretch_layer( Image.Layer o, int x1, int x2, int w )
38
int leftovers = w - (x1 + (o->xsize()-x2) );
41
l = layer_slice( o, 0, x1 );
42
m = layer_slice( o, x1+1, x2-1 );
43
r = layer_slice( o, x2, o->xsize() );
45
m->set_image( m->image()->scale( leftovers, l->ysize() ),
46
m->alpha()->scale( leftovers, l->ysize() ));
49
m->set_offset( x1,0 );
50
r->set_offset( w-r->xsize(),0 );
51
o = Image.lay( ({ l, m, r }) );
52
o->set_mode( oo->mode() );
53
o->set_alpha_value( oo->alpha_value() );
57
mapping load_icon(string path)
59
werror("Loading Icon="+path+"\n");
63
array(Image.Layer) load_layers(string path)
65
object obj = _FILEPATH->path_to_object(path);
66
string data = obj->get_content();
67
return Image.decode_layers(data);
70
Image.Font resolve_font(string font)
72
object fontobj = Image.Font();
74
fontobj->load("server/modules/test.fnt");
78
array(Image.Layer)|mapping draw_button(mapping args, string text)
83
Image.Layer background;
87
int left, right, top, middle, bottom; /* offsets */
88
int req_width, noframe;
92
void set_image( array layers )
94
foreach( layers||({}), object l )
96
if(!l->get_misc_value( "name" ) ) // Hm. Probably PSD
99
ll[lower_case(l->get_misc_value( "name" ))] = l;
100
switch( lower_case(l->get_misc_value( "name" )) )
102
case "background": background = l; break;
103
case "frame": frame = l; break;
104
case "mask": mask = l; break;
109
if( args->border_image )
111
array(Image.Layer)|mapping tmp = load_layers(args->border_image);
113
if (tmp->error == 401)
116
error("GButton: Failed to load frame image: %O\n",
122
// otherwise load default images
123
if ( !frame && !background && !mask )
125
string data = Stdio.read_file("gbutton.xcf");
127
error ("Failed to load default frame image "
128
"(roxen-images/gbutton.xcf): " + strerror (errno()));
130
set_image(Image.XCF.decode_layers(data));
134
catch (err[0] = "Failed to decode default frame image "
135
"(gbutton.xcf): " + err[0]);
139
error("Failed to decode default frame image "
140
"(roxen-images/gbutton.xcf).\n");
146
frame = background || mask; // for sizes offsets et.al.
149
// Translate frame image to 0,0 (left layers are most likely to the
150
// left of the frame image)
151
int x0 = frame->xoffset();
152
int y0 = frame->yoffset();
154
foreach( values( ll ), object l )
156
int x = l->xoffset();
157
int y = l->yoffset();
158
l->set_offset( x-x0, y-y0 );
167
foreach( frame->get_misc_value( "image_guides" ), object g )
169
x += ({ g->pos - x0 });
171
y += ({ g->pos - y0 });
177
x = ({ 5, frame->xsize()-5 });
180
y = ({ 2, frame->ysize()-2 });
182
left = x[0]; right = x[-1]; top = y[0]; middle = y[1]; bottom = y[-1];
183
right = frame->xsize()-right;
185
// Text height depends on which guides we should align to
187
switch (args->icva) {
189
text_height = bottom - middle;
192
text_height = middle - top;
196
text_height = bottom - top;
202
icon = load_icon(args->icn);
204
icon = load_icon(args->icd);
206
int i_width = icon && icon->img->xsize();
207
int i_height = icon && icon->img->ysize();
208
int i_spc = i_width && sizeof(text) && 5;
214
Image.Font button_font;
215
int th = text_height;
218
button_font = resolve_font( args->font+" "+th );
219
text_img = button_font->write(text);
220
os = text_img->ysize();
222
if( os < text_height )
224
else if( os > text_height )
226
if( dir > 0 && os > text_height ) break;
227
else if( dir < 0 && os < text_height ) dir = 1;
228
else if( os == text_height ) break;
230
} while( (text_img->ysize() - text_height)
231
&& (th>0 && th<text_height*2));
233
// fonts that can not be scaled.
234
if( abs(text_img->ysize() - text_height)>2 )
235
text_img = text_img->scale(0, text_height );
238
int o = text_img->ysize() - text_height;
243
text_img = text_img->scale((int) round(text_img->xsize() * 0.8),
248
int t_width = text_img && text_img->xsize();
250
// Compute text and icon placement. Only incorporate icon width/spacing if
251
// it's placed inline with the text.
252
req_width = t_width + left + right;
253
if ((args->icva || "middle") == "middle")
254
req_width += i_width + i_spc;
255
if (args->wi && (req_width < args->wi))
256
req_width = args->wi;
258
int icn_x, icn_y, txt_x, txt_y;
260
// Are text and icon lined up or on separate lines?
261
switch (args->icva) {
264
// Note: This requires _three_ guidelines! Icon and text can only be
265
// horizontally centered
266
icn_x = left + (req_width - right - left - i_width) / 2;
267
txt_x = left + (req_width - right - left - t_width) / 2;
268
if (args->icva == "above" || !text_height) {
270
icn_y = top + ((text_height ? middle : bottom) - top - i_height) / 2;
273
icn_y = middle + (bottom - middle - i_height) / 2;
279
// Center icon vertically on same line as text
280
icn_y = icon && (frame->ysize() - icon->img->ysize()) / 2;
286
// Allow icon alignment: left, right
291
txt_x = icn_x + i_width + i_spc;
296
icn_x = req_width - right - i_width;
304
// Allow icon alignment:
305
// left, center, center-before, center-after, right
310
txt_x = (req_width - right - left - i_width - i_spc - t_width) / 2;
311
txt_x += icn_x + i_width + i_spc;
315
case "center_before":
316
case "center-before":
317
icn_x = (req_width - i_width - i_spc - t_width) / 2;
318
txt_x = icn_x + i_width + i_spc;
322
txt_x = (req_width - i_width - i_spc - t_width) / 2;
323
icn_x = txt_x + t_width + i_spc;
326
icn_x = req_width - right - i_width;
327
txt_x = left + (icn_x - i_spc - t_width - left) / 2;
333
// Allow icon alignment: left, right
339
txt_x = req_width - right - t_width;
342
icn_x = req_width - right - i_width;
343
txt_x = icn_x - i_spc - t_width;
351
if( args->extra_frame_layers )
354
foreach( args->extra_frame_layers/",", string q )
358
frame = Image.lay( l+(noframe?({}):({frame})) );
361
if( args->extra_mask_layers )
364
foreach( args->extra_mask_layers/",", string q )
371
mask = Image.lay( l );
375
right = frame->xsize()-right;
378
Image.Image i = mask->image();
379
Image.Image m = mask->alpha();
380
int x0 = -mask->xoffset();
381
int y0 = -mask->yoffset();
382
int x1 = frame->xsize()-1+x0;
383
int y1 = frame->ysize()-1+y0;
385
i = i->copy(x0,y0, x1,y1);
387
m = m->copy(x0,y0, x1,y1);
388
mask->set_image( i, m );
389
mask = stretch_layer( mask, left, right, req_width );
391
if( frame != background )
392
frame = stretch_layer( frame, left, right, req_width );
393
array(Image.Layer) button_layers = ({
394
Image.Layer( Image.Image(req_width, frame->ysize(), args->bg),
395
mask->alpha()->copy(0,0,req_width-1,frame->ysize()-1)),
399
if( args->extra_background_layers || background)
401
array l = ({ background });
402
foreach( (args->extra_background_layers||"")/","-({""}), string q )
405
foreach( l, object ll )
408
ll->set_alpha_value( 0.3 );
409
button_layers += ({ stretch_layer( ll, left, right, req_width ) });
415
button_layers += ({ frame });
416
frame->set_mode( "value" );
421
// Adjust dimmed border intensity to the background
422
int bg_value = Image.Color(@args->bg)->hsv()[2];
423
int dim_high, dim_low;
424
if (bg_value < 128) {
425
dim_low = max(bg_value - 64, 0);
426
dim_high = dim_low + 128;
428
dim_high = min(bg_value + 64, 255);
429
dim_low = dim_high - 128;
431
frame->set_image(frame->image()->
432
modify_by_intensity( 1, 1, 1,
433
({ dim_low, dim_low, dim_low }),
434
({ dim_high, dim_high, dim_high })),
442
"alpha_value":(args->dim ? 0.3 : 1.0),
452
float ta = args->txtalpha?args->txtalpha:1.0;
456
"mode":args->txtmode,
457
"image":text_img->color(0,0,0)->invert()->color(@args->txt),
458
"alpha":(text_img*(args->dim?0.5*ta:ta)),
465
// 'plain' extra layers are added on top of everything else
466
if( args->extra_layers )
468
array q = map(args->extra_layers/",",
469
lambda(string q) { return ll[q]; } )-({0});
470
foreach( q, object ll )
473
ll->set_alpha_value( 0.3 );
474
button_layers += ({stretch_layer(ll,left,right,req_width)});
475
button_layers[-1]->set_offset( 0,
476
button_layers[0]->ysize()-
477
button_layers[-1]->ysize() );
481
button_layers -= ({ 0 });
482
// left layers are added to the left of the image, and the mask is
483
// extended using their mask. There is no corresponding 'mask' layers
484
// for these, but that is not a problem most of the time.
485
if( args->extra_left_layers )
488
foreach( args->extra_left_layers/",", string q )
491
l->set_offset( 0, 0 );
494
object q = Image.lay( l );
495
foreach( button_layers, object b )
497
int x = b->xoffset();
498
int y = b->yoffset();
499
b->set_offset( x+q->xsize(), y );
501
q->set_offset( 0, button_layers[0]->ysize()-q->ysize() );
502
button_layers += ({ q });
506
// right layers are added to the right of the image, and the mask is
507
// extended using their mask. There is no corresponding 'mask' layers
508
// for these, but that is not a problem most of the time.
509
if( args->extra_right_layers )
512
foreach( args->extra_right_layers/",", string q )
515
l->set_offset( 0, 0 );
518
object q = Image.lay( l );
519
q->set_offset( button_layers[0]->xsize()+
520
button_layers[0]->xoffset(),
521
button_layers[0]->ysize()-q->ysize());
522
button_layers += ({ q });
526
// if( !equal( args->pagebg, args->bg ) )
528
// FIXME: fix transparency (somewhat)
529
// this version totally destroys the alpha channel of the image,
530
// but that's sort of the intention. The reason is that
531
// the png images are generated without alpha.
532
if (args->format == "png")
533
return ({ Image.Layer(([ "fill":args->pagebg, ])) }) + button_layers;
535
return button_layers;
540
mixed tab(mapping args)
542
mapping gbutton_args = args;
546
if ( !stringp(args->frame_image) ) {
547
fimage = Stdio.read_file("tabframe.xcf");
548
gbutton_args["frame-image"] = fimage;
551
object fimg = _FILEPATH->path_to_object(args->frame_image);
552
fimage = fimg->get_content();
556
array(Image.Layer) button_layers;
557
if( args->selected ) {
558
//add_layers( gbutton_args, "selected" );
559
gbutton_args->bg = Colors.parse_color(args->selcolor || "white");
560
gbutton_args->txt = Colors.parse_color(args->seltextcolor || "black");
561
gbutton_args->txtmode = (args->textmode ||"normal");
562
button_layers = draw_button(gbutton_args, "Hello");
564
//add_layers( gbutton_args, "unselected" );
565
gbutton_args->bg = Colors.parse_color(args->dimcolor || "#003366");
566
gbutton_args->txt = Colors.parse_color(args->textcolor || "white");
567
gbutton_args->txtmode = (args->textmode ||"normal");
568
button_layers = draw_button(gbutton_args, args->text);
570
m_delete(gbutton_args, "selected");
571
m_delete(gbutton_args, "dimcolor");
572
m_delete(gbutton_args, "seltextcolor");
573
m_delete(gbutton_args, "selcolor");
574
m_delete(gbutton_args, "result");
575
return button_layers;
578
array(string) execute(mapping args)
580
array layers = tab(args);
581
object img = Image.lay( layers );
582
string str = Image.PNG->encode(img->image());
583
return ({ str, "image/gif" });
586
string get_identifier() { return "buttons"; }
589
void main(int argc, array argv)
592
object img = Image.lay( layers );
593
Stdio.write_file("test.jpg", Image.GIF->encode(img->image()));