view libaudacious/titlestring.c @ 1062:b727849e2128 trunk

[svn] - Add the ability to easily save to playlist.m3u from the list menu. (For those who hate having to restart Audacious in order to save the playlist).
author nhjm449
date Mon, 15 May 2006 20:55:19 -0700
parents 6636d328fa38
children ca5d03c4b3f1
line wrap: on
line source

/*
 * Copyright (C) 2001,  Espen Skoglund <esk@ira.uka.de>
 * Copyright (C) 2001,  Haavard Kvaalen <havardk@xmms.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#define GETTEXT_PACKAGE PACKAGE_NAME

#include <glib.h>
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>

#include "titlestring.h"

#define CHECK(input, field) \
	(((gchar *) &input->field - (gchar *) input) < input->__size)

#define VS(input, field) (CHECK(input, field) ? input->field : NULL)
#define VI(input, field) (CHECK(input, field) ? input->field : 0)


BmpTitleInput *
bmp_title_input_new()
{
    BmpTitleInput *input;
    input = g_new0(BmpTitleInput, 1);
    input->__size = XMMS_TITLEINPUT_SIZE;
    input->__version = XMMS_TITLEINPUT_VERSION;
    return input;
}

void
bmp_title_input_free(BmpTitleInput * input)
{
    if (!input)
        return;

    g_free(input->performer);
    g_free(input->album_name);
    g_free(input->track_name);
    g_free(input->date);
    g_free(input->genre);
    g_free(input->comment);
    g_free(input->file_name);
    g_free(input->file_path);
    g_free(input);
}

gchar *
xmms_get_titlestring(const gchar * fmt, TitleInput * input)
{
    GString *outstr;
    const gchar *string;
    gchar c, convert[16];
    gint numdigits, numpr, val, i;
    gint f_left, f_space, f_zero, someflag, width, precision;
    gboolean did_output = FALSE;
    gchar digits[] = "0123456789";

#define PUTCH(ch) g_string_append_c(outstr, ch)

#define LEFTPAD(num)                            \
    G_STMT_START {                              \
        gint cnt = (num);                       \
        if ( ! f_left && cnt > 0 )              \
            while ( cnt-- > 0 )                 \
                PUTCH(f_zero ? '0' : ' ');      \
    } G_STMT_END;

#define RIGHTPAD(num)                           \
    G_STMT_START {                              \
        gint cnt = (num);                       \
        if ( f_left && cnt > 0 )                \
            while ( cnt-- > 0 )                 \
                PUTCH( ' ' );                   \
    } G_STMT_END;

    if (fmt == NULL)
        return NULL;

    outstr = g_string_new("");

    for (;;) {
        /* Copy characters until we encounter '%'. */
        while ((c = *fmt++) != '%') {
            if (c == '\0')
                goto Done;
            g_string_append_c(outstr, c);
        }

        f_left = f_space = f_zero = 0;
        someflag = 1;


        /* Parse flags. */
        while (someflag) {
            switch (*fmt) {
            case '-':
                f_left = 1;
                fmt++;
                break;
            case ' ':
                f_space = 1;
                fmt++;
                break;
            case '0':
                f_zero = 1;
                fmt++;
                break;
            default:
                someflag = 0;
                break;
            }
        }


        /* Parse field width. */
        if ((c = *fmt) >= '0' && c <= '9') {
            width = 0;
            while ((c = *fmt++) >= '0' && c <= '9') {
                width *= 10;
                width += c - '0';
            }
            fmt--;
        }
        else
            width = -1;


        /* Parse precision. */
        if (*fmt == '.') {
            if ((c = *++fmt) >= '0' && c <= '9') {
                precision = 0;
                while ((c = *fmt++) >= '0' && c <= '9') {
                    precision *= 10;
                    precision += c - '0';
                }
                fmt--;
            }
            else
                precision = -1;
        }
        else
            precision = -1;


        /* Parse format conversion. */
        switch (c = *fmt++) {
        case '}':              /* close optional, just ignore */
            continue;

        case '{':{             /* optional entry: %{n:...%} */
                char n = *fmt++;
                if (!((n == 'a' && VS(input, album_name)) ||
                      (n == 'c' && VS(input, comment)) ||
                      (n == 'd' && VS(input, date)) ||
                      (n == 'e' && VS(input, file_ext)) ||
                      (n == 'f' && VS(input, file_name)) ||
                      (n == 'F' && VS(input, file_path)) ||
                      (n == 'g' && VS(input, genre)) ||
                      (n == 'n' && VI(input, track_number)) ||
                      (n == 'p' && VS(input, performer)) ||
                      (n == 't' && VS(input, track_name)))) {
                    int nl = 0;
                    char c;
                    while ((c = *fmt++))    /* until end of string      */
                        if (c == '}')   /* if end of opt            */
                            if (!nl)
                                break;  /* if outmost indent level  */
                            else
                                --nl;   /* else reduce indent       */
                        else if (c == '{')
                            ++nl;   /* increase indent          */
                }
                else
                    ++fmt;
                break;
            }

        case 'a':
            string = VS(input, album_name);
            goto Print_string;
        case 'c':
            string = VS(input, comment);
            goto Print_string;
        case 'd':
            string = VS(input, date);
            goto Print_string;
        case 'e':
            string = VS(input, file_ext);
            goto Print_string;
        case 'f':
            string = VS(input, file_name);
            goto Print_string;
        case 'F':
            string = VS(input, file_path);
            goto Print_string;
        case 'g':
            string = VS(input, genre);
            goto Print_string;
        case 'n':
            val = VI(input, track_number);
            goto Print_number;
        case 'p':
            string = VS(input, performer);
            goto Print_string;
        case 't':
            string = VS(input, track_name);

          Print_string:
            if (string == NULL)
                break;
            did_output = TRUE;

            numpr = 0;
            if (width > 0) {
                /* Calculate printed size. */
                numpr = strlen(string);
                if (precision >= 0 && precision < numpr)
                    numpr = precision;

                LEFTPAD(width - numpr);
            }

            /* Insert string. */
            if (precision >= 0) {
                while (precision-- > 0 && (c = *string++) != '\0')
                    PUTCH(c);
            }
            else {
                while ((c = *string++) != '\0')
                    PUTCH(c);
            }

            RIGHTPAD(width - numpr);
            break;

        case 'y':
            val = VI(input, year);

          Print_number:
            if (val == 0)
                break;
            if (c != 'N')
                did_output = TRUE;

            /* Create reversed number string. */
            numdigits = 0;
            do {
                convert[numdigits++] = digits[val % 10];
                val /= 10;
            }
            while (val > 0);

            numpr = numdigits > precision ? numdigits : precision;

            /* Insert left padding. */
            if (!f_left && width > numpr) {
                if (f_zero)
                    numpr = width;
                else
                    for (i = width - numpr; i-- > 0;)
                        PUTCH(' ');
            }

            /* Insert zero padding. */
            for (i = numpr - numdigits; i-- > 0;)
                PUTCH('0');

            /* Insert number. */
            while (numdigits > 0)
                PUTCH(convert[--numdigits]);

            RIGHTPAD(width - numpr);
            break;

        case '%':
            PUTCH('%');
            break;

        default:
            PUTCH('%');
            PUTCH(c);
            break;
        }
    }

  Done:
    if (did_output)
        return g_string_free(outstr, FALSE);
    else
        return NULL;
}

