~ubuntu-branches/ubuntu/natty/steam/natty

« back to all changes in this revision

Viewing changes to server/modules/button.pike

  • Committer: Bazaar Package Importer
  • Author(s): Alain Schroeder
  • Date: 2005-05-14 16:33:35 UTC
  • Revision ID: james.westby@ubuntu.com-20050514163335-5v7lbxibmlww15dx
Tags: upstream-1.6.3
ImportĀ upstreamĀ versionĀ 1.6.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2004  Thomas Bopp, Thorsten Hampel, Ludger Merkens
 
2
 *
 
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.
 
7
 *
 
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.
 
12
 *
 
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
 
16
 * 
 
17
 * $Id: button.pike,v 1.1.1.1 2005/02/23 14:47:21 cvs Exp $
 
18
 */
 
19
 
 
20
constant cvs_version="$Id: button.pike,v 1.1.1.1 2005/02/23 14:47:21 cvs Exp $";
 
21
 
 
22
inherit "/kernel/module";
 
23
 
 
24
#include <database.h>
 
25
#include <macros.h>
 
26
 
 
27
Image.Layer layer_slice( Image.Layer l, int from, int to )
 
28
{
 
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 ),
 
32
  ]) );
 
33
}
 
34
 
 
35
Image.Layer stretch_layer( Image.Layer o, int x1, int x2, int w )
 
36
{
 
37
  Image.Layer l, m, r;
 
38
  int leftovers = w - (x1 + (o->xsize()-x2) );
 
39
  object oo = o;
 
40
 
 
41
  l = layer_slice( o, 0, x1 );
 
42
  m = layer_slice( o, x1+1, x2-1 );
 
43
  r = layer_slice( o, x2, o->xsize() );
 
44
 
 
45
  m->set_image( m->image()->scale( leftovers, l->ysize() ),
 
46
                m->alpha()->scale( leftovers, l->ysize() ));
 
47
 
 
48
  l->set_offset(  0,0 );
 
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() );
 
54
  return o;
 
55
}
 
56
 
 
57
mapping load_icon(string path) 
 
58
{
 
59
    werror("Loading Icon="+path+"\n");
 
60
}
 
61
 
 
62
 
 
63
array(Image.Layer) load_layers(string path)
 
64
{
 
65
    object obj = _FILEPATH->path_to_object(path);
 
66
    string data = obj->get_content();
 
67
    return Image.decode_layers(data);
 
68
}
 
69
 
 
70
Image.Font resolve_font(string font)
 
71
{
 
72
    object fontobj = Image.Font();
 
73
    
 
74
    fontobj->load("server/modules/test.fnt");
 
75
    return fontobj;
 
76
}
 
77
 
 
78
array(Image.Layer)|mapping draw_button(mapping args, string text)
 
