[GRASS-SVN] r69037 - grass/branches/releasebranch_7_2/display/d.legend

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Jul 27 11:05:07 PDT 2016


Author: annakrat
Date: 2016-07-27 11:05:07 -0700 (Wed, 27 Jul 2016)
New Revision: 69037

Added:
   grass/branches/releasebranch_7_2/display/d.legend/d_legend_custom_labels_and_background.png
   grass/branches/releasebranch_7_2/display/d.legend/d_legend_logarithmic.png
   grass/branches/releasebranch_7_2/display/d.legend/draw.c
Modified:
   grass/branches/releasebranch_7_2/display/d.legend/d.legend.html
   grass/branches/releasebranch_7_2/display/d.legend/get_stats.c
   grass/branches/releasebranch_7_2/display/d.legend/histogram.c
   grass/branches/releasebranch_7_2/display/d.legend/local_proto.h
   grass/branches/releasebranch_7_2/display/d.legend/main.c
Log:
d.legend: backport recent GSoC improvements, author Adam Laza

Modified: grass/branches/releasebranch_7_2/display/d.legend/d.legend.html
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/d.legend.html	2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/d.legend.html	2016-07-27 18:05:07 UTC (rev 69037)
@@ -63,7 +63,9 @@
 <p>
 The text produced from floating-point raster maps will automatically create
 output with a meaningful number of significant digits. For very small values,
-numbers will be expressed in scientific notation, e.g. "1.7e-9".
+numbers will be expressed in scientific notation, e.g. "1.7e-9". Option
+<b>digits</b> can be used to determine how many digits after decimal point
+will be displayed.
 <p>
 When the <b>-d</b> flag is used to display a histogram distribution along
 side the smoothed gradient legend, note that the statistics are calculated
@@ -73,7 +75,25 @@
 <p>
 If the raster map's <i>units</i> metadata has been set with the
 <em>r.support</em> module then it will be displayed along side the legend.
-
+<p>
+The option <b>title</b> will display the custom title at the top of the legend. 
+In case of vertical legend the title is aligned to the left edge of legend, in case
+of horizontal legend the title is aligned to the center. <b>title_fontsize</b> can
+be used to set the size of legend title. By default the legend title font size is
+the same as labels font size. 
+<p>
+There are different options to customize displayed labels. The <b>labelnum</b> set
+the number of labels which are displayed in regular intervals. The <b>label_values</b>
+will specify the values where the labels will be displayed. The <b>label_step</b> will
+display labels at values which are divisible by this value.
+<p>
+The flag <b>-t</b> will show ticks at labels.
+<p>
+The flag <b>-b</b> will show the background. Options <b>bgcolor</b> and <b>border_color</b> can be
+used to choose the color of border and background fill.
+<p>
+The flag <b>-l</b> will switch to logarithmic scale. In case this flag is used,
+the provided step in <b>label_step</b> is interpreted in the logarithmic space.
 <h2>EXAMPLE</h2>
 
 Displaying the legend along with a histogram (North Carolina Sample dataset):
@@ -88,7 +108,33 @@
 <img src="d_legend.png" alt="Elevation map with legend" border=1>
 </center>
 
+Displaying the legend with custom labels and background:
 
+<div class="code"><pre>
+g.region raster=elevation -p
+d.rast elevation
+d.legend raster=elevation -t label_step=20 label_values=108 title=Legend -b bgcolor=255:255:204 border_color=gray
+</pre></div>
+
+<center>
+<img src="d_legend_custom_labels_and_background.png" alt="Elevation map with custom legend" border=1>
+</center>
+
+Displaying the legend with logarithmic scale:
+
+<div class="code"><pre>
+g.region raster=elevation -p
+r.watershed -a elevation=elevation threshold=1000 accumulation=flowacc
+d.rast flowacc
+d.legend raster=flowacc -t -l label_step=1
+</pre></div>
+
+<center>
+<img src="d_legend_logarithmic.png" alt="Flow accumulation map with logarithmic legend" border=1>
+</center>
+
+
+
 <h2>SEE ALSO</h2>
 
 <em>

Copied: grass/branches/releasebranch_7_2/display/d.legend/d_legend_custom_labels_and_background.png (from rev 68759, grass/trunk/display/d.legend/d_legend_custom_labels_and_background.png)
===================================================================
(Binary files differ)

Copied: grass/branches/releasebranch_7_2/display/d.legend/d_legend_logarithmic.png (from rev 68759, grass/trunk/display/d.legend/d_legend_logarithmic.png)
===================================================================
(Binary files differ)