struct _TagDescription {
    gchar tag;
    gchar *description;
};

typedef struct _TagDescription TagDescription;

static TagDescription tag_descriptions[] = {
    {'p', N_("Performer/Artist")},
    {'a', N_("Album")},
    {'g', N_("Genre")},
    {'f', N_("File name")},
    {'F', N_("File path")},
    {'e', N_("File extension")},
    {'t', N_("Track name")},
    {'n', N_("Track number")},
    {'d', N_("Date")},
    {'y', N_("Year")},
    {'c', N_("Comment")}
};

gint tag_descriptions_length =
    sizeof(tag_descriptions) / sizeof(TagDescription);

GtkWidget *
xmms_titlestring_descriptions(gchar * tags, gint columns)
{
    GtkWidget *table, *label;
    gchar tag_str[5];
    gint num = strlen(tags);
    gint r = 0, c, i;

    g_return_val_if_fail(tags != NULL, NULL);
    g_return_val_if_fail(columns <= num, NULL);

    table = gtk_table_new((num + columns - 1) / columns, columns * 2, FALSE);
    gtk_table_set_row_spacings(GTK_TABLE(table), 2);
    gtk_table_set_col_spacings(GTK_TABLE(table), 5);

    for (c = 0; c < columns; c++) {
        for (r = 0; r < (num + columns - 1 - c) / columns; r++) {
            g_snprintf(tag_str, sizeof(tag_str), "%%%c:", *tags);
            label = gtk_label_new(tag_str);
            gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
            gtk_table_attach(GTK_TABLE(table), label, 2 * c, 2 * c + 1, r,
                             r + 1, GTK_FILL, GTK_FILL, 0, 0);
            gtk_widget_show(label);

            for (i = 0; i < tag_descriptions_length; i++) {
                if (*tags == tag_descriptions[i].tag) {
                    label = gtk_label_new(_(tag_descriptions[i].description));
                    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
                    gtk_table_attach(GTK_TABLE(table), label, 2 * c + 1,
                                     2 * c + 2, r, r + 1,
                                     GTK_EXPAND | GTK_FILL,
                                     GTK_EXPAND | GTK_FILL, 0, 0);
                    gtk_widget_show(label);
                    break;
                }
            }

            if (i == tag_descriptions_length)
                g_warning("Invalid tag: %c", *tags);

            tags++;
        }

    }

    label = gtk_label_new(_("%{n:...%}: Display \"...\" only if element "
                            "%n is present"));
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 0, r + 1,
                     r + 1, r + 2, GTK_FILL, GTK_FILL, 0, 0);
    gtk_widget_show(label);

    return table;
}