79
{
 
80
  Image.Image  text_img;
 
81
  mapping      icon;
 
82
 
 
83
  Image.Layer background;
 
84
  Image.Layer frame;
 
85
  Image.Layer mask;
 
86
 
 
87
  int left, right, top, middle, bottom; /* offsets */
 
88
  int req_width, noframe;
 
89
 
 
90
  mapping ll = ([]);
 
91
 
 
92
  void set_image( array layers )
 
93
  {
 
94
    foreach( layers||({}), object l )
 
95
    {
 
96
      if(!l->get_misc_value( "name" ) ) // Hm. Probably PSD
 
97
        continue;
 
98
 
 
99
      ll[lower_case(l->get_misc_value( "name" ))] = l;
 
100
      switch( lower_case(l->get_misc_value( "name" )) )
 
101
      {
 
102
       case "background": background = l; break;
 
103
       case "frame":      frame = l;     break;
 
104
       case "mask":       mask = l;     break;
 
105
      }
 
106
    }
 
107
  };
 
108
 
 
109
  if( args->border_image )
 
110
  {
 
111
      array(Image.Layer)|mapping tmp = load_layers(args->border_image);
 
112
    if (mappingp(tmp))
 
113
      if (tmp->error == 401)
 
114
        return tmp;
 
115
      else
 
116
        error("GButton: Failed to load frame image: %O\n",
 
117
              args->border_image);
 
118
    set_image( tmp );
 
119
  }
 
120
 
 
121
 
 
122
  //  otherwise load default images
 
123
  if ( !frame && !background && !mask )
 
124
  {
 
125
    string data = Stdio.read_file("gbutton.xcf");
 
126
    if (!data)
 
127
      error ("Failed to load default frame image "
 
128
             "(roxen-images/gbutton.xcf): " + strerror (errno()));
 
129
    mixed err = catch {
 
130
      set_image(Image.XCF.decode_layers(data));
 
131
    };
 
132
    if( !frame )
 
133
      if (err) {
 
134
        catch (err[0] = "Failed to decode default frame image "
 
135
               "(gbutton.xcf): " + err[0]);
 
136
        throw (err);
 
137
      }
 
138
      else
 
139
        error("Failed to decode default frame image "
 
140
              "(roxen-images/gbutton.xcf).\n");
 
141
  }
 
142
 
 
143
  if( !frame )
 
144
  {
 
145
    noframe = 1;
 
146
    frame = background || mask; // for sizes offsets et.al.
 
147
  }
 
148
  
 
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();
 
153
  if( x0 || y0 )
 
154
    foreach( values( ll ), object l )
 
155
    {
 
156
      int x = l->xoffset();
 
157
      int y = l->yoffset();
 
158
      l->set_offset( x-x0, y-y0 );
 
159
    }
 
160
 
 
161
  if( !mask )
 
162
    mask = frame;
 
163
 
 
164
  array x = ({});
 
165
  array y = ({});
 
166
 
 
167
  foreach( frame->get_misc_value( "image_guides" ), object g )
 
168
    if( g->vertical )
 
169
      x += ({ g->pos - x0 });
 
170
    else
 
171
      y += ({ g->pos - y0 });
 
172
 
 
173
  sort( y );
 
174
  sort( x );
 
175
 
 
176
  if(sizeof( x ) < 2)
 
177
    x = ({ 5, frame->xsize()-5 });
 
178
 
 
179
  if(sizeof( y ) < 2)
 
180
    y = ({ 2, frame->ysize()-2 });
 
181
 
 
182
  left = x[0]; right = x[-1];    top = y[0]; middle = y[1]; bottom = y[-1];
 
183
  right = frame->xsize()-right;
 
184
 
 
185
  //  Text height depends on which guides we should align to
 
186
  int text_height;
 
187
  switch (args->icva) {
 
188
  case "above":
 
189
    text_height = bottom - middle;
 
190
    break;
 
191
  case "below":
 
192
    text_height = middle - top;
 
193
    break;
 
194
  default:
 
195
  case "middle":
 
196
    text_height = bottom - top;
 
197
    break;
 
198
  }
 
199
 
 
200
  //  Get icon
 
201
  if (args->icn)
 
202
      icon = load_icon(args->icn);
 
203
  else if (args->icd)
 
204
      icon = load_icon(args->icd);
 
205
 
 
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;
 
209
 
 
210
  //  Generate text
 
211
  if (sizeof(text))
 
212
  {
 
213
    int os, dir;
 
214
    Image.Font button_font;
 
215
    int th = text_height;
 
216
    do
 
217
    {
 
218
      button_font = resolve_font( args->font+" "+th );
 
219
      text_img = button_font->write(text);
 
220
      os = text_img->ysize();
 
221
      if( !dir )
 
222
        if( os < text_height )
 
223
          dir = 1;
 
224
        else if( os > text_height )
 
225
          dir =-1;
 
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;
 
229
      th += dir;
 
230
    } while( (text_img->ysize() - text_height)
 
231
             && (th>0 && th<text_height*2));
 
232
 
 
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 );
 
236
    else
 
237
    {
 
238
      int o = text_img->ysize() - text_height; 
 
239
      top -= o;
 
240
      middle -= o/2;
 
241
    }
 
242
    if (args->cnd)
 
243
      text_img = text_img->scale((int) round(text_img->xsize() * 0.8),
 
244
                                 text_img->ysize());
 
245
  } else
 
246
    text_height = 0;
 
247
 
 
248
  int t_width = text_img && text_img->xsize();
 
249
 
 
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;
 
257
 
 
258
  int icn_x, icn_y, txt_x, txt_y;
 
259
 
 
260
  //  Are text and icon lined up or on separate lines?
 
261
  switch (args->icva) {
 
262
  case "above":
 
263
  case "below":
 
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) {
 
269
      txt_y = middle;
 
270
      icn_y = top + ((text_height ? middle : bottom) - top - i_height) / 2;
 
271
    } else {
 
272
      txt_y = top;
 
273
      icn_y = middle + (bottom - middle - i_height) / 2;
 
274
    }
 