Copied: grass/branches/releasebranch_7_2/display/d.legend/draw.c (from rev 68699, grass/trunk/display/d.legend/draw.c)
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/draw.c	                        (rev 0)
+++ grass/branches/releasebranch_7_2/display/d.legend/draw.c	2016-07-27 18:05:07 UTC (rev 69037)
@@ -0,0 +1,1364 @@
+/* draw.c:
+ *    Compute position of legend, title, labels and ticks
+ *    Extracted from original d.legend/main.c for background purpose
+ *    Moving to seperate file: Adam Laza, GSoC 2016
+ *
+ *    Copyright (C) 2014 by Hamish Bowman, and the GRASS Development Team*
+ *    This program is free software under the GPL (>=v2)
+ *    Read the COPYING file that comes with GRASS for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <grass/gis.h>
+#include <grass/raster.h>
+#include <grass/raster3d.h>
+#include <grass/display.h>
+#include <grass/glocale.h>
+#include "local_proto.h"
+
+void draw(const char *map_name, int maptype, int color, int thin, int lines,
+          int steps, int fp, int label_indent, int hide_catnum,
+          int hide_catstr, int show_ticks, int hide_nodata, int do_smooth,
+          struct Categories cats, struct Colors colors, double X0, double X1,
+          double Y0, double Y1, int flip, int UserRange, double UserRangeMin,
+          double UserRangeMax, double *catlist, int catlistCount,
+          int use_catlist, int ticksCount, double fontsize,
+          double tit_fontsize, const char *title, double *tick_values,
+          double t_step, int colorb, int colorbg, struct Option *opt_use,
+          struct Option *opt_at, struct Option *opt_fontsize,
+          struct Option *opt_tstep, struct Option *opt_range, struct Flag *histo,
+          struct Flag *hidestr, int log_sc, int draw, int digits, char *units)
+{
+    char buff[512];
+    int black, white;
+    int cats_num;
+    int cur_dot_row;
+    int do_cats;
+    int dots_per_line;
+    int i, j, k;
+    double t, b, l, r;
+    char *cstr;
+    double x_box[5], y_box[5];
+    struct Range range;
+    struct FPRange fprange, render_range;
+    CELL min_ind, max_ind;
+    DCELL dmin, dmax, val;
+    CELL min_colr, max_colr;
+    DCELL min_dcolr, max_dcolr;
+    int x0, x1, y0, y1, xyTemp;
+    int SigDigits;
+    unsigned int MaxLabelLen;
+    char DispFormat[5];         /*  %.Xf\0  */
+    double maxCat;
+    int horiz;
+    char *units_bottom;
+    double t_start;
+    double max_hist;
+    double txsiz, titsiz;
+    int tcell;
+    float ScaleFactor = 1.0;
+    double x_tit, y_tit, x1_tit;
+    double x0bg, y0bg, x1bg, y1bg;
+    double wleg, lleg;
+    int true_l, true_r;
+    int dx, dy;
+    double coef;
+    double ppl;
+    double bb,bt,bl,br;
+    char MaxLabel[512];
+    double num;
+    int MaxLabelW, LabelW;
+
+
+    if (draw) {
+        /* init colors */
+        black = D_translate_color(DEFAULT_FG_COLOR);
+        white = D_translate_color(DEFAULT_BG_COLOR);
+    }
+
+    /* Figure out where to put text */
+    D_setup_unity(0);
+    D_get_src(&t, &b, &l, &r);
+
+    x0 = l + (int)((r - l) * X0 / 100.);
+    x1 = l + (int)((r - l) * X1 / 100.);
+    y0 = t + (int)((b - t) * (100. - Y0) / 100.);       /* make lower left the origin */
+    y1 = t + (int)((b - t) * (100. - Y1) / 100.);
+
+    if (y0 > y1) {              /* allow for variety in order of corner */
+        flip = !flip;           /*   selection without broken output    */
+        xyTemp = y0;
+        y0 = y1;
+        y1 = xyTemp;
+    }
+    if (x0 > x1) {
+        xyTemp = x0;
+        x0 = x1;
+        x1 = xyTemp;
+    }
+
+    if (x0 == x1)
+        x1++;                   /* avoid 0 width boxes */
+    if (y0 == y1)
+        y1++;
+
+    if (draw) {
+        if ((x0 < l) || (x1 > r) || (y0 < t) || (y1 > b))       /* for mouse or at= 0- or 100+; needs to be after order check */
+            G_warning(_("Legend box lies outside of frame. Text may not display properly."));
+    }
+
+    horiz = (x1 - x0 > y1 - y0);
+    if (horiz && draw)
+        G_message(_("Drawing horizontal legend as box width exceeds height"));
+
+    if (!fp && horiz)           /* better than nothing */
+        do_smooth = TRUE;
+
+    MaxLabelLen = 0;            /* init variable */
+    MaxLabelW = 0;
+
+    /* How many categories to show */
+    /* not fp */
+    if (!fp) {
+        if (Rast_read_range(map_name, "", &range) == -1)
+            G_fatal_error(_("Range information for <%s> not available (run r.support)"),
+                          map_name);
+
+        Rast_get_range_min_max(&range, &min_ind, &max_ind);
+        if (Rast_is_c_null_value(&min_ind))
+            G_fatal_error(_("Input map contains no data"));
+
+        Rast_get_c_color_range(&min_colr, &max_colr, &colors);
+
+        if (UserRange) {
+            if (min_ind < UserRangeMin)
+                min_ind = (int)ceil(UserRangeMin);
+            if (max_ind > UserRangeMax)
+                max_ind = (int)floor(UserRangeMax);
+            if (min_ind > UserRangeMin) {
+                min_ind =
+                    UserRangeMin <
+                    min_colr ? min_colr : (int)ceil(UserRangeMin);
+                if (draw)
+                    G_warning(_("Requested range exceeds lower limit of actual data"));
+            }
+            if (max_ind < UserRangeMax) {
+                max_ind =
+                    UserRangeMax >
+                    max_colr ? max_colr : (int)floor(UserRangeMax);
+                if (draw)
+                    G_warning(_("Requested range exceeds upper limit of actual data"));
+            }
+        }
+
+        /*  cats_num is total number of categories in raster                  */
+        /*  do_cats is  total number of categories to be displayed            */
+        /*  k is number of cats to be displayed after skipping unlabeled cats */
+        /*  lines is number of text lines/legend window                       */
+
+        cats_num = max_ind - min_ind + 1;
+
+        if (lines == 0)
+            lines = cats_num;
+
+        do_cats = cats_num > lines ? lines : cats_num;
+
+        if (do_cats == cats_num)
+            lines = (int)ceil((1.0 * lines) / thin);
+
+        if (!use_catlist) {
+            catlist = (double *)G_calloc(lines + 1, sizeof(double));
+            catlistCount = lines;
+        }
+        /* see how many boxes there REALLY will be */
+        maxCat = 0.0;
+        for (i = min_ind, j = 1, k = 0; j <= do_cats && i <= max_ind;
+             j++, i += thin) {
+            if (!flip)
+                cstr = Rast_get_c_cat(&i, &cats);
+            else {
+                CELL cat = max_ind - (i - min_ind);
+
+                cstr = Rast_get_c_cat(&cat, &cats);
+            }
+
+            if (!use_catlist)
+                catlist[j - 1] = (double)i;
+
+            if (!cstr[0]) {     /* no cat label found, skip str output */
+                if (hide_nodata)
+                    continue;
+            }
+            else {              /* ie has a label */
+                if (!hide_catstr && (MaxLabelLen < strlen(cstr))) {
+                    MaxLabelLen = strlen(cstr);
+                    sprintf(MaxLabel, "%s", cstr);
+            }
+            }
+
+            if (!hide_catnum)
+                if (i > maxCat)
+                    maxCat = (double)i;
+            k++;                /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
+        }
+        lines = k;
+
+        /* figure out how long the category + label will be */
+        if (use_catlist) {
+            MaxLabelLen = 0;
+            maxCat = 0;         /* reset */
+            for (i = 0, k = 0; i < catlistCount; i++) {
+                if ((catlist[i] < min_ind) || (catlist[i] > max_ind)) {
+                    G_fatal_error(_("use=%s out of range [%d,%d] (extend with range= ?)"),
+                                  opt_use->answers[i], min_ind, max_ind);
+                }
+
+                cstr = Rast_get_d_cat(&catlist[i], &cats);
+                if (!cstr[0]) { /* no cat label found, skip str output */
+                    if (hide_nodata)
+                        continue;
+                }
+                else {          /* ie has a label */
+                    if (!hide_catstr && (MaxLabelLen < strlen(cstr)))
+                        MaxLabelLen = strlen(cstr);
+                }
+                if (!hide_catnum)
+                    if (catlist[i] > maxCat)
+                        maxCat = catlist[i];
+                k++;
+            }
+            if (0 == k)         /* nothing to draw */
+                lines = 0;
+        }
+
+        /* following covers both the above if(do_cats == cats_num) and k++ loop */
+        if (lines < 1) {
+            lines = 1;          /* ward off the dpl floating point exception */
+            G_fatal_error(_("Nothing to draw! (no categories with labels? out of range?)"));
+        }
+
+        /* Figure number of lines, number of pixles per line and text size */
+        dots_per_line = ((y1 - y0) / lines);
+
+        /* switch to a smooth legend for CELL maps with too many cats */
+        /*  an alternate solution is to set   dots_per_line=1         */
+        if ((dots_per_line == 0) && (do_smooth == FALSE)) {
+            if (!use_catlist) {
+                if (draw)
+                    G_message(_("Forcing a smooth legend: too many categories for current window height"));
+                do_smooth = TRUE;
+            }
+        }
+
+        /* center really tiny legends */
+        if (opt_at->answer == NULL) {   /* if defualt scaling */
+            if (!do_smooth && (dots_per_line < 4))      /* if so small that there's no box */
+                if ((b - (dots_per_line * lines)) / (b * 1.0) > 0.15)   /* if there's more than a 15% blank at the bottom */
+                    y0 = ((b - t) - (dots_per_line * lines)) / 2;
+        }
+
+        /* D_text_size(dots_per_line*4/5., dots_per_line*4/5.);    redundant */
+        /* if(Rast_is_c_null_value(&min_ind) && Rast_is_c_null_value(&max_ind))
+           {
+           min_ind = 1;
+           max_ind = 0;
+           } */
+
+        if (horiz)
+            sprintf(DispFormat, "%%d");
+        else {
+            if (maxCat > 0.0)
+                sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
+            else
+                sprintf(DispFormat, "%%2d");
+        }
+    }                           /* end of if(!fp) */
+
+    else {                      /* is fp */
+        if (maptype == MAP_TYPE_RASTER2D) {
+            if (Rast_read_fp_range(map_name, "", &fprange) == -1)
+                G_fatal_error(_("Range information for <%s> not available"),
+                              map_name);
+        }
+        else {
+            if (Rast3d_read_range(map_name, "", &fprange) == -1)
+                G_fatal_error(_("Range information for <%s> not available"),
+                              map_name);
+        }
+
+        Rast_get_fp_range_min_max(&fprange, &dmin, &dmax);
+        Rast_get_d_color_range(&min_dcolr, &max_dcolr, &colors);
+
+        if (UserRange) {
+            if (dmin < UserRangeMin)
+                dmin = UserRangeMin;
+            if (dmax > UserRangeMax)
+                dmax = UserRangeMax;
+            if (dmin > UserRangeMin) {
+                dmin = UserRangeMin < min_dcolr ? min_dcolr : UserRangeMin;
+                G_warning(_("Color range exceeds lower limit of actual data"));
+            }
+            if (dmax < UserRangeMax) {
+                dmax = UserRangeMax > max_dcolr ? max_dcolr : UserRangeMax;
+                G_warning(_("Color range exceeds upper limit of actual data"));
+            }
+        }
+
+        /* In case of log. scale raster doesn't contain negative or zero values */
+        if (log_sc)
+            if ((dmin<=0) || (dmax<=0))
+                G_fatal_error(_("Range [%.3f, %.3f] out of the logarithm domain."),
+                              dmin, dmax);
+
+
+        if (use_catlist) {
+            for (i = 0; i < catlistCount; i++) {
+                if ((catlist[i] < dmin) || (catlist[i] > dmax)) {
+                    G_fatal_error(_("use=%s out of range [%.3f, %.3f] (extend with range= ?)"),
+                                  opt_use->answers[i], dmin, dmax);
+                }
+                if (strlen(opt_use->answers[i]) > MaxLabelLen)
+                    MaxLabelLen = strlen(opt_use->answers[i]);
+            }
+        }
+        do_cats = 0;            /* if only to get rid of the compiler warning  */
+        cats_num = 0;           /* if only to get rid of the compiler warning  */
+        /* determine how many significant digits to display based on range */
+        if (digits != -1) /* number of digits given by user */
+            sprintf(DispFormat, "%%.%df", digits);
+        else {/* automatic calculation */
+        if (0 == (dmax - dmin)) /* trap divide by 0 for single value rasters */
+            sprintf(DispFormat, "%%f");
+        else {
+            SigDigits = (int)ceil(log10(fabs(25 / (dmax - dmin))));
+            if (SigDigits < 0)
+                SigDigits = 0;
+            if (SigDigits < 7)
+                sprintf(DispFormat, "%%.%df", SigDigits);
+            else
+                sprintf(DispFormat, "%%.2g");   /* eg 4.2e-9  */
+        }
+        }
+    }                           /* end of is fp */
+
+    if (use_catlist) {
+        cats_num = catlistCount;
+        do_cats = catlistCount;
+        lines = catlistCount;
+        do_smooth = FALSE;
+    }
+
+
+    if (do_smooth) {
+        if (horiz) {
+            if (draw) {
+                lleg = x1 - x0;
+                dx = 0;
+                dy = y1 - y0;
+            }
+            if (fp)
+                flip = !flip;   /* horiz floats look better not flipped by default */
+        }
+        else {
+            if (draw) {
+                lleg = y1 - y0;
+                dy = 0;
+                dx = x1 - x0;
+            }
+        }
+
+        /* Draw colors */
+        /* Draw the legend bar */
+        if (draw) {
+            for (k = 0; k < lleg; k++) {
+                if (log_sc) { /* logarithmic scale */
+                    num = k / lleg;
+                    val = dmin * pow(dmax/dmin, num);
+                    D_d_color(val, &colors);
+                    if (!flip) {
+                        if (horiz)
+                            D_box_abs(x0 + k, y0, x0 + k + 1, y0 + dy);
+                        else
+                            D_box_abs(x0, y0 + k, x0 + dx, y0 + k + 1);
+                        }
+                    else {
+                        if (horiz)
+                            D_box_abs(x1 - k, y0, x1 - k - 1, y0 + dy);
+                        else
+                            D_box_abs(x0, y1 - k, x0 + dx, y1 - k - 1);
+                    }
+
+                } /* linear scale */
+                else{
+                if (!fp) {
+                    if (!flip)
+                        tcell = min_ind + k * (double)(1 + max_ind - min_ind) / lleg;
+                    else
+                        tcell = (max_ind + 1) - k * (double)(1 + max_ind - min_ind) / lleg;
+                    D_color((CELL) tcell, &colors);
+                }
+                else {
+                    if (!flip)
+                            val = dmin + k / lleg * (dmax - dmin);
+                    else
+                            val = dmax - k / lleg * (dmax - dmin);
+                    D_d_color(val, &colors);
+                }
+
+                if (dx < dy)
+                    D_box_abs(x0 + k, y0, x0 + k + (dx ? -dx : 1),
+                              y0 - (dy ? -dy : 1));
+                else
+                    D_box_abs(x0, y0 + k, x0 - (dx ? -dx : 1),
+                              y0 + k + (dy ? -dy : 1));
+            }
+        }
+        }
+
+        /* Format text */
+        if (!fp) {              /* cut down labelnum so they don't repeat */
+            if (do_cats < steps)
+                steps = do_cats;
+        }
+
+        /* Draw text and ticks */
+        if (!horiz)
+            txsiz = (y1 - y0) / 20;
+        else
+            txsiz = (x1 - x0) / 20;
+
+        wleg = x1 - x0;
+        lleg = y1 - y0;
+
+        /* scale text to fit in window if position not manually set */
+        /* usually not needed, except when frame is really narrow   */
+        if (opt_at->answer == NULL) {   /* ie default scaling */
+            ScaleFactor = ((r - x1) / ((MaxLabelLen + 1) * txsiz * 0.81));      /* ?? txsiz*.81=actual text width. */
+            if (ScaleFactor < 1.0) {
+                txsiz = txsiz * ScaleFactor;
+            }
+        }
+
+        if (opt_fontsize->answer != NULL)
+            txsiz = fontsize;
+
+        if (txsiz < 0)
+            txsiz = 0;          /* keep it sane */
+
+        if (tit_fontsize == 0)
+            titsiz = txsiz;
+        else
+            titsiz = tit_fontsize;
+
+        if (draw) {
+            D_text_size(txsiz, txsiz);
+            D_use_color(color);
+        }
+
+        /* Draw labels and ticks */
+        /* LABELNUM OPTION */
+        if (steps >= 2) {
+            for (k = 0; k < steps; k++) {
+                if (!fp) {
+                    if (!flip)
+                        tcell =
+                            min_ind + k * (double)(max_ind -
+                                                   min_ind) / (steps - 1);
+                    else
+                        tcell =
+                            max_ind - k * (double)(max_ind -
+                                                   min_ind) / (steps - 1);
+
+                    if (!cstr[0])       /* no cats found, disable str output */
+                        hide_catstr = 1;
+                    else
+                        hide_catstr = hidestr->answer;
+
+                    buff[0] = 0;        /* blank string */
+
+                    if (!hide_catnum) { /* num */
+                        sprintf(buff, DispFormat, tcell);
+                        if (!hide_catstr)       /* both */
+                            strcat(buff, ")");
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                    }
+                    }
+                    if (!hide_catstr) {  /* str */
+                        sprintf(buff + strlen(buff), " %s", cstr);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                }
+                    }
+                }
+                else {          /* ie FP map */
+                    if (hide_catnum)
+                        buff[0] = 0;    /* no text */
+                    else {
+                        if (log_sc) {
+                            num = log10(dmax) - k * ((log10(dmax) - log10(dmin)) / (steps - 1));
+                            val = pow(10,num);
+                        }
+                        else{
+                        if (!flip)
+                            val = dmin + k * (dmax - dmin) / (steps - 1);
+                        else
+                            val = dmax - k * (dmax - dmin) / (steps - 1);
+                        }
+                        sprintf(buff, DispFormat, val);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                    }
+                }
+                }
+
+                if (draw) {
+                    if (!hide_catnum) {
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff, &bb, &bt, &bl, &br);
+                        if (!horiz) {
+                            if (log_sc) {
+                                coef = (log10(val) - log10(dmin)) / (log10(dmax) - log10(dmin));
+                                if (flip)
+                            D_pos_abs(x1 + label_indent,
+                                              y1 - coef * lleg + (bb - bt) / 2);
+                                else
+                                    D_pos_abs(x1 + label_indent,
+                                              y0 + coef * lleg + (bb - bt) / 2);
+                        }
+                        else {
+                                ppl = (lleg) / (steps * 1.0 - 1);
+                                D_pos_abs(x1 + label_indent,
+                                          y0 + ppl * k + (bb - bt) / 2);
+                            }
+                            if (show_ticks) {
+                                D_use_color(black);
+                                if (log_sc)
+                                    if (flip)
+                                        D_line_abs(x1, y1 - coef * lleg,
+                                                   x1 + 6, y1 - coef * lleg);
+                                    else
+                                        D_line_abs(x1, y0 + coef * lleg,
+                                                   x1 + 6, y0 + coef * lleg);
+                                else
+                                    D_line_abs(x1, y0 + ppl * k,
+                                               x1 + 6, y0 + ppl * k);
+                            }
+                        }
+                        else {
+                            if (log_sc) {
+                                coef = (log10(val) - log10(dmin)) / (log10(dmax) - log10(dmin));
+                                if (flip)
+                                    D_pos_abs(x1 - coef * wleg - ((br - bl) / 2),
+                                      y1 + label_indent + txsiz);
+                                else
+                                    D_pos_abs(x0 + coef * wleg - ((br - bl) / 2),
+                                              y1 + label_indent + txsiz);
+                        }
+                            else {
+                                ppl = (wleg) / (steps * 1.0 - 1);
+                                D_pos_abs(x0 + ppl * k - ((br - bl) / 2),
+                                          y1 + label_indent + txsiz);
+                            }
+                            if (show_ticks) {
+                                D_use_color(black);
+                                if (log_sc)
+                                    if (flip)
+                                        D_line_abs(x1 - coef * wleg, y1,
+                                                   x1 - coef * wleg, y1 + 6);
+                                    else
+                                        D_line_abs(x0 + coef * wleg, y1,
+                                                   x0 + coef * wleg, y1 + 6);
+                                else
+                                    D_line_abs(x0 + ppl * k, y1,
+                                               x0 + ppl * k, y1 + 6);
+                            }
+                        }
+                        if (color)
+                            D_use_color(color);
+                            D_text(buff);
+                    }
+                }
+            }                   /* for */
+        }
+
+        if (!fp) {
+            dmin = min_ind;
+            dmax = max_ind;
+            sprintf(DispFormat, "%s", "%.0f");
+        }
+
+        /* LABEL_VALUE OPTION */
+        if (ticksCount > 0) {
+            for (i = 0; i < ticksCount; i++) {
+                if ((tick_values[i] < dmin) || (tick_values[i] > dmax)) {
+                    G_fatal_error(_("tick_value=%.3f out of range [%.3f, %.3f]"),
+                                  tick_values[i], dmin, dmax);
+                }
+                sprintf(buff, DispFormat, tick_values[i]);
+                if (strlen(units)>0)
+                    strcat(buff, units);
+                D_text_size(txsiz, txsiz);
+                D_get_text_box(buff,&bb,&bt, &bl, &br);
+                LabelW = br - bl;
+                if (LabelW > MaxLabelW) {
+                    MaxLabelW = LabelW;
+                    sprintf(MaxLabel, "%s", buff);
+                }
+
+                if (log_sc) {
+                    coef = (log10(tick_values[i]) - log10(dmin)) / (log10(dmax) - log10(dmin));
+                }
+                else
+                coef = (tick_values[i] - dmin) / ((dmax - dmin) * 1.0);
+
+                if (draw) {
+                    if (!flip) {
+                        if (!horiz) {
+                            if (show_ticks) {
+                                D_use_color(black);
+                                D_line_abs(x1, y0 + coef * lleg,
+                                           x1 + 6, y0 + coef * lleg);
+                            }
+                            D_pos_abs(x1 + label_indent,
+                                      y0 + coef * lleg + txsiz / 2);
+                        }
+                        else {
+                            if (show_ticks) {
+                                D_use_color(black);
+                                D_line_abs(x0 + coef * wleg, y1,
+                                           x0 + coef * wleg, y1 + 6);
+                            }
+                            D_pos_abs(x0 + coef * wleg -
+                                      (strlen(buff) * txsiz * .81 / 2),
+                                      y1 + label_indent + txsiz);
+                        }
+                    }
+                    else {
+                        if (!horiz) {
+                            if (show_ticks) {
+                                D_use_color(black);
+                                D_line_abs(x1, y1 - coef * lleg,
+                                           x1 + 6, y1 - coef * lleg);
+                            }
+                            D_pos_abs(x1 + label_indent,
+                                      y1 - coef * lleg + txsiz / 2);
+                        }
+                        else {
+                            if (show_ticks) {
+                                D_use_color(black);
+                                D_line_abs(x1 - coef * wleg, y1,
+                                           x1 - coef * wleg, y1 + 6);
+                            }
+                            D_pos_abs(x1 - coef * wleg -
+                                      (strlen(buff) * txsiz * .81 / 2),
+                                      y1 + label_indent + txsiz);
+                        }
+                    }
+                    D_use_color(color);
+                    D_text(buff);
+                }
+            }
+        }
+
+        /* LABEL_STEP OPTION */
+        if (opt_tstep->answer) {
+            if (log_sc) { /* logarithmic */
+                t_start=0;
+                while (log10(dmin) + t_start < log10(dmax)){
+                    num = ceil(log10(dmin)) + t_start;
+                    val = pow(10,num);
+                    sprintf(buff, DispFormat, val);
+                    if (strlen(units)>0)
+                        strcat(buff, units);
+                    D_text_size(txsiz, txsiz);
+                    D_get_text_box(buff,&bb,&bt, &bl, &br);
+                    LabelW = br - bl;
+                    if (LabelW > MaxLabelW) {
+                        MaxLabelW = LabelW;
+                        sprintf(MaxLabel, "%s", buff);
+                    }
+                    coef = (log10(val) - log10(dmin)) / (log10(dmax) - log10(dmin));
+                    if (draw){
+                        if (!flip){
+                            if (!horiz){
+                                if (show_ticks) {
+                                    D_use_color(black);
+                                    D_line_abs(x1, y0 + coef * lleg,
+                                               x1 + 6, y0 + coef * lleg);
+                                }
+                                D_pos_abs(x1 + label_indent,
+                                          y0 + coef * lleg + txsiz / 2);
+                            }
+                            else{
+                                if (show_ticks) {
+                                    D_use_color(black);
+                                    D_line_abs(x0 + coef * wleg, y1,
+                                               x0 + coef * wleg, y1 + 6);
+                                }
+                                D_pos_abs(x0 + coef * wleg -
+                                          (strlen(buff) * txsiz * .81 / 2),
+                                          y1 + label_indent + txsiz);
+                            }
+                        }
+                        else{
+                            if (!horiz){
+                                if (show_ticks) {
+                                    D_use_color(black);
+                                    D_line_abs(x1, y1 - coef * lleg,
+                                               x1 + 6, y1 - coef * lleg);
+                                }
+                                D_pos_abs(x1 + label_indent,
+                                          y1 - coef * lleg + txsiz / 2);
+                            }
+                            else{
+                                if (show_ticks){
+                                    D_use_color(black);
+                                    D_line_abs(x1 - coef * wleg, y1,
+                                               x1 - coef * wleg, y1 + 6);
+                                }
+                                D_pos_abs(x1 - coef * wleg -
+                                          (strlen(buff) * txsiz * .81 / 2),
+                                          y1 + label_indent + txsiz);
+                            }
+                        }
+                        D_use_color(color);
+                        D_text(buff);
+
+                    }
+                t_start += t_step;
+                }
+            }
+            else { /* linear */
+            t_start = ceil(dmin / t_step) * t_step;
+            if (t_start == -0)
+                t_start = 0;
+
+            if (!flip) {
+                if (!horiz)
+                    while (t_start <= dmax) {
+                        sprintf(buff, DispFormat, t_start);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                        }
+                        if (draw) {
+                            coef = (t_start - dmin) / ((dmax - dmin) * 1.0);
+                            if (show_ticks) {
+                                D_use_color(black);
+                                D_line_abs(x1, y0 + coef * lleg,
+                                           x1 + 6, y0 + coef * lleg);
+                            }
+                            D_pos_abs(x1 + label_indent,
+                                      y0 + coef * lleg + txsiz / 2);
+                            D_use_color(color);
+                            D_text(buff);
+                        }
+                        t_start += t_step;
+                    }
+                else
+                    while (t_start <= dmax) {
+                        sprintf(buff, DispFormat, t_start);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                        }
+
+                        if (draw) {
+                            coef = (t_start - dmin) / ((dmax - dmin) * 1.0);
+                            if (show_ticks) {
+                                D_use_color(black);
+                                D_line_abs(x0 + coef * wleg, y1,
+                                           x0 + coef * wleg, y1 + 6);
+                            }
+                            D_pos_abs(x0 + coef * wleg -
+                                      (strlen(buff) * txsiz * .81 / 2),
+                                      y1 + label_indent + txsiz);
+                            D_use_color(color);
+                            D_text(buff);
+                        }
+                        t_start += t_step;
+                    }
+            }
+            else {
+                if (!horiz)
+                    while (t_start <= dmax) {
+                        sprintf(buff, DispFormat, t_start);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                        }
+
+                        if (draw) {
+                            coef = (t_start - dmin) / ((dmax - dmin) * 1.0);
+                            if (show_ticks) {
+                                D_use_color(black);
+                                D_line_abs(x1, y1 - coef * lleg,
+                                           x1 + 6, y1 - coef * lleg);
+                            }
+                            D_pos_abs(x1 + label_indent,
+                                      y1 - coef * lleg + txsiz / 2);
+                            D_use_color(color);
+                            D_text(buff);
+                        }
+                        t_start += t_step;
+                    }
+                else
+                    while (t_start <= dmax) {
+                        sprintf(buff, DispFormat, t_start);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                        }
+
+                        if (draw) {
+                            coef = (t_start - dmin) / ((dmax - dmin) * 1.0);
+                            if (show_ticks){
+                                D_use_color(black);
+                                D_line_abs(x1 - coef * wleg, y1,
+                                           x1 - coef * wleg, y1 + 6);
+                            }
+                            D_pos_abs(x1 - coef * wleg -
+                                      (strlen(buff) * txsiz * .81 / 2),
+                                      y1 + label_indent + txsiz);
+                            D_use_color(color);
+                            D_text(buff);
+                        }
+                        t_start += t_step;
+                    }
+            }
+        }
+        }
+
+        if (draw) {
+            /* Draw boxes outside of legend bar */
+            /* White box */
+            D_use_color(white);
+            D_begin();
+            D_move_abs(x0 + 1, y0 + 1);
+            D_cont_rel(0, lleg - 2);
+            D_cont_rel(wleg - 2, 0);
+            D_cont_rel(0, -lleg + 2);
+            D_close();
+            D_end();
+            D_stroke();
+
+            /* Black box */
+            D_use_color(black);
+            D_begin();
+            D_move_abs(x0, y0);
+            D_cont_rel(0, lleg);
+            D_cont_rel(wleg, 0);
+            D_cont_rel(0, -lleg);
+            D_close();
+            D_end();
+            D_stroke();
+        }
+
+        /* Display sidebar histogram, if requested.
+           /  In case of horizontal legend, maximum of histogram - max_hist
+           will efect the title position */
+        max_hist = 0;
+        if (histo->answer) {
+            render_range.min = (DCELL) (fp ? dmin : min_ind);
+            render_range.max = (DCELL) (fp ? dmax : max_ind);
+            /* reuse flag to indicate if user-specified or default ranging */
+            render_range.first_time = opt_range->answer ? TRUE : FALSE;
+
+            if (draw)
+                max_hist =
+                    histogram(map_name, x0, y0, wleg, lleg, color, flip,
+                              horiz, maptype, fp, render_range, 1);
+            else
+                max_hist =
+                    histogram(map_name, x0, y0, wleg, lleg, color, flip,
+                              horiz, maptype, fp, render_range, 0);
+        }
+
+
+        /* display title or units */
+        if (strlen(title) > 0) {
+            D_text_size(titsiz, titsiz);
+            D_get_text_box(title, &bb, &bt, &bl, &br);
+            /* title */
+            if (horiz) {
+                x_tit = (x0 + x1) / 2. - (br - bl) / 2;
+                y_tit = y0 - (titsiz) - max_hist;
+            }
+            else {
+                x_tit = x0;
+                y_tit = y0 - txsiz;
+            }
+
+            x1_tit = x_tit + (br - bl);
+
+            if (draw) {
+                D_use_color(color);
+                /* use tit_fontsize */
+                D_text_size(titsiz, titsiz);
+
+                D_pos_abs(x_tit, y_tit);
+                D_text(title);
+                /* restart fontsize */
+                D_text_size(txsiz, txsiz);
+            }
+        }
+        else {
+            /* units */
+            /* print units label, if present */
+            if (maptype == MAP_TYPE_RASTER2D)
+                units_bottom = Rast_read_units(map_name, "");
+            else
+                units = "";
+            /* FIXME: does the raster3d really need to be opened to read the units?
+               units_bottom = Rast3d_get_unit(map_fid); */
+
+            if (!units_bottom)
+                units_bottom = "";
+
+            if (strlen(units_bottom)) {
+                D_text_size(titsiz, titsiz);
+                D_get_text_box(title, &bb, &bt, &bl, &br);
+                if (horiz) {
+                    x_tit =
+                        (x0 + x1) / 2. - (br - bl) / 2;
+                    y_tit = y1 + (txsiz * 2.75);
+                }
+                else {
+                    x_tit = x0;
+                }
+                x1_tit = x_tit + (br - bl);
+
+                if (draw) {
+                    D_use_color(color);
+                    D_pos_abs(x_tit, y_tit);
+                    D_text(units_bottom);
+                }
+            }
+        }                       /* end of display units) */
+
+        if (!draw) {
+            /* Draw background */
+            D_text_size(txsiz, txsiz);
+            D_get_text_box(MaxLabel, &bb, &bt, &bl, &br);
+            if (!horiz) {
+                x0bg = x0 - max_hist - txsiz;
+                x1bg = x0 + wleg + label_indent + (br - bl) + txsiz;
+                if (x1bg < x1_tit)
+                    x1bg = x1_tit + txsiz;
+                y1bg = y0 + lleg + txsiz;
+                if (strlen(title) > 0)
+                    y0bg = y0 - titsiz -2 * txsiz;
+                else
+                    y0bg = y0 - txsiz;
+            }
+            else {
+                x0bg = x0 - (br - bl) / 2 - txsiz;
+                x1bg = x0 + wleg + (br - bl) / 2 + txsiz;
+                if (x1bg < x1_tit) {
+                    x0bg = x_tit - txsiz;
+                    x1bg = x1_tit + txsiz;
+                }
+                y1bg = y0 + lleg + label_indent + 1.5 * txsiz;
+                if (strlen(title) > 0)
+                    y0bg = y0 - (2.5 * titsiz) - max_hist;
+                else
+                    y0bg = y0 - titsiz - max_hist;
+            }
+
+            if (colorbg != 0) {
+                D_use_color(colorbg);
+                D_box_abs(x0bg, y0bg, x1bg, y1bg);
+            }
+
+            D_use_color(colorb);
+            D_begin();
+            D_move_abs(x0bg, y0bg);
+            D_cont_abs(x0bg, y1bg);
+            D_cont_abs(x1bg, y1bg);
+            D_cont_abs(x1bg, y0bg);
+            D_close();
+            D_end();
+            D_stroke();
+        }
+
+    }                           /* end of if(do_smooth) */
+
+    else {                      /* non FP, no smoothing */
+        ScaleFactor = 1.0;
+
+        if (histo->answer)
+            G_warning(_("Histogram plotting not implemented for categorical legends. "
+                       "Use the '-s' flag"));
+
+        /* set legend box bounds */
+        true_l = l;
+        true_r = r;             /* preserve window width */
+        l = x0;
+        t = y0;
+        r = x1;
+        b = y1;
+
+        /* figure out box height  */
+        if (do_cats == cats_num)
+            dots_per_line = (b - t) / (lines + 1);      /* +1 line for the two 1/2s at top and bottom */
+        else
+            dots_per_line = (b - t) / (lines + 2);      /* + another line for 'x of y categories' text */
+
+        /* adjust text size */
+        /*  txsiz = (int)((y1-y0)/(1.5*(lines+5))); */
+        txsiz = (y1 - y0) / (2.0 * lines);
+
+        if (tit_fontsize == 0)
+            titsiz = txsiz;
+        else
+            titsiz = tit_fontsize;
+
+        /* scale text to fit in window if position not manually set */
+        if (opt_at->answer == NULL) {   /* ie defualt scaling */
+            ScaleFactor = ((true_r - true_l) / ((MaxLabelLen + 3) * txsiz * 0.81));     /* ?? txsiz*.81=actual text width. */
+            if (ScaleFactor < 1.0) {
+                txsiz = txsiz * ScaleFactor;
+                dots_per_line = (int)floor(dots_per_line * ScaleFactor);
+            }
+        }
+
+        if (dots_per_line < txsiz)
+            txsiz = dots_per_line;
+
+        if (opt_fontsize->answer != NULL)
+            txsiz = fontsize;
+
+        /* Set up box arrays */
+        x_box[0] = 0;
+        y_box[0] = 0;
+        x_box[1] = 0;
+        y_box[1] = (5 - dots_per_line);
+        x_box[2] = (dots_per_line - 5);
+        y_box[2] = 0;
+        x_box[3] = 0;
+        y_box[3] = (dots_per_line - 5);
+        x_box[4] = (5 - dots_per_line);
+        y_box[4] = 0;
+
+
+        /* Draw away */
+
+        /* if(ScaleFactor < 1.0)   */
+        /*    cur_dot_row = ((b-t) - (dots_per_line*lines))/2; *//* this will center the legend */
+        /* else    */
+        cur_dot_row = t + dots_per_line / 2;
+
+        /*  j = (do_cats == cats_num ? 1 : 2 ); */
+
+        if (draw) {
+            D_pos_abs(x0, y0);
+            D_text_size(txsiz, txsiz);
+        }
+
+        for (i = 0, k = 0; i < catlistCount; i++)
+            /* for(i=min_ind, j=1, k=0; j<=do_cats && i<=max_ind; j++, i+=thin) */
+        {
+            if (!flip)
+                cstr = Rast_get_d_cat(&catlist[i], &cats);
+            else
+                cstr = Rast_get_d_cat(&catlist[catlistCount - i - 1], &cats);
+
+
+            if (!cstr[0]) {     /* no cat label found, skip str output */
+                hide_catstr = 1;
+                if (hide_nodata)
+                    continue;
+            }
+            else
+                hide_catstr = hidestr->answer;
+
+            k++;                /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
+
+            cur_dot_row += dots_per_line;
+
+            if (draw) {
+                /* Black box */
+                D_use_color(black);
+                D_begin();
+                D_move_abs(l + 2, (cur_dot_row - 1));
+                D_cont_rel(0, (3 - dots_per_line));
+                D_cont_rel((dots_per_line - 3), 0);
+                D_cont_rel(0, (dots_per_line - 3));
+                D_close();
+                D_end();
+                D_stroke();
+
+                /* White box */
+                D_use_color(white);
+                D_begin();
+                D_move_abs(l + 3, (cur_dot_row - 2));
+                D_cont_rel(0, (5 - dots_per_line));
+                D_cont_rel((dots_per_line - 5), 0);
+                D_cont_rel(0, (dots_per_line - 5));
+                D_close();
+                D_end();
+                D_stroke();
+
+
+                /* Color solid box */
+                if (!fp) {
+                    if (!flip)
+                        D_color((CELL) (int)catlist[i], &colors);
+                    else
+                        D_color((CELL) (int)catlist[catlistCount - i - 1],
+                                &colors);
+                }
+                else {
+                    if (!flip)
+                        D_d_color(catlist[i], &colors);
+                    else
+                        D_d_color(catlist[catlistCount - i - 1], &colors);
+                }
+
+                D_pos_abs(l + 3, (cur_dot_row - 2));
+                D_polygon_rel(x_box, y_box, 5);
+
+                /* Draw text */
+                D_use_color(color);
+            }
+
+
+            if (!fp) {
+                /* nothing, box only */
+                buff[0] = 0;
+                if (!hide_catnum) {     /* num */
+                    sprintf(buff, DispFormat, (int)catlist[i]);
+                    if (strlen(units)>0)
+                        strcat(buff, units);
+                    D_text_size(txsiz, txsiz);
+                    D_get_text_box(buff,&bb,&bt, &bl, &br);
+                    LabelW = br - bl;
+                    if (LabelW > MaxLabelW) {
+                        MaxLabelW = LabelW;
+                        sprintf(MaxLabel, "%s", buff);
+                    }
+                    if (!flip) {
+                        sprintf(buff, DispFormat, (int)catlist[i]);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                        }
+                    }
+                    else {
+                        sprintf(buff, DispFormat,
+                                (int)catlist[catlistCount - i - 1]);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                        }
+                    }
+                    if (!hide_catstr)   /* both */
+                        strcat(buff, ")");
+                }
+                if (!hide_catstr) {       /* str */
+                    sprintf(buff + strlen(buff), " %s", cstr);
+                    if (strlen(units)>0)
+                        strcat(buff, units);
+                    D_text_size(txsiz, txsiz);
+                    D_get_text_box(buff,&bb,&bt, &bl, &br);
+                    LabelW = br - bl;
+                    if (LabelW > MaxLabelW) {
+                        MaxLabelW = LabelW;
+                        sprintf(MaxLabel, " %s", buff);
+            }
+                }
+            }
+            else {              /* is fp */
+                if (!flip) {
+                    if (use_catlist) {
+                        /* pass through format exactly as given by the user in
+                           the use= command line parameter (helps with log scale) */
+                        sprintf(buff, "%s", opt_use->answers[i]);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, " %s", buff);
+                        }
+                    }
+                    else {
+                        /* automatically generated/tuned decimal precision format */
+                        sprintf(buff, DispFormat, catlist[i]);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, "%s", buff);
+                }
+                    }
+                }
+                else {
+                    if (use_catlist){
+                        sprintf(buff, "%s", opt_use->answers[catlistCount - i - 1]);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, " %s", buff);
+                }
+            }
+                    else {
+                        sprintf(buff, DispFormat, catlist[catlistCount - i - 1]);
+                        if (strlen(units)>0)
+                            strcat(buff, units);
+                        D_text_size(txsiz, txsiz);
+                        D_get_text_box(buff,&bb,&bt, &bl, &br);
+                        LabelW = br - bl;
+                        if (LabelW > MaxLabelW) {
+                            MaxLabelW = LabelW;
+                            sprintf(MaxLabel, " %s", buff);
+            }
+                    }
+                }
+            }
+
+            if (draw) {
+                D_pos_abs((l + 3 + dots_per_line), (cur_dot_row) - 3);
+                if (color)
+                    D_text(buff);
+            }
+        }
+
+        if (0 == k)
+            G_fatal_error(_("Nothing to draw! (no categories with labels?)"));  /* "(..., out of range?)" */
+
+        /* display title */
+        if (strlen(title) > 0) {
+            x_tit = x0;
+            y_tit = y0 - txsiz;
+
+            D_text_size(titsiz, titsiz);
+            D_get_text_box(title, &bb, &bt, &bl, &br);
+            x1_tit = x_tit + (br - bl);
+
+            if (draw) {
+                D_use_color(color);
+                /* use tit_fontsize */
+                D_text_size(titsiz, titsiz);
+                D_pos_abs(x_tit, y_tit);
+                D_text(title);
+                /* restart fontsize */
+                D_text_size(txsiz, txsiz);
+            }
+        }
+
+        /* Display info line about numbers of categories */
+        if (do_cats != cats_num) {
+            cur_dot_row += dots_per_line;
+            /* sprintf(buff, "%d of %d categories\n", (j-1), cats_num); */
+
+            sprintf(buff, "%d of %d categories\n", k, cats_num);
+            if (strlen(buff) > MaxLabelLen) {
+                MaxLabelLen = strlen(buff);
+                sprintf(MaxLabel, "%d of %d categories\n", k, cats_num);
+            }
+
+            if (draw) {
+                if (opt_fontsize->answer != NULL)
+                    txsiz = fontsize;
+                D_text_size(txsiz, txsiz);
+                D_use_color(black);
+                D_pos_abs((l + 3 + dots_per_line), (cur_dot_row));
+                if (color)
+                    D_text(buff);
+            }
+        }
+
+        if (!draw) {
+            /* Draw background */
+            D_text_size(txsiz, txsiz);
+            D_get_text_box(MaxLabel, &bb, &bt, &bl, &br);
+            x0bg = x0 - txsiz;
+            x1bg =
+                x0 + dots_per_line + 3 + (br - bl) + txsiz;
+            if (x1bg < x1_tit)
+                x1bg = x1_tit + txsiz;
+            y1bg = cur_dot_row + txsiz;
+            if (strlen(title) > 0)
+                y0bg = y0 - 2 * txsiz - titsiz;
+            else
+                y0bg = y0 - txsiz;
+
+
+            if (colorbg != 0) {
+                D_use_color(colorbg);
+                D_box_abs(x0bg, y0bg, x1bg, y1bg);
+            }
+
+            D_use_color(colorb);
+            D_begin();
+            D_move_abs(x0bg, y0bg);
+            D_cont_abs(x0bg, y1bg);
+            D_cont_abs(x1bg, y1bg);
+            D_cont_abs(x1bg, y0bg);
+            D_close();
+            D_end();
+            D_stroke();
+        }
+
+    }
+    D_save_command(G_recreate_command());
+}

