]> git.decadent.org.uk Git - ion3.git/blobdiff - de/draw.c
Imported Upstream version 20090110
[ion3.git] / de / draw.c
index aae2dae629d30bb0109aaf67fead4c58b5dc7f64..bcacfece99a074033792576233ade5cbd5dac143 100644 (file)
--- a/de/draw.c
+++ b/de/draw.c
@@ -1,12 +1,9 @@
 /*
  * ion/de/draw.c
  *
- * Copyright (c) Tuomo Valkonen 1999-2006
+ * Copyright (c) Tuomo Valkonen 1999-2009
  *
- * Ion is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
+ * See the included file LICENSE for details.
  */
 
 #include <string.h>
@@ -15,6 +12,7 @@
 #include <ioncore/global.h>
 #include <ioncore/common.h>
 #include <ioncore/gr.h>
+#include <ioncore/gr-util.h>
 #include "brush.h"
 #include "font.h"
 #include "private.h"
 
 
 static DEColourGroup *destyle_get_colour_group2(DEStyle *style,
-                                                const char *attr_p1,
-                                                const char *attr_p2)
+                                                const GrStyleSpec *a1,
+                                                const GrStyleSpec *a2)
 {
     int i, score, maxscore=0;
     DEColourGroup *maxg=&(style->cgrp);
     
     while(style!=NULL){
         for(i=0; i<style->n_extra_cgrps; i++){
-            score=gr_stylespec_score2(style->extra_cgrps[i].spec,
-                                      attr_p1, attr_p2);
+            score=gr_stylespec_score2(&style->extra_cgrps[i].spec, a1, a2);
+            
             if(score>maxscore){
                 maxg=&(style->extra_cgrps[i]);
                 maxscore=score;
@@ -49,19 +47,25 @@ static DEColourGroup *destyle_get_colour_group2(DEStyle *style,
 
 
 DEColourGroup *debrush_get_colour_group2(DEBrush *brush, 
-                                         const char *attr_p1,
-                                         const char *attr_p2)
+                                         const GrStyleSpec *a1,
+                                         const GrStyleSpec *a2)
 {
-    return destyle_get_colour_group2(brush->d, attr_p1, attr_p2);
+    return destyle_get_colour_group2(brush->d, a1, a2);
 }
 
 
-DEColourGroup *debrush_get_colour_group(DEBrush *brush, const char *attr)
+DEColourGroup *debrush_get_colour_group(DEBrush *brush, const GrStyleSpec *attr)
 {
     return destyle_get_colour_group2(brush->d, attr, NULL);
 }
 
 
+DEColourGroup *debrush_get_current_colour_group(DEBrush *brush)
+{
+    return debrush_get_colour_group(brush, debrush_get_current_attr(brush));
+}
+
+
 /*}}}*/
 
 
@@ -106,8 +110,8 @@ static void do_draw_border(Window win, GC gc, int x, int y, int w, int h,
     b=0;
     
     for(i=0; i<br; i++){
-        points[0].x=x+w-i;        points[0].y=y+b;
-        points[1].x=x+w-i;        points[1].y=y+h-i;
+        points[0].x=x+w-i;      points[0].y=y+b;
+        points[1].x=x+w-i;      points[1].y=y+h-i;
         points[2].x=x+a;        points[2].y=y+h-i;
     
         if(a<tl)
@@ -132,63 +136,29 @@ static void draw_border(Window win, GC gc, WRectangle *geom,
 }
 
 
-void debrush_do_draw_border(DEBrush *brush, WRectangle geom, 
-                            DEColourGroup *cg)
-{
-    DEBorder *bd=&(brush->d->border);
-    GC gc=brush->d->normal_gc;
-    Window win=brush->win;
-    
-    switch(bd->style){
-    case DEBORDER_RIDGE:
-        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
-    case DEBORDER_INLAID:
-        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
-        draw_border(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl);
-        break;
-    case DEBORDER_GROOVE:
-        draw_border(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl);
-        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
-        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
-        break;
-    case DEBORDER_ELEVATED:
-    default:
-        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
-        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
-        break;
-    }
-}
-
-
-void debrush_draw_border(DEBrush *brush, 
-                         const WRectangle *geom,
-                         const char *attrib)
-{
-    DEColourGroup *cg=debrush_get_colour_group(brush, attrib);
-    if(cg!=NULL)
-        debrush_do_draw_border(brush, *geom, cg);
-}
-
-
 static void draw_borderline(Window win, GC gc, WRectangle *geom,
                             uint tl, uint br, DEColour tlc, DEColour brc, 
                             GrBorderLine line)
 {
-    if(line==GR_BORDERLINE_LEFT && geom->h>0){
+    if(line==GR_BORDERLINE_LEFT && geom->h>0 && tl>0){
         XSetForeground(ioncore_g.dpy, gc, tlc);
-        XDrawRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y, tl, geom->h);
+        XSetBackground(ioncore_g.dpy, gc, tlc);
+        XFillRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y, tl, geom->h);
         geom->x+=tl;
-    }else if(line==GR_BORDERLINE_TOP && geom->w>0){
+    }else if(line==GR_BORDERLINE_TOP && geom->w>0 && tl>0){
         XSetForeground(ioncore_g.dpy, gc, tlc);
-        XDrawRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y, geom->w, tl);
+        XSetBackground(ioncore_g.dpy, gc, tlc);
+        XFillRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y, geom->w, tl);
         geom->y+=tl;
-    }else if(line==GR_BORDERLINE_RIGHT && geom->h>0){
+    }else if(line==GR_BORDERLINE_RIGHT && geom->h>0 && br>0){
         XSetForeground(ioncore_g.dpy, gc, brc);
-        XDrawRectangle(ioncore_g.dpy, win, gc, geom->x+geom->w-1-br, geom->y, br, geom->h);
+        XSetBackground(ioncore_g.dpy, gc, brc);
+        XFillRectangle(ioncore_g.dpy, win, gc, geom->x+geom->w-br, geom->y, br, geom->h);
         geom->w-=br;
-    }else if(line==GR_BORDERLINE_BOTTOM && geom->w>0){
+    }else if(line==GR_BORDERLINE_BOTTOM && geom->w>0 && br>0){
         XSetForeground(ioncore_g.dpy, gc, brc);
-        XDrawRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y+geom->h-1-br, geom->w, br);
+        XSetBackground(ioncore_g.dpy, gc, brc);
+        XFillRectangle(ioncore_g.dpy, win, gc, geom->x, geom->y+geom->h-br, geom->w, br);
         geom->h-=br;
     }
 }
@@ -222,15 +192,88 @@ void debrush_do_draw_borderline(DEBrush *brush, WRectangle geom,
 }
 
 
+void debrush_do_draw_padline(DEBrush *brush, WRectangle geom,
+                             DEColourGroup *cg, GrBorderLine line)
+{
+    DEBorder *bd=&(brush->d->border);
+    GC gc=brush->d->normal_gc;
+    Window win=brush->win;
+    
+    draw_borderline(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad, line);
+}
+
+
 void debrush_draw_borderline(DEBrush *brush, const WRectangle *geom,
-                             const char *attrib, GrBorderLine line)
+                             GrBorderLine line)
 {
-    DEColourGroup *cg=debrush_get_colour_group(brush, attrib);
+    DEColourGroup *cg=debrush_get_current_colour_group(brush);
     if(cg!=NULL)
         debrush_do_draw_borderline(brush, *geom, cg, line);
 }
 
 
+static void debrush_do_do_draw_border(DEBrush *brush, WRectangle geom, 
+                                      DEColourGroup *cg)
+{
+    DEBorder *bd=&(brush->d->border);
+    GC gc=brush->d->normal_gc;
+    Window win=brush->win;
+    
+    switch(bd->style){
+    case DEBORDER_RIDGE:
+        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
+    case DEBORDER_INLAID:
+        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
+        draw_border(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl);
+        break;
+    case DEBORDER_GROOVE:
+        draw_border(win, gc, &geom, bd->sh, bd->hl, cg->sh, cg->hl);
+        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
+        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
+        break;
+    case DEBORDER_ELEVATED:
+    default:
+        draw_border(win, gc, &geom, bd->hl, bd->sh, cg->hl, cg->sh);
+        draw_border(win, gc, &geom, bd->pad, bd->pad, cg->pad, cg->pad);
+        break;
+    }
+}
+
+
+void debrush_do_draw_border(DEBrush *brush, WRectangle geom, 
+                            DEColourGroup *cg)
+{
+    DEBorder *bd=&(brush->d->border);
+
+    switch(bd->sides){
+    case DEBORDER_ALL:
+        debrush_do_do_draw_border(brush, geom, cg);
+        break;
+    case DEBORDER_TB:
+        debrush_do_draw_padline(brush, geom, cg, GR_BORDERLINE_LEFT);
+        debrush_do_draw_padline(brush, geom, cg, GR_BORDERLINE_RIGHT);
+        debrush_do_draw_borderline(brush, geom, cg, GR_BORDERLINE_TOP);
+        debrush_do_draw_borderline(brush, geom, cg, GR_BORDERLINE_BOTTOM);
+        break;
+    case DEBORDER_LR:
+        debrush_do_draw_padline(brush, geom, cg, GR_BORDERLINE_TOP);
+        debrush_do_draw_padline(brush, geom, cg, GR_BORDERLINE_BOTTOM);
+        debrush_do_draw_borderline(brush, geom, cg, GR_BORDERLINE_LEFT);
+        debrush_do_draw_borderline(brush, geom, cg, GR_BORDERLINE_RIGHT);
+        break;
+    }
+}
+
+    
+void debrush_draw_border(DEBrush *brush, 
+                         const WRectangle *geom)
+{
+    DEColourGroup *cg=debrush_get_current_colour_group(brush);
+    if(cg!=NULL)
+        debrush_do_draw_border(brush, *geom, cg);
+}
+
+
 /*}}}*/
 
 
@@ -251,11 +294,43 @@ static void copy_masked(DEBrush *brush, Drawable src, Drawable dst,
 }
 
 
+
+#define ISSET(S, A) ((S)!=NULL && gr_stylespec_isset(S, A))
+
+
+GR_DEFATTR(dragged);
+GR_DEFATTR(tagged);
+GR_DEFATTR(submenu);
+GR_DEFATTR(numbered);
+GR_DEFATTR(tabnumber);
+
+
+static void ensure_attrs()
+{
+    GR_ALLOCATTR_BEGIN;
+    GR_ALLOCATTR(dragged);
+    GR_ALLOCATTR(tagged);
+    GR_ALLOCATTR(submenu);
+    GR_ALLOCATTR(numbered);
+    GR_ALLOCATTR(tabnumber);
+    GR_ALLOCATTR_END;
+}
+
+
+static int get_ty(const WRectangle *g, const GrBorderWidths *bdw, 
+                  const GrFontExtents *fnte)
+{
+    return (g->y+bdw->top+fnte->baseline
+            +(g->h-bdw->top-bdw->bottom-fnte->max_height)/2);
+}
+
+
 void debrush_tab_extras(DEBrush *brush, const WRectangle *g, 
-                        DEColourGroup *cg, GrBorderWidths *bdw,
-                        GrFontExtents *fnte,
-                        const char *a1, const char *a2,
-                        bool pre)
+                        DEColourGroup *cg, const GrBorderWidths *bdw,
+                        const GrFontExtents *fnte,
+                        const GrStyleSpec *a1, 
+                        const GrStyleSpec *a2,
+                        bool pre, int index)
 {
     DEStyle *d=brush->d;
     GC tmp;
@@ -263,20 +338,56 @@ void debrush_tab_extras(DEBrush *brush, const WRectangle *g,
      * with shared GC:s.
      */
     static bool swapped=FALSE;
+
+    ensure_attrs();
     
     if(pre){
-        if(!MATCHES2("*-*-*-dragged", a1, a2))
-            return;
-        
-        tmp=d->normal_gc;
-        d->normal_gc=d->stipple_gc;
-        d->stipple_gc=tmp;
-        swapped=TRUE;
-        XClearArea(ioncore_g.dpy, brush->win, g->x, g->y, g->w, g->h, False);
+        if(ISSET(a2, GR_ATTR(dragged)) || ISSET(a1, GR_ATTR(dragged))){
+            tmp=d->normal_gc;
+            d->normal_gc=d->stipple_gc;
+            d->stipple_gc=tmp;
+            swapped=TRUE;
+            XClearArea(ioncore_g.dpy, brush->win, g->x, g->y, g->w, g->h, False);
+        }
         return;
     }
     
-    if(MATCHES2("*-*-tagged", a1, a2)){
+    
+    if((ISSET(a1, GR_ATTR(numbered)) || ISSET(a2, GR_ATTR(numbered))) 
+       && index>=0){
+        
+        DEColourGroup *cg;
+        GrStyleSpec tmp;
+        
+        gr_stylespec_init(&tmp);
+        gr_stylespec_append(&tmp, a2);
+        gr_stylespec_set(&tmp, GR_ATTR(tabnumber));
+        
+        cg=debrush_get_colour_group2(brush, a1, &tmp);
+        
+        gr_stylespec_unalloc(&tmp);
+
+        if(cg!=NULL){
+            char *s=NULL;
+            
+            libtu_asprintf(&s, "[%d]", index+1);
+            
+            if(s!=NULL){
+                int l=strlen(s);
+                uint w=debrush_get_text_width(brush, s, l);
+                if(w < g->w-bdw->right-bdw->left){
+                    int ty=get_ty(g, bdw, fnte);
+                    int tx=(d->textalign==DEALIGN_RIGHT
+                            ? g->x+bdw->left
+                            : g->x+g->w-bdw->right-w);
+                    debrush_do_draw_string(brush, tx, ty, s, l, TRUE, cg);
+                }
+                free(s);
+            }
+        }
+    }
+    
+    if(ISSET(a2, GR_ATTR(tagged)) || ISSET(a1, GR_ATTR(tagged))){
         XSetForeground(ioncore_g.dpy, d->copy_gc, cg->fg);
             
         copy_masked(brush, d->tag_pixmap, brush->win, 0, 0,
@@ -284,7 +395,7 @@ void debrush_tab_extras(DEBrush *brush, const WRectangle *g,
                     g->x+g->w-bdw->right-d->tag_pixmap_w, 
                     g->y+bdw->top);
     }
-
+    
     if(swapped){
         tmp=d->normal_gc;
         d->normal_gc=d->stipple_gc;
@@ -298,26 +409,29 @@ void debrush_tab_extras(DEBrush *brush, const WRectangle *g,
 }
 
 
-void debrush_menuentry_extras(DEBrush *brush, const WRectangle *g, 
-                              DEColourGroup *cg, GrBorderWidths *bdw,
-                              GrFontExtents *fnte,
-                              const char *a1, const char *a2, 
-                              bool pre)
+void debrush_menuentry_extras(DEBrush *brush, 
+                              const WRectangle *g, 
+                              DEColourGroup *cg, 
+                              const GrBorderWidths *bdw,
+                              const GrFontExtents *fnte,
+                              const GrStyleSpec *a1, 
+                              const GrStyleSpec *a2, 
+                              bool pre, int index)
 {
     int tx, ty;
 
     if(pre)
         return;
     
-    if(!MATCHES2("*-*-submenu", a1, a2))
-        return;
-        
-    ty=(g->y+bdw->top+fnte->baseline
-        +(g->h-bdw->top-bdw->bottom-fnte->max_height)/2);
-    tx=g->x+g->w-bdw->right;
+    ensure_attrs();
+    
+    if(ISSET(a2, GR_ATTR(submenu)) || ISSET(a1, GR_ATTR(submenu))){
+        ty=get_ty(g, bdw, fnte);
+        tx=g->x+g->w-bdw->right;
 
-    debrush_do_draw_string(brush, tx, ty, DE_SUB_IND, DE_SUB_IND_LEN, 
-                           FALSE, cg);
+        debrush_do_draw_string(brush, tx, ty, DE_SUB_IND, DE_SUB_IND_LEN, 
+                               FALSE, cg);
+    }
 }
 
 
@@ -336,10 +450,14 @@ void debrush_do_draw_box(DEBrush *brush, const WRectangle *geom,
 }
 
 
-static void debrush_do_draw_textbox(DEBrush *brush, const WRectangle *geom, 
-                                    const char *text, DEColourGroup *cg, 
+static void debrush_do_draw_textbox(DEBrush *brush, 
+                                    const WRectangle *geom, 
+                                    const char *text, 
+                                    DEColourGroup *cg, 
                                     bool needfill,
-                                    const char *a1, const char *a2)
+                                    const GrStyleSpec *a1, 
+                                    const GrStyleSpec *a2,
+                                    int index)
 {
     uint len;
     GrBorderWidths bdw;
@@ -350,7 +468,7 @@ static void debrush_do_draw_textbox(DEBrush *brush, const WRectangle *geom,
     grbrush_get_font_extents(&(brush->grbrush), &fnte);
     
     if(brush->extras_fn!=NULL)
-        brush->extras_fn(brush, geom, cg, &bdw, &fnte, a1, a2, TRUE);
+        brush->extras_fn(brush, geom, cg, &bdw, &fnte, a1, a2, TRUE, index);
     
     debrush_do_draw_box(brush, geom, cg, needfill);
     
@@ -374,49 +492,55 @@ static void debrush_do_draw_textbox(DEBrush *brush, const WRectangle *geom,
             tx=geom->x+bdw.left;
         }
         
-        ty=(geom->y+bdw.top+fnte.baseline
-            +(geom->h-bdw.top-bdw.bottom-fnte.max_height)/2);
+        ty=get_ty(geom, &bdw, &fnte);
         
         debrush_do_draw_string(brush, tx, ty, text, len, FALSE, cg);
     }while(0);
     
     if(brush->extras_fn!=NULL)
-        brush->extras_fn(brush, geom, cg, &bdw, &fnte, a1, a2, FALSE);
+        brush->extras_fn(brush, geom, cg, &bdw, &fnte, a1, a2, FALSE, index);
 }
 
 
 void debrush_draw_textbox(DEBrush *brush, const WRectangle *geom, 
-                          const char *text, const char *attr, 
-                          bool needfill)
+                          const char *text, bool needfill)
 {
+    GrStyleSpec *attr=debrush_get_current_attr(brush);
     DEColourGroup *cg=debrush_get_colour_group(brush, attr);
+    
     if(cg!=NULL){
         debrush_do_draw_textbox(brush, geom, text, cg, needfill, 
-                                attr, NULL);
+                                attr, NULL, -1);
     }
 }
 
 
 void debrush_draw_textboxes(DEBrush *brush, const WRectangle *geom,
                             int n, const GrTextElem *elem, 
-                            bool needfill, const char *common_attrib)
+                            bool needfill)
 {
+    GrStyleSpec *common_attrib;
     WRectangle g=*geom;
     DEColourGroup *cg;
     GrBorderWidths bdw;
     int i;
     
+    common_attrib=debrush_get_current_attr(brush);
+    
     grbrush_get_border_widths(&(brush->grbrush), &bdw);
     
-    for(i=0; i<n; i++){
+    for(i=0; ; i++){
         g.w=bdw.left+elem[i].iw+bdw.right;
-        cg=debrush_get_colour_group2(brush, common_attrib, elem[i].attr);
+        cg=debrush_get_colour_group2(brush, common_attrib, &elem[i].attr);
         
         if(cg!=NULL){
             debrush_do_draw_textbox(brush, &g, elem[i].text, cg, needfill,
-                                    common_attrib, elem[i].attr);
+                                    common_attrib, &elem[i].attr, i);
         }
         
+        if(i==n-1)
+            break;
+        
         g.x+=g.w;
         if(bdw.spacing>0 && needfill){
             XClearArea(ioncore_g.dpy, brush->win, g.x, g.y,
@@ -490,9 +614,9 @@ void debrush_enable_transparency(DEBrush *brush, GrTransparency mode)
 }
 
 
-void debrush_fill_area(DEBrush *brush, const WRectangle *geom, const char *attr)
+void debrush_fill_area(DEBrush *brush, const WRectangle *geom)
 {
-    DEColourGroup *cg=debrush_get_colour_group(brush, attr);
+    DEColourGroup *cg=debrush_get_current_colour_group(brush);
     GC gc=brush->d->normal_gc;
 
     if(cg==NULL)
@@ -555,9 +679,13 @@ static void debrush_clear_clipping_rectangle(DEBrush *brush)
 
 void debrush_begin(DEBrush *brush, const WRectangle *geom, int flags)
 {
+    
     if(flags&GRBRUSH_AMEND)
         flags|=GRBRUSH_NO_CLEAR_OK;
     
+    if(!(flags&GRBRUSH_KEEP_ATTR))
+        debrush_init_attr(brush, NULL);
+    
     if(!(flags&GRBRUSH_NO_CLEAR_OK))
         debrush_clear_area(brush, geom);