275
    break;
 
276
 
 
277
  default:
 
278
  case "middle":
 
279
    //  Center icon vertically on same line as text
 
280
    icn_y = icon && (frame->ysize() - icon->img->ysize()) / 2;
 
281
    txt_y = top;
 
282
    
 
283
    switch (args->al)
 
284
    {
 
285
    case "left":
 
286
      //  Allow icon alignment: left, right
 
287
      switch (args->ica)
 
288
      {
 
289
      case "left":
 
290
        icn_x = left;
 
291
        txt_x = icn_x + i_width + i_spc;
 
292
        break;
 
293
      default:
 
294
      case "right":
 
295
        txt_x = left;
 
296
        icn_x = req_width - right - i_width;
 
297
        break;
 
298
      }
 
299
    break;
 
300
 
 
301
    default:
 
302
    case "center":
 
303
    case "middle":
 
304
      //  Allow icon alignment:
 
305
      //  left, center, center-before, center-after, right
 
306
      switch (args->ica)
 
307
      {
 
308
      case "left":
 
309
        icn_x = left;
 
310
        txt_x = (req_width - right - left - i_width - i_spc - t_width) / 2;
 
311
        txt_x += icn_x + i_width + i_spc;
 
312
        break;
 
313
      default:
 
314
      case "center":
 
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;
 
319
        break;
 
320
      case "center_after":
 
321
      case "center-after":
 
322
        txt_x = (req_width - i_width - i_spc - t_width) / 2;
 
323
        icn_x = txt_x + t_width + i_spc;
 
324
        break;
 
325
      case "right":
 
326
        icn_x = req_width - right - i_width;
 
327
        txt_x = left + (icn_x - i_spc - t_width - left) / 2;
 
328
        break;
 
329
      }
 
330
      break;
 
331
      
 
332
    case "right":
 
333
      //  Allow icon alignment: left, right
 
334
      switch (args->ica)
 
335
      {
 
336
      default:
 
337
      case "left":
 
338
        icn_x = left;
 
339
        txt_x = req_width - right - t_width;
 
340
        break;
 
341
      case "right":
 
342
        icn_x = req_width - right - i_width;
 
343
        txt_x = icn_x - i_spc - t_width;
 
344
        break;
 
345
      }
 
346
      break;
 
347
    }
 
348
    break;
 
349
  }
 
350
 
 
351
  if( args->extra_frame_layers )
 
352
  {
 
353
    array l = ({ });
 
354
    foreach( args->extra_frame_layers/",", string q )
 
355
      l += ({ ll[q] });
 
356
    l-=({ 0 });
 
357
    if( sizeof( l ) )
 
358
      frame = Image.lay( l+(noframe?({}):({frame})) );
 
359
  }
 
360
 
 
361
  if( args->extra_mask_layers )
 
362
  {
 
363
    array l = ({ });
 
364
    foreach( args->extra_mask_layers/",", string q )
 
365
      l += ({ ll[q] });
 
366
    l-=({ 0 });
 
367
    if( sizeof( l ) )
 
368
    {
 
369
      if( mask )
 
370
        l = ({ mask })+l;
 
371
      mask = Image.lay( l );
 
372
    }
 
373
  }
 
374
 
 
375
  right = frame->xsize()-right;
 
376
  if (mask != frame)
 
377
  {
 
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;
 
384
    
 
385
    i = i->copy(x0,y0, x1,y1);
 
386
    if( m )
 
387
      m = m->copy(x0,y0, x1,y1);
 
388
    mask->set_image( i, m );
 
389
    mask = stretch_layer( mask, left, right, req_width );
 
390
  }
 
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)),
 
396
  });
 
397
 
 
398
 
 
399
  if( args->extra_background_layers || background)
 
400
  {
 
401
    array l = ({ background });
 
402
    foreach( (args->extra_background_layers||"")/","-({""}), string q )
 
403
      l += ({ ll[q] });
 
404
    l-=({ 0 });
 
405
    foreach( l, object ll )
 
406
    {
 
407
      if( args->dim )
 
408
        ll->set_alpha_value( 0.3 );
 
409
      button_layers += ({ stretch_layer( ll, left, right, req_width ) });
 
410
    }
 
411
  }
 