Modified: grass/branches/releasebranch_7_2/display/d.legend/get_stats.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/get_stats.c	2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/get_stats.c	2016-07-27 18:05:07 UTC (rev 69037)
@@ -7,18 +7,18 @@
 
 
 void run_stats(const char *mapname, int nsteps, const char *tempfile,
-	       int map_type)
+               int map_type)
 {
     char buf[32];
     const char *argv[12];
     int argc = 0;
 
     if (map_type == MAP_TYPE_RASTER2D) {
-	argv[argc++] = "r.stats";
-	argv[argc++] = "-r";
+        argv[argc++] = "r.stats";
+        argv[argc++] = "-r";
     }
     else
-	argv[argc++] = "r3.stats";
+        argv[argc++] = "r3.stats";
 
     argv[argc++] = "-c";
     argv[argc++] = mapname;
@@ -34,42 +34,43 @@
     argv[argc++] = NULL;
 
     if (G_vspawn_ex(argv[0], argv) != 0)
-	G_fatal_error("error running r.stats");
+        G_fatal_error("error running r.stats");
 }
 
 /* linked list of stats */
 void get_stats(const char *mapname, struct stat_list *dist_stats, int nsteps,
-	       int map_type)
+               int map_type)
 {
-    char buf[1024];		/* input buffer for reading stats */
+    char buf[1024];             /* input buffer for reading stats */
     int done = FALSE;
-    char *tempfile;		/* temp file name */
-    FILE *fd;			/* temp file pointer */
-/*
-    int is_fp;
-    struct FPRange fp_range;
-*/
-    long int cat;		/* a category value */
-    long int stat;		/* a category stat value */
+    char *tempfile;             /* temp file name */
+    FILE *fd;                   /* temp file pointer */
+
+    /*
+       int is_fp;
+       struct FPRange fp_range;
+     */
+    long int cat;               /* a category value */
+    long int stat;              /* a category stat value */
     struct stat_node *ptr = NULL;
     int first;
 
     /* write stats to a temp file */
     tempfile = G_tempfile();
-/*
-    is_fp = Rast_map_is_fp(mapname, "");
-    if (is_fp) {
-	if (Rast_read_fp_range(mapname, "", &fp_range) <= 0)
-	    G_fatal_error("Can't read frange file");
-    }
-*/
+    /*
+       is_fp = Rast_map_is_fp(mapname, "");
+       if (is_fp) {
+       if (Rast_read_fp_range(mapname, "", &fp_range) <= 0)
+       G_fatal_error("Can't read frange file");
+       }
+     */
     run_stats(mapname, nsteps, tempfile, map_type);
 
     /* open temp file and read the stats into a linked list */
     fd = fopen(tempfile, "r");
     if (fd == NULL) {
-	perror("opening r.stats output file");
-	G_fatal_error("unable to continue.");
+        perror("opening r.stats output file");
+        G_fatal_error("unable to continue.");
     }
     dist_stats->ptr = NULL;
     dist_stats->count = 0;
@@ -78,71 +79,71 @@
     first = TRUE;
 
     while (!done) {
-	if (fgets(buf, sizeof(buf), fd) != NULL) {
-	    /* WARNING!!!!!!
-	     * this will be very wrong if type!=COUNT
-	     * since the stat prodcued by r.stats will be a floating point value
-	     * possibly less than 1 (shapiro)
-	     */
-	    if (sscanf(buf, "* %ld", &stat) == 1) {
-		dist_stats->null_stat = stat;
-/*
-		if (stat > dist_stats->maxstat && nodata)
-		    dist_stats->maxstat = stat;
-		if (stat < dist_stats->minstat && nodata)
-		    dist_stats->minstat = stat;
-		if (nodata)
-		    dist_stats->sumstat += stat;
-*/
-	    }
-	    else if (sscanf(buf, "%ld %ld", &cat, &stat) == 2) {
-		/* count stats */
-		dist_stats->count++;
+        if (fgets(buf, sizeof(buf), fd) != NULL) {
+            /* WARNING!!!!!!
+             * this will be very wrong if type!=COUNT
+             * since the stat prodcued by r.stats will be a floating point value
+             * possibly less than 1 (shapiro)
+             */
+            if (sscanf(buf, "* %ld", &stat) == 1) {
+                dist_stats->null_stat = stat;
+                /*
+                   if (stat > dist_stats->maxstat && nodata)
+                   dist_stats->maxstat = stat;
+                   if (stat < dist_stats->minstat && nodata)
+                   dist_stats->minstat = stat;
+                   if (nodata)
+                   dist_stats->sumstat += stat;
+                 */
+            }
+            else if (sscanf(buf, "%ld %ld", &cat, &stat) == 2) {
+                /* count stats */
+                dist_stats->count++;
 
-		/* sum stats */
-		dist_stats->sumstat += stat;
+                /* sum stats */
+                dist_stats->sumstat += stat;
 
-		/* a max or a min stat? */
-		if (first) {
-		    dist_stats->maxstat = stat;
-		    dist_stats->minstat = stat;
-		    dist_stats->maxcat = cat;
-		    dist_stats->mincat = cat;
-		    first = FALSE;
-		}
-		if (stat > dist_stats->maxstat)
-		    dist_stats->maxstat = stat;
-		if (stat < dist_stats->minstat)
-		    dist_stats->minstat = stat;
+                /* a max or a min stat? */
+                if (first) {
+                    dist_stats->maxstat = stat;
+                    dist_stats->minstat = stat;
+                    dist_stats->maxcat = cat;
+                    dist_stats->mincat = cat;
+                    first = FALSE;
+                }
+                if (stat > dist_stats->maxstat)
+                    dist_stats->maxstat = stat;
+                if (stat < dist_stats->minstat)
+                    dist_stats->minstat = stat;
 
-		/* a max or a min cat? */
-		if (cat > dist_stats->maxcat)
-		    dist_stats->maxcat = cat;
-		if (cat < dist_stats->mincat)
-		    dist_stats->mincat = cat;
+                /* a max or a min cat? */
+                if (cat > dist_stats->maxcat)
+                    dist_stats->maxcat = cat;
+                if (cat < dist_stats->mincat)
+                    dist_stats->mincat = cat;
 
-		/* put it in the list */
-		if (dist_stats->ptr == NULL) {
-		    /* first in list */
-		    dist_stats->ptr = (struct stat_node *)
-			G_malloc(sizeof(struct stat_node));
-		    dist_stats->ptr->cat = cat;
-		    dist_stats->ptr->stat = stat;
-		    dist_stats->ptr->next = NULL;
-		    ptr = dist_stats->ptr;
-		}
-		else {
-		    ptr->next = (struct stat_node *)
-			G_malloc(sizeof(struct stat_node));
-		    ptr->next->cat = cat;
-		    ptr->next->stat = stat;
-		    ptr->next->next = NULL;	/* mod: shapiro */
-		    ptr = ptr->next;
-		}
-	    }
-	}
-	else
-	    done = TRUE;
+                /* put it in the list */
+                if (dist_stats->ptr == NULL) {
+                    /* first in list */
+                    dist_stats->ptr = (struct stat_node *)
+                        G_malloc(sizeof(struct stat_node));
+                    dist_stats->ptr->cat = cat;
+                    dist_stats->ptr->stat = stat;
+                    dist_stats->ptr->next = NULL;
+                    ptr = dist_stats->ptr;
+                }
+                else {
+                    ptr->next = (struct stat_node *)
+                        G_malloc(sizeof(struct stat_node));
+                    ptr->next->cat = cat;
+                    ptr->next->stat = stat;
+                    ptr->next->next = NULL;     /* mod: shapiro */
+                    ptr = ptr->next;
+                }
+            }
+        }
+        else
+            done = TRUE;
     }
     fclose(fd);
     unlink(tempfile);

Modified: grass/branches/releasebranch_7_2/display/d.legend/histogram.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/histogram.c	2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/histogram.c	2016-07-27 18:05:07 UTC (rev 69037)
@@ -13,14 +13,14 @@
 #include <grass/glocale.h>
 #include "local_proto.h"
 
-void draw_histogram(const char *map_name, int x0, int y0, int width,
-		    int height, int color, int flip, int horiz,
-		    int map_type, int is_fp, struct FPRange render_range)
+double histogram(const char *map_name, int x0, int y0, int width,
+                 int height, int color, int flip, int horiz, int map_type,
+                 int is_fp, struct FPRange render_range, int drawh)
 {
     int i, nsteps, ystep;
     long cell_count = 0;
-    double max_width, width_mult, dx;
-    double dy, y0_adjust;	/* only needed for CELL maps */
+    double max_width, width_mult, dx, max;
+    double dy, y0_adjust;       /* only needed for CELL maps */
     struct stat_list dist_stats;
     struct stat_node *ptr;
     struct Range range;
@@ -31,83 +31,90 @@
     double crop_min_perc = 0.0, crop_max_perc = 1.0, pad_min_perc = 0.0;
 
     if (horiz) {
-	max_width = height * 1.75;
-	nsteps = width - 3;
+        max_width = height * 1.75;
+        nsteps = width - 3;
     }
     else {
-	max_width = width * 1.75;
-	nsteps = height - 3;
+        max_width = width * 1.75;
+        nsteps = height - 3;
     }
 
+    /* reset return value max */
+    max = 0;
 
+
     if (render_range.first_time) {
-	/* user specified range, can be either larger
-	    or smaller than actual map's range */
+        /* user specified range, can be either larger
+           or smaller than actual map's range */
 
-	if (is_fp) {
-	    Rast_read_fp_range(map_name, "", &fprange);
-	    Rast_get_fp_range_min_max(&fprange, &d_map_min, &d_map_max);
-	    map_min = (double)d_map_min;
-	    map_max = (double)d_map_max;
-	}
-	else {
-	    Rast_read_range(map_name, "", &range);
-	    Rast_get_range_min_max(&range, &c_map_min, &c_map_max);
-	    map_min = (double)c_map_min;
-	    map_max = (double)c_map_max;
-	}
+        if (is_fp) {
+            Rast_read_fp_range(map_name, "", &fprange);
+            Rast_get_fp_range_min_max(&fprange, &d_map_min, &d_map_max);
+            map_min = (double)d_map_min;
+            map_max = (double)d_map_max;
+        }
+        else {
+            Rast_read_range(map_name, "", &range);
+            Rast_get_range_min_max(&range, &c_map_min, &c_map_max);
+            map_min = (double)c_map_min;
+            map_max = (double)c_map_max;
+        }
 
-	map_range = map_max - map_min;
-	user_range = render_range.max - render_range.min;
+        map_range = map_max - map_min;
+        user_range = render_range.max - render_range.min;
 
-	if (horiz)
-	    nsteps = (int)(0.5 + (map_range * (width - 3) / user_range));
-	else
-	    nsteps = (int)(0.5 + (map_range * (height - 3) / user_range));
+        if (horiz)
+            nsteps = (int)(0.5 + (map_range * (width - 3) / user_range));
+        else
+            nsteps = (int)(0.5 + (map_range * (height - 3) / user_range));
 
-	G_debug(1, "number of steps for r.stats = %d, height-3=%d  width-3=%d",
-		nsteps, height - 3, width - 3);
+        G_debug(1,
+                "number of steps for r.stats = %d, height-3=%d  width-3=%d",
+                nsteps, height - 3, width - 3);
 
-	/* need to know the % of the MAP range where user range starts and stops.
-	 *   note that MAP range can be fully inside user range, in which case
-	 *   keep 0-100% aka 0,nsteps, i.e. the step number in the nsteps range */
+        /* need to know the % of the MAP range where user range starts and stops.
+         *   note that MAP range can be fully inside user range, in which case
+         *   keep 0-100% aka 0,nsteps, i.e. the step number in the nsteps range */
 
-	if (render_range.min > map_min) {
-	   crop_min_perc = (render_range.min - map_min) / map_range;
-	   G_debug(3, "min: %.02f vs. %.02f (%.02f) ... %.02f%%",
-	   	   render_range.min, map_min, map_range, 100 * crop_min_perc);
-	}
+        if (render_range.min > map_min) {
+            crop_min_perc = (render_range.min - map_min) / map_range;
+            G_debug(3, "min: %.02f vs. %.02f (%.02f) ... %.02f%%",
+                    render_range.min, map_min, map_range,
+                    100 * crop_min_perc);
+        }
 
-	if (render_range.max > map_max) {
-	    crop_max_perc = 1.0 - ((render_range.max - map_max) / user_range);
-	    G_debug(3, "max: %.02f vs. %.02f (%.02f) ... %.02f%%",
-		    map_max, render_range.max, map_range, 100 * crop_max_perc);
-	}
+        if (render_range.max > map_max) {
+            crop_max_perc = 1.0 - ((render_range.max - map_max) / user_range);
+            G_debug(3, "max: %.02f vs. %.02f (%.02f) ... %.02f%%",
+                    map_max, render_range.max, map_range,
+                    100 * crop_max_perc);
+        }
 
-	if (render_range.min < map_min) {
-	   pad_min_perc = (map_min - render_range.min) / user_range;
-	   G_debug(3, "Min: %.02f vs. %.02f (%.02f) ... %.02f%%",
-	   	   map_min, render_range.min, user_range, 100 * pad_min_perc);
-	}
+        if (render_range.min < map_min) {
+            pad_min_perc = (map_min - render_range.min) / user_range;
+            G_debug(3, "Min: %.02f vs. %.02f (%.02f) ... %.02f%%",
+                    map_min, render_range.min, user_range,
+                    100 * pad_min_perc);
+        }
 
 #ifdef amplify_gain
-	/* proportion of nsteps to width, use as mult factor to boost the 1.75x
-	    when spread out over more nsteps than we are displaying */
-	G_debug(0, "max_width was: %.2f  (nsteps=%d)", max_width, nsteps);
+        /* proportion of nsteps to width, use as mult factor to boost the 1.75x
+           when spread out over more nsteps than we are displaying */
+        G_debug(0, "max_width was: %.2f  (nsteps=%d)", max_width, nsteps);
 
-	if (nsteps > ((horiz ? width : height) - 3.0))
-	    max_width *= nsteps / ((horiz ? width : height) - 3.0);
+        if (nsteps > ((horiz ? width : height) - 3.0))
+            max_width *= nsteps / ((horiz ? width : height) - 3.0);
 
-	G_debug(0, "max_width now: %.2f", max_width);
+        G_debug(0, "max_width now: %.2f", max_width);
 #endif
     }
 
 
     /* TODO */
     if (!is_fp && render_range.first_time) {
-	G_warning(_("Histogram constrained by range not yet implemented for "
-		  "categorical rasters"));
-	return;
+        G_warning(_("Histogram constrained by range not yet implemented for "
+                    "categorical rasters"));
+        return max;
     }
 
 
@@ -115,139 +122,150 @@
     get_stats(map_name, &dist_stats, nsteps, map_type);
 
     width_mult = max_width / dist_stats.maxstat;
+    ptr = dist_stats.ptr;
 
-    D_use_color(color);
-    D_begin();
+    if (drawh) {
+        D_use_color(color);
+        D_begin();
 
-    ptr = dist_stats.ptr;
+        if (!is_fp) {
+            dy = (nsteps + 3.0) / (1 + dist_stats.maxcat - dist_stats.mincat);
 
-    if (!is_fp) {
-	dy = (nsteps + 3.0) / (1 + dist_stats.maxcat - dist_stats.mincat);
+            if (flip)
+                dy *= -1;
 
-	if (flip)
-	    dy *= -1;
+            if (dist_stats.mincat == 0)
+                y0_adjust = dy;
+            else
+                y0_adjust = 0;
 
-	if (dist_stats.mincat == 0)
-	    y0_adjust = dy;
-	else
-	    y0_adjust = 0;
-
-	if (!flip)  /* mmph */
-	    y0_adjust += 0.5;
+            if (!flip)          /* mmph */
+                y0_adjust += 0.5;
+        }
     }
 
 
-    G_debug(3, "mincat=%ld  maxcat=%ld", dist_stats.mincat, dist_stats.maxcat);
+    G_debug(3, "mincat=%ld  maxcat=%ld", dist_stats.mincat,
+            dist_stats.maxcat);
 
     for (i = dist_stats.mincat, ystep = 0; i <= dist_stats.maxcat; i++) {
-	if (!ptr)
-	    break;
+        cell_count = 0;
+        if (!ptr)
+            break;
 
-	/* jump out if user range cuts things shorter than the map's native range */
-	if ((horiz && ystep > width - 4) || (!horiz && ystep > height - 4))
-	    break;
+        /* jump out if user range cuts things shorter than the map's native range */
+        if ((horiz && ystep > width - 4) || (!horiz && ystep > height - 4))
+            break;
 
-	/* jump out if user range goes beyond max of map data */
-	if (((double)ystep / ((horiz ? width : height) - 3.0)) > crop_max_perc)
-	    break;
-/* TODO	if (!is_fp && i > render_range.max)
-	    break;
-*/
-	/* haven't made it to the min of the user range yet */
-	if (((double)i / nsteps) < crop_min_perc) {
-	    continue;
-	}
+        /* jump out if user range goes beyond max of map data */
+        if (((double)ystep / ((horiz ? width : height) - 3.0)) >
+            crop_max_perc)
+            break;
+        /* TODO if (!is_fp && i > render_range.max)
+           break;
+         */
+        /* haven't made it to the min of the user range yet */
+        if (((double)i / nsteps) < crop_min_perc) {
+            continue;
+        }
 
-	/* now it's ok advance the plotter position */
-	ystep++;
+        /* now it's ok advance the plotter position */
+        ystep++;
 
-	/* if user range is below the minimum real map value, we need to pad out the space */
-	if (render_range.first_time && render_range.min < map_min) {
-	    if ( ((double)ystep / ((horiz ? width : height) - 3.0)) < pad_min_perc) {
-		i--;
-		continue;
-	    }
-	}
+        /* if user range is below the minimum real map value, we need to pad out the space */
+        if (render_range.first_time && render_range.min < map_min) {
+            if (((double)ystep / ((horiz ? width : height) - 3.0)) <
+                pad_min_perc) {
+                i--;
+                continue;
+            }
+        }
 
-	if (ptr->cat == i) {	/* AH-HA!! found the stat */
-	    cell_count = ptr->stat;
+        if (ptr->cat == i) {    /* AH-HA!! found the stat */
+            cell_count = ptr->stat;
 
-	    if (ptr->next != NULL)
-		ptr = ptr->next;
-	}
-	else {			/* we have to look for the stat */
+            if (ptr->next != NULL)
+                ptr = ptr->next;
+        }
+        else {                  /* we have to look for the stat */
 
-	    /* loop until we find it, or pass where it should be */
-	    while (ptr->cat < i && ptr->next != NULL)
-		ptr = ptr->next;
-	    if (ptr->cat == i) {	/* AH-HA!! found the stat */
-		cell_count = ptr->stat;
+            /* loop until we find it, or pass where it should be */
+            while (ptr->cat < i && ptr->next != NULL)
+                ptr = ptr->next;
+            if (ptr->cat == i) {        /* AH-HA!! found the stat */
+                cell_count = ptr->stat;
 
-		if (ptr->next != NULL)
-		    ptr = ptr->next;
-	    }
-	    else		/* stat cannot be found */
-		G_debug(5, "No matching stat found, i=%d", i);
-	}
+                if (ptr->next != NULL)
+                    ptr = ptr->next;
+            }
+            else                /* stat cannot be found */
+                G_debug(5, "No matching stat found, i=%d", i);
+        }
 
-	G_debug(5, "i=%d  ptr->cat=%ld  cell_count=%ld", i, ptr->cat, 
-		cell_count);
+        G_debug(5, "i=%d  ptr->cat=%ld  cell_count=%ld", i, ptr->cat,
+                cell_count);
 
-	if (!cell_count)
-	    continue;
+        if (!cell_count)
+            continue;
 
-	dx = cell_count * width_mult;
+        dx = cell_count * width_mult;
 
-	if (is_fp) {
-	    if (horiz) {
-		if (flip)
-		    D_move_abs(x0 + width - ystep - 1, y0 - 1);
-		else
-		    D_move_abs(x0 + ystep + 1, y0 - 1);
+        if (drawh) {
+            if (is_fp) {
+                if (horiz) {
+                    if (flip)
+                        D_move_abs(x0 + width - ystep - 1, y0 - 1);
+                    else
+                        D_move_abs(x0 + ystep + 1, y0 - 1);
 
-		D_cont_rel(0, -dx);
-	    }
-	    else {  /* vertical */
-		if (flip)
-		    D_move_abs(x0 - 1, y0 - 1 + height - ystep);
-		else
-		    D_move_abs(x0 - 1, y0 + 1 + ystep);
+                    D_cont_rel(0, -dx);
+                }
+                else {          /* vertical */
+                    if (flip)
+                        D_move_abs(x0 - 1, y0 - 1 + height - ystep);
+                    else
+                        D_move_abs(x0 - 1, y0 + 1 + ystep);
 
-		D_cont_rel(-dx, 0);
-	    }
-	}
-	else {	/* categorical */
+                    D_cont_rel(-dx, 0);
+                }
+            }
+            else {              /* categorical */
 
-	    if (horiz) {
-		if (flip)
-		    D_box_abs(x0 + width + y0_adjust + ((i - 1) * dy),
-			      y0 - 1,
-			      x0 + width + y0_adjust + 1 + (i * dy),
-			      y0 - 1 - dx);
-		else
-		    D_box_abs(x0 + y0_adjust + ((i - 1) * dy),
-			      y0 - 1,
-			      x0 - 1 + y0_adjust + (i * dy),
-			      y0 - 1 - dx);
-	    }
-	    else {  /* vertical */
+                if (horiz) {
+                    if (flip)
+                        D_box_abs(x0 + width + y0_adjust + ((i - 2) * dy),
+                                  y0 - 1,
+                                  x0 + width + y0_adjust + 1 + ((i - 1) * dy),
+                                  y0 - 1 - dx);
+                    else
+                        D_box_abs(x0 + y0_adjust + ((i - 2) * dy),
+                                  y0 - 1,
+                                  x0 - 1 + y0_adjust + ((i - 1) * dy), y0 - 1 - dx);
+                }
+                else {          /* vertical */
 
-		if (flip)
-		    /* GRASS_EPSILON fudge around D_box_abs() weirdness + PNG driver */
-		    D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
-			      y0 + height + y0_adjust + ((i - 1) * dy),
-			      x0 - 1 - dx,
-			      y0 + height + y0_adjust + 1 + (i * dy));
-		else
-		    D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
-			      y0 + y0_adjust + ((i - 1) * dy),
-			      x0 - 1 - dx,
-			      y0 + y0_adjust - 1 + (i * dy));
-	    }
-	}
+                    if (flip)
+                        /* GRASS_EPSILON fudge around D_box_abs() weirdness + PNG driver */
+                        D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
+                                  y0 + height + y0_adjust + ((i - 2) * dy),
+                                  x0 - 1 - dx,
+                                  y0 + height + y0_adjust + 1 + ((i - 1) * dy));
+                    else
+                        D_box_abs(x0 - 1 - GRASS_EPSILON * 10,
+                                  y0 + y0_adjust + ((i - 2) * dy),
+                                  x0 - 1 - dx, y0 + y0_adjust - 1 + ((i - 1) * dy));
+                }
+            }
+        }
+        if (dx > max)
+            max = dx;
     }
 
-    D_close();
-    D_end();
-    D_stroke();
+    if (drawh) {
+        D_close();
+        D_end();
+        D_stroke();
+    }
+
+    return max;
 }

Modified: grass/branches/releasebranch_7_2/display/d.legend/local_proto.h
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/local_proto.h	2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/local_proto.h	2016-07-27 18:05:07 UTC (rev 69037)
@@ -3,9 +3,9 @@
 #define MAP_TYPE_RASTER2D 1
 #define MAP_TYPE_RASTER3D 2
 /* possibles for the future:
-#define MAP_TYPE_VECTOR 3
-#define MAP_TYPE_RULES 4
-*/
+   #define MAP_TYPE_VECTOR 3
+   #define MAP_TYPE_RULES 4
+ */
 
 struct stat_node
 {
@@ -29,9 +29,17 @@
 
 
 /* histogram.c */
-void draw_histogram(const char *, int, int, int, int, int, int, int, int,
-		    int, struct FPRange);
+double histogram(const char *, int, int, int, int, int, int, int, int,
+                 int, struct FPRange, int);
 
 /* get_stats.c */
 void get_stats(const char *, struct stat_list *, int, int);
 void run_stats(const char *, int, const char *, int);
+
+/* draw.c */
+void draw(const char *, int, int, int, int, int, int, int, int, int, int, int,
+          int, struct Categories, struct Colors, double, double, double,
+          double, int, int, double, double, double *, int, int, int, double,
+          double, const char *, double *, double, int, int, struct Option *,
+          struct Option *, struct Option *, struct Option *, struct Option *,
+          struct Flag *, struct Flag *, int, int, int, char *);

Modified: grass/branches/releasebranch_7_2/display/d.legend/main.c
===================================================================
--- grass/branches/releasebranch_7_2/display/d.legend/main.c	2016-07-27 11:18:55 UTC (rev 69036)
+++ grass/branches/releasebranch_7_2/display/d.legend/main.c	2016-07-27 18:05:07 UTC (rev 69037)
@@ -15,6 +15,8 @@
  *         Markus Neteler
  *      Late 2002: Rewrite of much of the code:
  *         Hamish Bowman, Otago University, New Zealand
+ *      Improvements (ticks, more label options, title):
+ *         Adam Laza (part of GSoC 2016)
  *
  * COPYRIGHT:   (c) 2002-2014 by The GRASS Development Team
  *
@@ -37,47 +39,38 @@
 
 int main(int argc, char **argv)
 {
-    char buff[512];
     char *map_name;
     int maptype;
-    int black, white, color;
-    int cats_num;
-    int cur_dot_row;
-    int do_cats;
-    int dots_per_line;
-    int i, j, k;
+    int color;
+    int i;
     int thin, lines, steps;
     int fp;
-    double t, b, l, r;
-    int hide_catnum, hide_catstr, hide_nodata, do_smooth;
-    char *cstr;
-    double x_box[5], y_box[5];
+    int label_indent;
+    int hide_catnum, hide_catstr, show_ticks, show_bg, hide_nodata, do_smooth;
     struct Categories cats;
     struct Colors colors;
     struct GModule *module;
     struct Option *opt_rast2d, *opt_rast3d, *opt_color, *opt_lines,
-		  *opt_thin, *opt_labelnum, *opt_at, *opt_use, *opt_range,
-		  *opt_font, *opt_path, *opt_charset, *opt_fontsize;
-    struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *flipit, *histo;
-    struct Range range;
-    struct FPRange fprange, render_range;
-    CELL min_ind, max_ind;
-    DCELL dmin, dmax, val;
-    CELL min_colr, max_colr;
-    DCELL min_dcolr, max_dcolr;
-    int x0, x1, y0, y1, xyTemp;
+        *opt_thin, *opt_labelnum, *opt_at, *opt_use, *opt_range,
+        *opt_font, *opt_path, *opt_charset, *opt_fontsize, *opt_title,
+        *opt_ticks, *opt_tstep, *opt_brdcolor, *opt_bgcolor,
+        *opt_tit_fontsize, *opt_digits, *opt_units;
+    struct Flag *hidestr, *hidenum, *hidenodata, *smooth, *flipit, *histo,
+        *showtick, *showbg, *log_sc;
     double X0, X1, Y0, Y1;
-    int SigDigits;
-    unsigned int MaxLabelLen;
-    char DispFormat[5];		/*  %.Xf\0  */
-    int flip, horiz, UserRange;
+    int flip, UserRange;
     double UserRangeMin, UserRangeMax, UserRangeTemp;
-    double *catlist, maxCat;
-    int catlistCount, use_catlist;
+    double *catlist;
+    int catlistCount, use_catlist, ticksCount;
     double fontsize;
+    char *title;
     char *units;
+    double *tick_values;
+    double t_step;
+    int colorb, colorbg;
+    double tit_fontsize;
+    int log_scale, digits;
 
-
     /* Initialize the GIS calls */
     G_gisinit(argv[0]);
 
@@ -86,8 +79,8 @@
     G_add_keyword(_("cartography"));
     G_add_keyword(_("legend"));
     module->description =
-	_("Displays a legend for a 2D or 3D raster map in the active frame "
-	  "of the graphics monitor.");
+        _("Displays a legend for a 2D or 3D raster map in the active frame "
+          "of the graphics monitor.");
 
     opt_rast2d = G_define_standard_option(G_OPT_R_MAP);
     opt_rast2d->key = "raster";
@@ -99,13 +92,29 @@
     opt_rast3d->required = NO;
     opt_rast3d->guisection = _("Input");
 
+    opt_title = G_define_option();
+    opt_title->key = "title";
+    opt_title->type = TYPE_STRING;
+    opt_title->required = NO;
+    opt_title->description = _("Legend title");
+    opt_title->guisection = _("Title");
+
+    opt_tit_fontsize = G_define_option();
+    opt_tit_fontsize->key = "title_fontsize";
+    opt_tit_fontsize->type = TYPE_DOUBLE;
+    opt_tit_fontsize->required = NO;
+    opt_tit_fontsize->options = "1-360";
+    opt_tit_fontsize->label = _("Title font size");
+    opt_tit_fontsize->description = _("Default: Same as fontsize");
+    opt_tit_fontsize->guisection = _("Title");
+
     opt_lines = G_define_option();
     opt_lines->key = "lines";
     opt_lines->type = TYPE_INTEGER;
     opt_lines->answer = "0";
     opt_lines->options = "0-1000";
     opt_lines->description =
-	_("Number of text lines (useful for truncating long legends)");
+        _("Number of text lines (useful for truncating long legends)");
     opt_lines->guisection = _("Advanced");
 
     opt_thin = G_define_option();
@@ -115,46 +124,79 @@
     opt_thin->answer = "1";
     opt_thin->options = "1-1000";
     opt_thin->description =
-	_("Thinning factor (thin=10 gives cats 0,10,20...)");
+        _("Thinning factor (thin=10 gives cats 0,10,20...)");
     opt_thin->guisection = _("Advanced");
 
+    opt_units = G_define_option();
+    opt_units->key = "units";
+    opt_units->type = TYPE_STRING;
+    opt_units->required = NO;
+    opt_units->description =
+            _("Units to display after labels (e.g. meters)");
+    opt_units->guisection = _("Advanced");
+
     opt_labelnum = G_define_option();
     opt_labelnum->key = "labelnum";
     opt_labelnum->type = TYPE_INTEGER;
     opt_labelnum->answer = "5";
     opt_labelnum->options = "2-100";
     opt_labelnum->description =
-	_("Number of text labels for smooth gradient legend");
+        _("Number of text labels for smooth gradient legend");
     opt_labelnum->guisection = _("Gradient");
 
+    opt_ticks = G_define_option();
+    opt_ticks->key = "label_values";
+    opt_ticks->type = TYPE_DOUBLE;
+    opt_ticks->required = NO;
+    opt_ticks->description = _("Specific values to draw ticks");
+    opt_ticks->required = NO;
+    opt_ticks->multiple = YES;
+    opt_ticks->guisection = _("Gradient");
+
+    opt_tstep = G_define_option();
+    opt_tstep->key = "label_step";
+    opt_tstep->type = TYPE_DOUBLE;
+    opt_tstep->required = NO;
+    opt_tstep->description = _("Display label every step");
+    opt_tstep->guisection = _("Gradient");
+
+    opt_digits = G_define_option();
+    opt_digits->key = "digits";
+    opt_digits->type = TYPE_INTEGER;
+    opt_digits->required = NO;
+    opt_digits->description = _("Number of digits after decimal point");
+    opt_digits->guisection = _("Advanced");
+    opt_digits->answer = NULL;
+    opt_digits->options = "0-6";
+
     opt_at = G_define_option();
     opt_at->key = "at";
     opt_at->key_desc = "bottom,top,left,right";
-    opt_at->type = TYPE_DOUBLE;  /* needs to be TYPE_DOUBLE to get past options check */
+    opt_at->type = TYPE_DOUBLE; /* needs to be TYPE_DOUBLE to get past options check */
     opt_at->required = NO;
     opt_at->options = "0-100";
     opt_at->label =
-	_("Size and placement as percentage of screen coordinates "
-	  "(0,0 is lower left)");
+        _("Size and placement as percentage of screen coordinates "
+          "(0,0 is lower left)");
     opt_at->description = opt_at->key_desc;
     opt_at->answer = NULL;
 
     opt_use = G_define_option();
     opt_use->key = "use";
-    opt_use->type = TYPE_DOUBLE;  /* string as it is fed through the parser? */
+    opt_use->type = TYPE_DOUBLE;        /* string as it is fed through the parser? */
     opt_use->required = NO;
     opt_use->description =
-	_("List of discrete category numbers/values for legend");
+        _("List of discrete category numbers/values for legend");
     opt_use->multiple = YES;
     opt_use->guisection = _("Subset");
 
     opt_range = G_define_option();
     opt_range->key = "range";
     opt_range->key_desc = "min,max";
-    opt_range->type = TYPE_DOUBLE;  /* should it be type_double or _string ?? */
+    opt_range->type = TYPE_DOUBLE;      /* should it be type_double or _string ?? */
     opt_range->required = NO;
     opt_range->description =
-	_("Use a subset of the map range for the legend (min,max)");
+        _("Use a subset of the map range for the legend (min,max)");
     opt_range->guisection = _("Subset");
 
     opt_color = G_define_standard_option(G_OPT_C);
@@ -189,9 +231,22 @@
     opt_charset->type = TYPE_STRING;
     opt_charset->required = NO;
     opt_charset->description =
-	_("Text encoding (only applicable to TrueType fonts)");
+        _("Text encoding (only applicable to TrueType fonts)");
     opt_charset->guisection = _("Font settings");
 
+    opt_brdcolor = G_define_standard_option(G_OPT_CN);
+    opt_brdcolor->key = "border_color";
+    opt_brdcolor->answer = "black";
+    opt_brdcolor->label = _("Border color");
+    opt_brdcolor->guisection = _("Background");
+
+    opt_bgcolor = G_define_standard_option(G_OPT_CN);
+    opt_bgcolor->key = "bgcolor";
+    opt_bgcolor->answer = "white";
+    opt_bgcolor->label = _("Background color");
+    opt_bgcolor->guisection = _("Background");
+
+
     hidestr = G_define_flag();
     hidestr->key = 'v';
     hidestr->description = _("Do not show category labels");
@@ -202,6 +257,11 @@
     hidenum->description = _("Do not show category numbers");
     hidenum->guisection = _("Advanced");
 
+    showtick = G_define_flag();
+    showtick->key = 't';
+    showtick->description = _("Draw legend ticks for labels");
+    showtick->guisection = _("Gradient");
+
     hidenodata = G_define_flag();
     hidenodata->key = 'n';
     hidenodata->description = _("Skip categories with no label");
@@ -222,835 +282,210 @@
     histo->description = _("Add histogram to smoothed legend");
     histo->guisection = _("Gradient");
 
+    showbg = G_define_flag();
+    showbg->key = 'b';
+    showbg->description = _("Show background");
+    showbg->guisection = _("Background");
 
+    log_sc = G_define_flag();
+    log_sc->key = 'l';
+    log_sc->description = _("Use logarithmic scale");
+    log_sc->guisection = _("Advanced");
+
+    G_option_required(opt_rast2d, opt_rast3d, NULL);
+    G_option_exclusive(opt_rast2d, opt_rast3d, NULL);
+    G_option_exclusive(hidenum, opt_ticks, NULL);
+    G_option_exclusive(hidenum, opt_tstep, NULL);
+
     /* Check command line */
     if (G_parser(argc, argv))
-	exit(EXIT_FAILURE);
+        exit(EXIT_FAILURE);
 
-    /* FIXME: add GUI launching logic to G_parser() call */
-    if ((opt_rast2d->answer && opt_rast3d->answer) ||
-        !(opt_rast2d->answer || opt_rast3d->answer))
-	G_fatal_error(_("Please specify a single map name. To launch GUI use d.legend --ui."));
-
     if (opt_rast2d->answer) {
-	map_name = opt_rast2d->answer;
-	maptype = MAP_TYPE_RASTER2D;
+        map_name = opt_rast2d->answer;
+        maptype = MAP_TYPE_RASTER2D;
     }
     else {
-	map_name = opt_rast3d->answer;
-	maptype = MAP_TYPE_RASTER3D;
+        map_name = opt_rast3d->answer;
+        maptype = MAP_TYPE_RASTER3D;
     }
 
-    hide_catstr = hidestr->answer;	/* note hide_catstr gets changed and re-read below */
+    if (opt_title->answer)
+        title = opt_title->answer;
+    else
+        title = "";
+
+    if (opt_units->answer) {
+        units = opt_units->answer;
+    }
+    else
+        units = "";
+
+    hide_catstr = hidestr->answer;      /* note hide_catstr gets changed and re-read below */
     hide_catnum = hidenum->answer;
+    show_ticks = showtick->answer;
     hide_nodata = hidenodata->answer;
     do_smooth = smooth->answer;
     flip = flipit->answer;
+    show_bg = showbg->answer;
+    log_scale = log_sc->answer;
 
+    if (showtick->answer) {
+        label_indent = 12;
+    }
+    else
+        label_indent = 6;
+
+    if (opt_digits->answer != NULL)
+        sscanf(opt_digits->answer, "%d", &digits);
+    else
+        digits = -1;
+
     color = D_parse_color(opt_color->answer, TRUE);
 
     if (opt_lines->answer != NULL)
-	sscanf(opt_lines->answer, "%d", &lines);
+        sscanf(opt_lines->answer, "%d", &lines);
 
     thin = 1;
     if (opt_thin->answer != NULL)
-	sscanf(opt_thin->answer, "%d", &thin);
+        sscanf(opt_thin->answer, "%d", &thin);
     if (!thin)
-	thin = 1;
+        thin = 1;
 
     if (opt_labelnum->answer != NULL)
-	sscanf(opt_labelnum->answer, "%d", &steps);
+        sscanf(opt_labelnum->answer, "%d", &steps);
 
+    if ((opt_tstep->answer) || (opt_ticks->answer))
+        steps = 0;
+
+    if (opt_tstep->answer != NULL)
+        t_step = atof(opt_tstep->answer);
+
+    ticksCount = 0;
+    if (opt_ticks->answer != NULL) {
+        tick_values = (double *)G_calloc(100 + 1, sizeof(double));
+        for (i = 0; i < 100; i++)       /* fill with dummy values */
+            tick_values[i] = 1.0 * (i + 1);
+        tick_values[i] = 0;
+
+        for (i = 0; (opt_ticks->answers[i] != NULL) && i < 100; i++)
+            tick_values[i] = atof(opt_ticks->answers[i]);
+        ticksCount = i;
+    }
+
     catlistCount = 0;
-    if (opt_use->answer != NULL) {	/* should this be answerS ? */
-	use_catlist = TRUE;
+    if (opt_use->answer != NULL) {      /* should this be answerS ? */
+        use_catlist = TRUE;
 
-	catlist = (double *)G_calloc(100 + 1, sizeof(double));
-	for (i = 0; i < 100; i++)	/* fill with dummy values */
-	    catlist[i] = 1.0 * (i + 1);
-	catlist[i] = 0;
+        catlist = (double *)G_calloc(100 + 1, sizeof(double));
+        for (i = 0; i < 100; i++)       /* fill with dummy values */
+            catlist[i] = 1.0 * (i + 1);
+        catlist[i] = 0;
 
-	for (i = 0; (opt_use->answers[i] != NULL) && i < 100; i++)
-	    catlist[i] = atof(opt_use->answers[i]);
+        for (i = 0; (opt_use->answers[i] != NULL) && i < 100; i++)
+            catlist[i] = atof(opt_use->answers[i]);
 
-	catlistCount = i;
+        catlistCount = i;
     }
     else
-	use_catlist = FALSE;
+        use_catlist = FALSE;
 
 
     UserRange = FALSE;
-    if (opt_range->answer != NULL) {	/* should this be answerS ? */
-	sscanf(opt_range->answers[0], "%lf", &UserRangeMin);
-	sscanf(opt_range->answers[1], "%lf", &UserRangeMax);
-	UserRange = TRUE;
-	if (UserRangeMin > UserRangeMax) {
-	    UserRangeTemp = UserRangeMax;
-	    UserRangeMax = UserRangeMin;
-	    UserRangeMin = UserRangeTemp;
-	    flip = !flip;
-	}
+    if (opt_range->answer != NULL) {    /* should this be answerS ? */
+        sscanf(opt_range->answers[0], "%lf", &UserRangeMin);
+        sscanf(opt_range->answers[1], "%lf", &UserRangeMax);
+        UserRange = TRUE;
+        if (UserRangeMin > UserRangeMax) {
+            UserRangeTemp = UserRangeMax;
+            UserRangeMax = UserRangeMin;
+            UserRangeMin = UserRangeTemp;
+            flip = !flip;
+        }
     }
 
     if (maptype == MAP_TYPE_RASTER2D) {
-	if (Rast_read_colors(map_name, "", &colors) == -1)
-	    G_fatal_error(_("Color file for <%s> not available"), map_name);
+        if (Rast_read_colors(map_name, "", &colors) == -1)
+            G_fatal_error(_("Color file for <%s> not available"), map_name);
 
-	fp = Rast_map_is_fp(map_name, "");
- 
-	Rast_read_cats(map_name, "", &cats);
+        fp = Rast_map_is_fp(map_name, "");
+
+        Rast_read_cats(map_name, "", &cats);
     }
     else {
-	if (Rast3d_read_colors(map_name, "", &colors) == -1)
-	    G_fatal_error(_("Color file for <%s> not available"), map_name);
+        if (Rast3d_read_colors(map_name, "", &colors) == -1)
+            G_fatal_error(_("Color file for <%s> not available"), map_name);
 
-	fp = TRUE;  /* currently raster 3D is always floating point */
+        fp = TRUE;              /* currently raster 3D is always floating point */
 
-	Rast3d_read_cats(map_name, "", &cats);
+        Rast3d_read_cats(map_name, "", &cats);
     }
 
     if (fp && !use_catlist) {
-	do_smooth = TRUE;
-	/* fprintf(stderr, "FP map found - switching gradient legend on\n"); */
-	flip = !flip;
+        do_smooth = TRUE;
+        /* fprintf(stderr, "FP map found - switching gradient legend on\n"); */
+        flip = !flip;
     }
 
     D_open_driver();
 
-    white = D_translate_color(DEFAULT_FG_COLOR);
-    black = D_translate_color(DEFAULT_BG_COLOR);
+    /* Parse and select background color */
+    colorb = D_parse_color(opt_brdcolor->answer, TRUE);
+    colorbg = D_parse_color(opt_bgcolor->answer, TRUE);
 
     if (opt_font->answer)
-	D_font(opt_font->answer);
+        D_font(opt_font->answer);
     else if (opt_path->answer)
-	D_font(opt_path->answer);
+        D_font(opt_path->answer);
 
     if (opt_fontsize->answer != NULL)
-	fontsize = atof(opt_fontsize->answer);
+        fontsize = atof(opt_fontsize->answer);
     else
-	fontsize = 12; /* dummy placeholder, should never be called */
+        fontsize = 12;          /* dummy placeholder, should never be called */
 
     if (opt_charset->answer)
-	D_encoding(opt_charset->answer);
+        D_encoding(opt_charset->answer);
 
-    /* Figure out where to put text */
-    D_setup_unity(0);
-    D_get_src(&t, &b, &l, &r);
+    if (opt_tit_fontsize->answer != NULL)
+        tit_fontsize = atof(opt_tit_fontsize->answer);
+    else
+        tit_fontsize = 0;
 
     if (opt_at->answer != NULL) {
-	sscanf(opt_at->answers[0], "%lf", &Y1);
-	sscanf(opt_at->answers[1], "%lf", &Y0);
-	sscanf(opt_at->answers[2], "%lf", &X0);
-	sscanf(opt_at->answers[3], "%lf", &X1);
+        sscanf(opt_at->answers[0], "%lf", &Y1);
+        sscanf(opt_at->answers[1], "%lf", &Y0);
+        sscanf(opt_at->answers[2], "%lf", &X0);
+        sscanf(opt_at->answers[3], "%lf", &X1);
     }
-    else {			/* default */
-	Y1 = 12;
-	Y0 = 88;
-	X0 = 3;
-	X1 = 7;
+    else {                      /* default */
+        Y1 = 12;
+        Y0 = 88;
+        X0 = 3;
+        X1 = 7;
 
-	if (histo->answer) {
-	    X0 += 5;
-	    X1 += 5;
-	}
+        if (histo->answer) {
+            X0 += 5;
+            X1 += 5;
+        }
     }
 
-    x0 = l + (int)((r - l) * X0 / 100.);
-    x1 = l + (int)((r - l) * X1 / 100.);
-    y0 = t + (int)((b - t) * (100. - Y0) / 100.);  /* make lower left the origin */
-    y1 = t + (int)((b - t) * (100. - Y1) / 100.);
+    if (show_bg)
+        draw(map_name, maptype, color, thin, lines, steps, fp, label_indent,
+             hide_catnum, hide_catstr, show_ticks, hide_nodata, do_smooth,
+             cats, colors, X0, X1, Y0, Y1, flip, UserRange, UserRangeMin,
+             UserRangeMax, catlist, catlistCount, use_catlist, ticksCount,
+             fontsize, tit_fontsize, title, tick_values, t_step, colorb,
+             colorbg, opt_use, opt_at, opt_fontsize, opt_tstep,
+             opt_range, histo, hidestr, log_scale, 0, digits, units);
 
-    if (y0 > y1) {		/* allow for variety in order of corner */
-	flip = !flip;		/*   selection without broken output    */
-	xyTemp = y0;
-	y0 = y1;
-	y1 = xyTemp;
-    }
-    if (x0 > x1) {
-	xyTemp = x0;
-	x0 = x1;
-	x1 = xyTemp;
-    }
+    draw(map_name, maptype, color, thin, lines, steps, fp, label_indent,
+         hide_catnum, hide_catstr, show_ticks, hide_nodata, do_smooth, cats,
+         colors, X0, X1, Y0, Y1, flip, UserRange, UserRangeMin, UserRangeMax,
+         catlist, catlistCount, use_catlist, ticksCount, fontsize,
+         tit_fontsize, title, tick_values, t_step, colorb, colorbg, opt_use,
+         opt_at, opt_fontsize, opt_tstep, opt_range, histo,
+         hidestr, log_scale, 1, digits, units);
 
-    if (x0 == x1)
-	x1++;			/* avoid 0 width boxes */
-    if (y0 == y1)
-	y1++;
-
-    if ((x0 < l) || (x1 > r) || (y0 < t) || (y1 > b))	/* for mouse or at= 0- or 100+; needs to be after order check */
-	G_warning(_("Legend box lies outside of frame. Text may not display properly."));
-
-    horiz = (x1 - x0 > y1 - y0);
-    if (horiz)
-	G_message(_("Drawing horizontal legend as box width exceeds height"));
-
-    if (!fp && horiz)		/* better than nothing */
-	do_smooth = TRUE;
-
-
-    MaxLabelLen = 0;		/* init variable */
-
-    /* How many categories to show */
-    if (!fp) {
-	if (Rast_read_range(map_name, "", &range) == -1)
-	    G_fatal_error(_("Range information for <%s> not available (run r.support)"),
-			  map_name);
-
-	Rast_get_range_min_max(&range, &min_ind, &max_ind);
-	if (Rast_is_c_null_value(&min_ind))
-	    G_fatal_error(_("Input map contains no data"));
-
-	Rast_get_c_color_range(&min_colr, &max_colr, &colors);
-
-	if (UserRange) {
-	    if (min_ind < UserRangeMin)
-		min_ind = (int)ceil(UserRangeMin);
-	    if (max_ind > UserRangeMax)
-		max_ind = (int)floor(UserRangeMax);
-	    if (min_ind > UserRangeMin) {
-		min_ind =
-		    UserRangeMin <
-		    min_colr ? min_colr : (int)ceil(UserRangeMin);
-		G_warning(_("Requested range exceeds lower limit of actual data"));
-	    }
-	    if (max_ind < UserRangeMax) {
-		max_ind =
-		    UserRangeMax >
-		    max_colr ? max_colr : (int)floor(UserRangeMax);
-		G_warning(_("Requested range exceeds upper limit of actual data"));
-	    }
-	}
-
-	/*  cats_num is total number of categories in raster                  */
-	/*  do_cats is  total number of categories to be displayed            */
-	/*  k is number of cats to be displayed after skipping unlabeled cats */
-	/*  lines is number of text lines/legend window                       */
-
-	cats_num = max_ind - min_ind + 1;
-
-	if (lines == 0)
-	    lines = cats_num;
-
-	do_cats = cats_num > lines ? lines : cats_num;
-
-	if (do_cats == cats_num)
-	    lines = (int)ceil((1.0 * lines) / thin);
-
-	if (!use_catlist) {
-	    catlist = (double *)G_calloc(lines + 1, sizeof(double));
-	    catlistCount = lines;
-	}
-	/* see how many boxes there REALLY will be */
-	maxCat = 0.0;
-	for (i = min_ind, j = 1, k = 0; j <= do_cats && i <= max_ind;
-	     j++, i += thin) {
-	    if (!flip)
-		cstr = Rast_get_c_cat(&i, &cats);
-	    else {
-		CELL cat = max_ind - (i - min_ind);
-		cstr = Rast_get_c_cat(&cat, &cats);
-	    }
-
-	    if (!use_catlist)
-		catlist[j - 1] = (double)i;
-
-	    if (!cstr[0]) {	/* no cat label found, skip str output */
-		if (hide_nodata)
-		    continue;
-	    }
-	    else {		/* ie has a label */
-		if (!hide_catstr && (MaxLabelLen < strlen(cstr)))
-		    MaxLabelLen = strlen(cstr);
-	    }
-
-	    if (!hide_catnum)
-		if (i > maxCat)
-		    maxCat = (double)i;
-	    k++;	/* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
-	}
-	lines = k;
-
-	/* figure out how long the category + label will be */
-	if (use_catlist) {
-	    MaxLabelLen = 0;
-	    maxCat = 0;		/* reset */
-	    for (i = 0, k = 0; i < catlistCount; i++) {
-		if ((catlist[i] < min_ind) || (catlist[i] > max_ind)) {
-		    G_fatal_error(_("use=%s out of range [%d,%d] (extend with range= ?)"),
-				  opt_use->answers[i], min_ind, max_ind);
-		}
-
-		cstr = Rast_get_d_cat(&catlist[i], &cats);
-		if (!cstr[0]) {	/* no cat label found, skip str output */
-		    if (hide_nodata)
-			continue;
-		}
-		else {		/* ie has a label */
-		    if (!hide_catstr && (MaxLabelLen < strlen(cstr)))
-			MaxLabelLen = strlen(cstr);
-		}
-		if (!hide_catnum)
-		    if (catlist[i] > maxCat)
-			maxCat = catlist[i];
-		k++;
-	    }
-	    if (0 == k)		/* nothing to draw */
-		lines = 0;
-	}
-
-	if (MaxLabelLen > 0) {	/* ie we've picked up at least one label */
-	    MaxLabelLen++;	/* compensate for leading space */
-	    if (!hide_catnum)
-		MaxLabelLen += 3;	/* compensate for "%2d) " */
-	}
-	else {
-	    if (!hide_catnum)
-		MaxLabelLen = 1;
-	}
-
-	/* compensate for categories >100 */
-	if (!hide_catnum) {
-	    if (maxCat > 99)
-		MaxLabelLen += (int)(log10(maxCat));
-	}
-
-	/* following covers both the above if(do_cats == cats_num) and k++ loop */
-	if (lines < 1) {
-	    lines = 1;		/* ward off the dpl floating point exception */
-	    G_fatal_error(_("Nothing to draw! (no categories with labels? out of range?)"));
-	}
-
-	/* Figure number of lines, number of pixles per line and text size */
-	dots_per_line = ((y1 - y0) / lines);
-
-	/* switch to a smooth legend for CELL maps with too many cats */
-	/*  an alternate solution is to set   dots_per_line=1         */
-	if ((dots_per_line == 0) && (do_smooth == FALSE)) {
-	    if (!use_catlist) {
-		G_message(_("Forcing a smooth legend: too many categories for current window height"));
-		do_smooth = TRUE;
-	    }
-	}
-
-	/* center really tiny legends */
-	if (opt_at->answer == NULL) {	/* if defualt scaling */
-	    if (!do_smooth && (dots_per_line < 4))	/* if so small that there's no box */
-		if ((b - (dots_per_line * lines)) / (b * 1.0) > 0.15)	/* if there's more than a 15% blank at the bottom */
-		    y0 = ((b - t) - (dots_per_line * lines)) / 2;
-	}
-
-	/* D_text_size(dots_per_line*4/5., dots_per_line*4/5.);    redundant */
-	/* if(Rast_is_c_null_value(&min_ind) && Rast_is_c_null_value(&max_ind))
-	   {
-	   min_ind = 1;
-	   max_ind = 0;
-	   } */
-
-	if (horiz)
-	    sprintf(DispFormat, "%%d");
-	else {
-	    if (maxCat > 0.0)
-		sprintf(DispFormat, "%%%dd", (int)(log10(fabs(maxCat))) + 1);
-	    else
-		sprintf(DispFormat, "%%2d");
-	}
-    }
-    else {	/* is fp */
-	if (maptype == MAP_TYPE_RASTER2D) {
-	    if (Rast_read_fp_range(map_name, "", &fprange) == -1)
-		G_fatal_error(_("Range information for <%s> not available"),
-				map_name);
-	}
-	else {
-	    if (Rast3d_read_range(map_name, "", &fprange) == -1)
-		G_fatal_error(_("Range information for <%s> not available"),
-				map_name);
-	}
-
-	Rast_get_fp_range_min_max(&fprange, &dmin, &dmax);
-	Rast_get_d_color_range(&min_dcolr, &max_dcolr, &colors);
-
-	if (UserRange) {
-	    if (dmin < UserRangeMin)
-		dmin = UserRangeMin;
-	    if (dmax > UserRangeMax)
-		dmax = UserRangeMax;
-	    if (dmin > UserRangeMin) {
-		dmin = UserRangeMin < min_dcolr ? min_dcolr : UserRangeMin;
-		G_warning(_("Color range exceeds lower limit of actual data"));
-	    }
-	    if (dmax < UserRangeMax) {
-		dmax = UserRangeMax > max_dcolr ? max_dcolr : UserRangeMax;
-		G_warning(_("Color range exceeds upper limit of actual data"));
-	    }
-	}
-
-	if (use_catlist) {
-	    for (i = 0; i < catlistCount; i++) {
-		if ((catlist[i] < dmin) || (catlist[i] > dmax)) {
-		    G_fatal_error(_("use=%s out of range [%.3f, %.3f] (extend with range= ?)"),
-				  opt_use->answers[i], dmin, dmax);
-		}
-		if (strlen(opt_use->answers[i]) > MaxLabelLen)
-		    MaxLabelLen = strlen(opt_use->answers[i]);
-	    }
-	}
-	do_cats = 0;		/* if only to get rid of the compiler warning  */
-	cats_num = 0;		/* if only to get rid of the compiler warning  */
-	/* determine how many significant digits to display based on range */
-	if (0 == (dmax - dmin))	/* trap divide by 0 for single value rasters */
-	    sprintf(DispFormat, "%%f");
-	else {
-	    SigDigits = (int)ceil(log10(fabs(25 / (dmax - dmin))));
-	    if (SigDigits < 0)
-		SigDigits = 0;
-	    if (SigDigits < 7)
-		sprintf(DispFormat, "%%.%df", SigDigits);
-	    else
-		sprintf(DispFormat, "%%.2g");	/* eg 4.2e-9  */
-	}
-    }
-
-    if (use_catlist) {
-	cats_num = catlistCount;
-	do_cats = catlistCount;
-	lines = catlistCount;
-	do_smooth = FALSE;
-    }
-
-
-    if (do_smooth) {
-	int wleg, lleg, dx, dy;
-	double txsiz;
-	int ppl;
-	int tcell;
-	float ScaleFactor = 1.0;
-
-	if (horiz) {
-	    lleg = x1 - x0;
-	    dx = 0;
-	    dy = y1 - y0;
-	    if (fp)
-		flip = !flip;	/* horiz floats look better not flipped by default */
-	}
-	else {
-	    lleg = y1 - y0;
-	    dy = 0;
-	    dx = x1 - x0;
-	}
-
-	/* Draw colors */
-	for (k = 0; k < lleg; k++) {
-	    if (!fp) {
-		if (!flip)
-		    tcell =
-			min_ind + k * (double)(1 + max_ind - min_ind) / lleg;
-		else
-		    tcell =
-			(max_ind + 1) - k * (double)(1 + max_ind -
-						     min_ind) / lleg;
-		D_color((CELL) tcell, &colors);
-	    }
-	    else {
-		if (!flip)
-		    val = dmin + k * (dmax - dmin) / lleg;
-		else
-		    val = dmax - k * (dmax - dmin) / lleg;
-		D_d_color(val, &colors);
-	    }
-
-	    if (dx < dy)
-		D_box_abs(x0 + k, y0, x0 + k + (dx ? -dx : 1),
-			  y0 - (dy ? -dy : 1));
-	    else
-		D_box_abs(x0, y0 + k, x0 - (dx ? -dx : 1),
-			  y0 + k + (dy ? -dy : 1));
-	}
-
-	/* Format text */
-	if (!fp) {		/* cut down labelnum so they don't repeat */
-	    if (do_cats < steps)
-		steps = do_cats;
-	    if (1 == steps)
-		steps = 2;	/* ward off the ppl floating point exception */
-	}
-
-	for (k = 0; k < steps; k++) {
-	    if (!fp) {
-		if (!flip)
-		    tcell =
-			min_ind + k * (double)(max_ind - min_ind) / (steps -
-								     1);
-		else
-		    tcell =
-			max_ind - k * (double)(max_ind - min_ind) / (steps -
-								     1);
-
-		cstr = Rast_get_c_cat(&tcell, &cats);
-
-		if (!cstr[0])	/* no cats found, disable str output */
-		    hide_catstr = 1;
-		else
-		    hide_catstr = hidestr->answer;
-
-		buff[0] = 0;	/* blank string */
-
-		if (!hide_catnum) {	/* num */
-		    sprintf(buff, DispFormat, tcell);
-		    if (!hide_catstr)	/* both */
-			strcat(buff, ")");
-		}
-		if (!hide_catstr)	/* str */
-		    sprintf(buff + strlen(buff), " %s", cstr);
-	    }
-	    else {		/* ie FP map */
-		if (hide_catnum)
-		    buff[0] = 0;	/* no text */
-		else {
-		    if (!flip)
-			val = dmin + k * (dmax - dmin) / (steps - 1);
-		    else
-			val = dmax - k * (dmax - dmin) / (steps - 1);
-
-		    sprintf(buff, DispFormat, val);
-		}
-	    }
-
-	    /* this probably shouldn't happen mid-loop as text sizes
-	       might not end up being uniform, but it's a start */
-	    if (strlen(buff) > MaxLabelLen)
-		MaxLabelLen = strlen(buff);
-
-	    /* Draw text */
-	    if (!horiz)
-		txsiz = (y1 - y0) / 20;
-	    else
-		txsiz = (x1 - x0) / 20;
-
-	    /* scale text to fit in window if position not manually set */
-	    /* usually not needed, except when frame is really narrow   */
-	    if (opt_at->answer == NULL) {	/* ie default scaling */
-		ScaleFactor = ((r - x1) / ((MaxLabelLen + 1) * txsiz * 0.81));	/* ?? txsiz*.81=actual text width. */
-		if (ScaleFactor < 1.0) {
-		    txsiz = txsiz * ScaleFactor;
-		}
-	    }
-
-	    if (opt_fontsize->answer != NULL)
-		txsiz = fontsize;
-
-	    if (txsiz < 0)
-		txsiz = 0;	/* keep it sane */
-
-	    D_text_size(txsiz, txsiz);
-	    D_use_color(color);
-
-	    ppl = (lleg) / (steps - 1);
-
-	    if (!horiz) {
-		if (!k)		/* first  */
-		    D_pos_abs(x1 + 4, y0 + txsiz);
-		else if (k == steps - 1)	/* last */
-		    D_pos_abs(x1 + 4, y1);
-		else
-		    D_pos_abs(x1 + 4, y0 + ppl * k + txsiz / 2);
-	    }
-	    else {
-		/* text width is 0.81 of text height? so even though we set width
-		   to txsiz with D_text_size(), we still have to reduce.. hmmm */
-		if (!k)		/* first  */
-		    D_pos_abs(x0 - (strlen(buff) * txsiz * .81 / 2),
-			      y1 + 4 + txsiz);
-		else if (k == steps - 1)	/* last */
-		    D_pos_abs(x1 - (strlen(buff) * txsiz * .81 / 2),
-			      y1 + 4 + txsiz);
-		else
-		    D_pos_abs(x0 + ppl * k -
-			      (strlen(buff) * txsiz * .81 / 2),
-			      y1 + 4 + txsiz);
-	    }
-
-	    if (color)
-		D_text(buff);
-
-	}	/* for */
-
-	lleg = y1 - y0;
-	wleg = x1 - x0;
-
-	/* Black box */
-	D_use_color(black);
-	D_begin();
-	D_move_abs(x0 + 1, y0 + 1);
-	D_cont_rel(0, lleg - 2);
-	D_cont_rel(wleg - 2, 0);
-	D_cont_rel(0, 2 - lleg);
-	D_close();
-	D_end();
-	D_stroke();
-
-	/* White box */
-	D_use_color(white);
-	D_begin();
-	D_move_abs(x0, y0);
-	D_cont_rel(0, lleg);
-	D_cont_rel(wleg, 0);
-	D_cont_rel(0, -lleg);
-	D_close();
-	D_end();
-	D_stroke();
-
-
-	/* print units label, if present */
-	if (maptype == MAP_TYPE_RASTER2D)
-	    units = Rast_read_units(map_name, "");
-	else
-	    units = "";
-/* FIXME: does the raster3d really need to be opened to read the units?
-	    units = Rast3d_get_unit(map_fid); */
-
-	if (!units)
-	    units = "";
-
-	if(strlen(units)) {
-	    double x_pos, y_pos;
-	    int default_pos = TRUE;
-
-	    D_use_color(color);
-	    /* D_text_size() should be already set */
-
-	    if (horiz) {
-		x_pos = (x0 + x1)/2. - (strlen(units) * txsiz * 0.81)/2;
-		y_pos = y1 + (txsiz * 3);
-	    }
-	    else {
-		x_pos = x1 - 4;
-		if (default_pos)
-		    y_pos = y0 - (txsiz * 1.75);
-		else
-		    y_pos = y1 + (txsiz * 2.75);
-	    }
-
-	    D_pos_abs(x_pos, y_pos);
-	    D_text(units);
-	}
-
-
-	/* display sidebar histogram, if requested */
-	if (histo->answer) {
-
-	    render_range.min = (DCELL)(fp ? dmin : min_ind);
-	    render_range.max = (DCELL)(fp ? dmax : max_ind);
-	    /* reuse flag to indicate if user-specified or default ranging */
-	    render_range.first_time = opt_range->answer ? TRUE : FALSE;
-
-	    draw_histogram(map_name, x0, y0, wleg, lleg, color, flip, horiz,
-			   maptype, fp, render_range);
-	}
-
-    }
-    else {	/* non FP, no smoothing */
-
-	int true_l, true_r;
-	double txsiz;
-	float ScaleFactor = 1.0;
-
-	if (histo->answer)
-	    G_warning(_("Histogram plotting not implemented for categorical legends. "
-			"Use the '-s' flag"));
-
-	/* set legend box bounds */
-	true_l = l;
-	true_r = r;	/* preserve window width */
-	l = x0;
-	t = y0;
-	r = x1;
-	b = y1;
-
-	D_pos_abs(x0, y0);
-
-	/* figure out box height  */
-	if (do_cats == cats_num)
-	    dots_per_line = (b - t) / (lines + 1);	/* +1 line for the two 1/2s at top and bottom */
-	else
-	    dots_per_line = (b - t) / (lines + 2);	/* + another line for 'x of y categories' text */
-
-	/* adjust text size */
-	/*  txsiz = (int)((y1-y0)/(1.5*(lines+5))); */
-	txsiz = (y1 - y0) / (2.0 * lines);
-
-	/* scale text to fit in window if position not manually set */
-	if (opt_at->answer == NULL) {	/* ie defualt scaling */
-	    ScaleFactor = ((true_r - true_l) / ((MaxLabelLen + 3) * txsiz * 0.81));	/* ?? txsiz*.81=actual text width. */
-	    if (ScaleFactor < 1.0) {
-		txsiz = txsiz * ScaleFactor;
-		dots_per_line = (int)floor(dots_per_line * ScaleFactor);
-	    }
-	}
-
-	if (dots_per_line < txsiz)
-	    txsiz = dots_per_line;
-
-	if (opt_fontsize->answer != NULL)
-	    txsiz = fontsize;
-
-	D_text_size(txsiz, txsiz);
-
-
-	/* Set up box arrays */
-	x_box[0] = 0;
-	y_box[0] = 0;
-	x_box[1] = 0;
-	y_box[1] = (5 - dots_per_line);
-	x_box[2] = (dots_per_line - 5);
-	y_box[2] = 0;
-	x_box[3] = 0;
-	y_box[3] = (dots_per_line - 5);
-	x_box[4] = (5 - dots_per_line);
-	y_box[4] = 0;
-
-
-	/* Draw away */
-
-	/* if(ScaleFactor < 1.0)   */
-	/*    cur_dot_row = ((b-t) - (dots_per_line*lines))/2; *//* this will center the legend */
-	/* else    */
-	cur_dot_row = t + dots_per_line / 2;
-
-	/*  j = (do_cats == cats_num ? 1 : 2 ); */
-
-	for (i = 0, k = 0; i < catlistCount; i++)
-	    /* for(i=min_ind, j=1, k=0; j<=do_cats && i<=max_ind; j++, i+=thin) */
-	{
-	    if (!flip)
-		cstr = Rast_get_d_cat(&catlist[i], &cats);
-	    else
-		cstr = Rast_get_d_cat(&catlist[catlistCount - i - 1], &cats);
-
-
-	    if (!cstr[0]) {	/* no cat label found, skip str output */
-		hide_catstr = 1;
-		if (hide_nodata)
-		    continue;
-	    }
-	    else
-		hide_catstr = hidestr->answer;
-
-	    k++;  /* count of actual boxes drawn (hide_nodata option invaidates using j-1) */
-
-	    /* White box */
-	    cur_dot_row += dots_per_line;
-	    D_use_color(white);
-	    D_begin();
-	    D_move_abs(l + 2, (cur_dot_row - 1));
-	    D_cont_rel(0, (3 - dots_per_line));
-	    D_cont_rel((dots_per_line - 3), 0);
-	    D_cont_rel(0, (dots_per_line - 3));
-	    D_close();
-	    D_end();
-	    D_stroke();
-
-	    /* Black box */
-	    D_use_color(black);
-	    D_begin();
-	    D_move_abs(l + 3, (cur_dot_row - 2));
-	    D_cont_rel(0, (5 - dots_per_line));
-	    D_cont_rel((dots_per_line - 5), 0);
-	    D_cont_rel(0, (dots_per_line - 5));
-	    D_close();
-	    D_end();
-	    D_stroke();
-
-	    /* Color solid box */
-	    if (!fp) {
-		if (!flip)
-		    D_color((CELL) (int)catlist[i], &colors);
-		else
-		    D_color((CELL) (int)catlist[catlistCount - i - 1],
-			    &colors);
-	    }
-	    else {
-		if (!flip)
-		    D_d_color(catlist[i], &colors);
-		else
-		    D_d_color(catlist[catlistCount - i - 1], &colors);
-	    }
-
-	    D_pos_abs(l + 3, (cur_dot_row - 2));
-	    D_polygon_rel(x_box, y_box, 5);
-
-	    /* Draw text */
-	    D_use_color(color);
-
-	    if (!fp) {
-		/* nothing, box only */
-		buff[0] = 0;
-		if (!hide_catnum) {	/* num */
-		    sprintf(buff, DispFormat, (int)catlist[i]);
-		    if (!flip)
-			sprintf(buff, DispFormat, (int)catlist[i]);
-		    else
-			sprintf(buff, DispFormat,
-				(int)catlist[catlistCount - i - 1]);
-		    if (!hide_catstr)	/* both */
-			strcat(buff, ")");
-		}
-		if (!hide_catstr)	/* str */
-		    sprintf(buff + strlen(buff), " %s", cstr);
-	    }
-	    else {		/* is fp */
-		if (!flip) {
-		    if (use_catlist)
-			/* pass through format exactly as given by the user in
-			   the use= command line parameter (helps with log scale) */
-			sprintf(buff, "%s", opt_use->answers[i]);
-		    else
-			/* automatically generated/tuned decimal precision format */
-			sprintf(buff, DispFormat, catlist[i]);
-		}
-		else {
-		    if(use_catlist)
-			sprintf(buff, "%s", opt_use->answers[catlistCount - i - 1]);
-		    else
-			sprintf(buff, DispFormat, catlist[catlistCount - i - 1]);
-		}
-	    }
-
-	    D_pos_abs((l + 3 + dots_per_line), (cur_dot_row) - 3);
-
-	    if (color)
-		D_text(buff);
-	}
-
-	if (0 == k)
-	    G_fatal_error(_("Nothing to draw! (no categories with labels?)"));	/* "(..., out of range?)" */
-
-
-	if (do_cats != cats_num) {
-	    cur_dot_row += dots_per_line;
-	    /* sprintf(buff, "%d of %d categories\n", (j-1), cats_num); */
-
-	    sprintf(buff, "%d of %d categories\n", k, cats_num);
-
-	    /* shrink text if it will run off the screen */
-	    MaxLabelLen = strlen(buff) + 4;
-	    ScaleFactor = ((true_r - true_l) / (MaxLabelLen * txsiz * 0.81));	/* ?? txsiz*.81=actual text width. */
-	    if (ScaleFactor < 1.0) {
-		txsiz = txsiz * ScaleFactor;
-
-		if (opt_fontsize->answer != NULL)
-		    txsiz = fontsize;
-
-		D_text_size(txsiz, txsiz);
-	    }
-	    D_use_color(white);
-	    D_pos_abs((l + 3 + dots_per_line), (cur_dot_row));
-	    if (color)
-		D_text(buff);
-	}
-    }
-
-    D_save_command(G_recreate_command());
     D_close_driver();
 
     exit(EXIT_SUCCESS);



More information about the grass-commit mailing list