412
 
 
413
  if( !noframe )
 
414
  {
 
415
    button_layers += ({ frame });
 
416
    frame->set_mode( "value" );
 
417
  }
 
418
 
 
419
  if( args->dim )
 
420
  {
 
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;
 
427
    } else {
 
428
      dim_high = min(bg_value + 64, 255);
 
429
      dim_low = dim_high - 128;
 
430
    }
 
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 })),
 
435
                     frame->alpha());
 
436
  }
 
437
 
 
438
  //  Draw icon.
 
439
  if (icon)
 
440
    button_layers += ({
 
441
      Image.Layer( ([
 
442
        "alpha_value":(args->dim ? 0.3 : 1.0),
 
443
        "image":icon->img,
 
444
        "alpha":icon->alpha,
 
445
        "xoffset":icn_x,
 
446
        "yoffset":icn_y
 
447
      ]) )});
 
448
 
 
449
  //  Draw text
 
450
  if(text_img)
 
451
  {
 
452
    float ta = args->txtalpha?args->txtalpha:1.0;
 
453
    button_layers +=
 
454
      ({
 
455
        Image.Layer(([
 
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)),
 
459
          "xoffset":txt_x,
 
460
          "yoffset":txt_y,
 
461
        ]))
 
462
     });
 
463
  }
 
464
 
 
465
  // 'plain' extra layers are added on top of everything else
 
466
  if( args->extra_layers )
 
467
  {
 
468
    array q = map(args->extra_layers/",",
 
469
                  lambda(string q) { return ll[q]; } )-({0});
 
470
    foreach( q, object ll )
 
471
    {
 
472
      if( args->dim )
 
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() );
 
478
    }
 
479
  }
 
480
 
 
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 )
 
486
  {
 
487
    array l = ({ });
 
488
    foreach( args->extra_left_layers/",", string q )
 
489
      l += ({ ll[q] });
 
490
    l-=({ 0 });
 
491
    l->set_offset( 0, 0 );
 
492
    if( sizeof( l ) )
 
493
    {
 
494
      object q = Image.lay( l );
 
495
      foreach( button_layers, object b )
 
496
      {
 
497
        int x = b->xoffset();
 
498
        int y = b->yoffset();
 
499
        b->set_offset( x+q->xsize(), y );
 
500
      }
 
501
      q->set_offset( 0, button_layers[0]->ysize()-q->ysize() );
 
502
      button_layers += ({ q });
 
503
    }
 
504
  }
 
505
 
 
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 )
 
510
  {
 
511
    array l = ({ });
 
512
    foreach( args->extra_right_layers/",", string q )
 
513
      l += ({ ll[q] });
 
514
    l-=({ 0 });
 
515
    l->set_offset( 0, 0 );
 
516
    if( sizeof( l ) )
 
517
    {
 
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 });
 
523
    }
 
524
  }
 
525
 
 
526
//   if( !equal( args->pagebg, args->bg ) )
 
527
//   {
 
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;
 
534
  else
 
535
    return button_layers;
 
536
//   }
 
537
}
 
538
 
 
539
 
 
540
mixed tab(mapping args)
 
541
{
 
542
    mapping gbutton_args = args;
 
543
        
 
544
 
 
545
    string fimage;
 
546
    if ( !stringp(args->frame_image) ) {
 
547
        fimage = Stdio.read_file("tabframe.xcf");
 
548
        gbutton_args["frame-image"] = fimage;
 
549
    }
 
550
    else {
 
551
        object fimg = _FILEPATH->path_to_object(args->frame_image);
 
552
        fimage = fimg->get_content();
 
553
    }
 
554
    
 
555
 
 
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");
 
563
    } else {
 
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);
 
569
    }
 
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;
 
576
}
 
577
 
 
578
array(string) execute(mapping args)
 
579
{
 
580
    array layers = tab(args);
 
581
    object img = Image.lay( layers );
 
582
    string str = Image.PNG->encode(img->image());
 
583
    return ({ str, "image/gif" });
 
584
}
 
585
 
 
586
string get_identifier() { return "buttons"; }
 
587
 
 
588
#if 0
 
589
void main(int argc, array argv)
 
590
{
 
591
 
 
592
    object img = Image.lay( layers );
 
593
    Stdio.write_file("test.jpg", Image.GIF->encode(img->image()));
 
594
}
 
595
#endif