/*  
    cursesmenudisplay.c

    Copyright (C) 2010-2019 Amf

    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
*/

#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#ifdef CHROMA_CURSES_HEADER
#include CHROMA_CURSES_HEADER
#else
#ifdef __WIN32__
#include <curses.h>
#else
#include <ncurses.h>
#endif
#endif

#include "chroma.h"
#include "menu.h"
#include "actions.h"
#include "level.h"
#include "display.h"
#include "util.h"

#define MAX_WIDTH 65

extern int display_size_x, display_size_y;
extern int actions[KEY_MAX];

extern short colourpair_menu;
extern short colourpair_menugrey;
extern short colourpair_red;
extern short colourpair_green;
extern short colourpair_yellow;
extern short colourpair_blue;
extern short colourpair_cyan;
extern short colourpair_magenta;
extern short colourpair_cyan;
extern short colourpair_white;

int menu_offset;
int menu_width;
int menu_height_notes;
int menu_height_entries;
int menu_y_min;
int menu_y_max;
int menu_y_logo_top;
int menu_y_logo_bottom;
int menu_scroll_y_min;
int menu_scroll_y_max;
int menu_scroll_top;
int menu_scroll_bottom;

int menu_entryheight(struct menuentry *pentry)
{
    if(pentry->flags & MENU_INVISIBLE)
        return 0;
    if(pentry->flags & MENU_DOUBLE)
        return 2;
    return 1;
}

void menu_displayentry(struct menu *pmenu, struct menuentry *pentry, int y, int selected)
{
    char buffer[MAX_WIDTH + 1];
    int x, i;

    if(menu_width < 1)
        return;

    if(pentry->flags & MENU_INVISIBLE)
        return;

    if(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_TEXT))
        selected = 0;

    /* Plot first line, if visible */
    if((y >= menu_y_min && y < menu_y_max) || (pentry->flags & MENU_NOTE))
    {
        /* Plot key press */
        attron(COLOR_PAIR(colourpair_white));
        if(pentry->key != 0 && pentry->key != MENU_KEY_ANY)
        {   
            mvprintw(y, menu_offset - 4, "[ ] ");
            attron(A_BOLD);
            mvprintw(y, menu_offset - 3, "%c", pentry->key);
            attroff(A_BOLD);
        }
        else
            mvprintw(y, menu_offset - 4, "    ");
        attroff(COLOR_PAIR(colourpair_white));

        /* Determine colour */
        if(pentry->flags & (MENU_GREY | MENU_SPACE))
            attron(COLOR_PAIR(colourpair_menugrey));
        else if(pentry->flags & MENU_NOTE)
        {
            if(pmenu->logo == 0)
                attron(COLOR_PAIR(colourpair_menugrey));
        }
        else if(pentry->flags & MENU_TEXT)
            attron(COLOR_PAIR(colourpair_white));
        else
            attron(COLOR_PAIR(colourpair_menu));
        if(selected)
            attron(A_REVERSE);

        /* Blank line */
        move(y, menu_offset);
        for(i = 0; i < menu_width; i ++)
            addch(' ');

        /* Plot right hand side text */
        if(pentry->text2 != NULL)
        {   
            utf8strncpy(buffer, pentry->text2, menu_width - 2);
            x = menu_offset + menu_width - 1 - utf8strlen(buffer);
            mvprintw(y, x, buffer);
        }

        /* Plot main text */
        if(pentry->text != NULL)
        {
            utf8strncpy(buffer, pentry->text, menu_width - 2);

            x = menu_offset + 1;
            if(pentry->flags & MENU_RIGHT)
                x = menu_offset + menu_width - utf8strlen(buffer);
            if(pentry->flags & MENU_CENTRE)
                x = menu_offset + ((menu_width - utf8strlen(buffer))/2);

            if(pentry->flags & MENU_BOLD)
                attron(A_BOLD);
            mvprintw(y, x, buffer);
            if(pentry->flags & MENU_BOLD)
                attroff(A_BOLD);
        }

        if(selected)
            attroff(A_REVERSE);
        if(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE))
            attroff(COLOR_PAIR(colourpair_menugrey));
        else if(pentry->flags & MENU_TEXT)
            attroff(COLOR_PAIR(colourpair_white));
        else
            attroff(COLOR_PAIR(colourpair_menu));
    }

    if(!(pentry->flags & MENU_DOUBLE))
        return;

    y ++;

    /* Plot second line, if visible */
    if((y >= menu_y_min && y < menu_y_max) || (pentry->flags & MENU_NOTE))
    {
        /* Blank key press area */
        attron(COLOR_PAIR(colourpair_white));
        mvprintw(y, menu_offset - 4, "    ");
        attroff(COLOR_PAIR(colourpair_white));

        /* Determine colour */
        if(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE))
            attron(COLOR_PAIR(colourpair_menugrey));
        else
            attron(COLOR_PAIR(colourpair_menu));
        if(selected)
            attron(A_REVERSE);

        /* Blank line */
        move(y, menu_offset);
        for(i = 0; i < menu_width; i ++)
            addch(' ');

        /* Plot right hand side text */
        if(pentry->text4 != NULL)
        {   
            utf8strncpy(buffer, pentry->text4, menu_width - 2);

            x = menu_offset + menu_width - 1 - utf8strlen(buffer);
            if(pentry->flags & MENU_EDITING)
                attron(COLOR_PAIR(colourpair_white));
            mvprintw(y, x, buffer);
            if(pentry->flags & MENU_EDITING)
                attroff(COLOR_PAIR(colourpair_white));
        }

        /* Plot left hand side text */
        if(pentry->text3 != NULL)
        {   
            utf8strncpy(buffer, pentry->text3, menu_width - 2);

            x = menu_offset + 1;
            mvprintw(y, x, buffer);
        }

        if(selected)
            attroff(A_REVERSE);
        if(pentry->flags & (MENU_GREY | MENU_SPACE))
            attroff(COLOR_PAIR(colourpair_menugrey));
        else if(pentry->flags & MENU_NOTE)
        {
            if(pmenu->logo == 0)
                attroff(COLOR_PAIR(colourpair_menugrey));
        }
        else
            attroff(COLOR_PAIR(colourpair_menu));
    }
}

void menu_display(struct menu *pmenu, int redraw)
{
    struct menuentry *pentry;
    int x, y, selected;
    char title[] = "chroma";
    char buffer[256];
    int i;
    int state;
    int y_editing;
    short cp;
    int j;

                /* 012345678901234567890123456789012345678901 */
    char logo[] = "       8                                  "
                  "       8                                  "
                  ".oPYo. 8oPYo. oPYo. .oPYo. ooYoYo. .oPYo. "
                  "8    ' 8    8 8  `' 8    8 8' 8  8 .oooo8 "
                  "8    . 8    8 8     8    8 8  8  8 8    8 "
                  "`YooP' 8    8 8     `YooP' 8  8  8 `YooP8 ";

#define LOGO_HEIGHT 7

    /* Calculate various widths */
    menu_width = display_size_x - 2;
    if(menu_width > MAX_WIDTH)
        menu_width = MAX_WIDTH;

    menu_offset = (display_size_x - menu_width) / 2;
    if(menu_offset < 0)
        menu_offset = 0;

    menu_width -= 5;
    menu_offset += 4;

    /* Calculate various heights */
    menu_height_notes = 0;
    menu_height_entries = 0;

    pentry = pmenu->entry_first;
    while(pentry != NULL)
    {   
        if(pentry->flags & MENU_NOTE)
            menu_height_notes += menu_entryheight(pentry);
        else
            menu_height_entries += menu_entryheight(pentry);
        pentry = pentry->next;
    }

    /* Add an extra line to pad the notes out, if there are any */
    if(menu_height_notes != 0)
        menu_height_notes += 1;

    if(pmenu->logo)
    {   
        menu_y_logo_top = (display_size_y - menu_height_entries - LOGO_HEIGHT) / 2;
        if(menu_y_logo_top < 0)
            menu_y_logo_top = 0;
        menu_y_logo_bottom = menu_y_logo_top + LOGO_HEIGHT;
        menu_y_min = display_size_y - menu_height_entries - 1;
        if(menu_y_min < menu_y_logo_bottom)
            menu_y_min = menu_y_logo_bottom;
        menu_y_max = display_size_y - 1;
    }
    else
    {   
        menu_y_min = 4;
        menu_y_max = display_size_y - menu_height_notes - 1;
        if(pmenu->title != NULL)
            menu_y_min += 2;
    }

    /* If a full redraw, clear the screen and plot the title */
    if(redraw == MENUREDRAW_ALL)
    { 
    clear();
    curs_set(0); 

        if(pmenu->logo)
        {
            x = (display_size_x - 42) / 2;
            y = menu_y_logo_top;
            cp = colourpair_red;

            move(y, x);

            for(i = 0; i < strlen(logo); i ++)
            {
                addch(logo[i] | A_BOLD | COLOR_PAIR(cp));
                switch(i % 42)
                {
                    case 6:
                        cp = colourpair_yellow;
                        break;
                    case 13:
                        cp = colourpair_green;
                        break;
                    case 18:
                        cp = colourpair_cyan;
                        break;
                    case 25:
                        cp = colourpair_blue;
                        break;
                    case 33:
                        cp = colourpair_magenta;
                        break;
                    case 41:
                        y ++;
                        move(y, x);
                        cp = colourpair_red;
                        break;
                }
            }

            y ++;

        }
        else
        {
            /* Display game title */
            x = (display_size_x / 2) - strlen(title);

            attron(A_BOLD);
            for(i = 0; i < strlen(title); i ++)
            {   
                if(i == 0) attron(COLOR_PAIR(colourpair_red));
                if(i == 1) attron(COLOR_PAIR(colourpair_yellow));
                if(i == 2) attron(COLOR_PAIR(colourpair_green));
                if(i == 3) attron(COLOR_PAIR(colourpair_cyan));
                if(i == 4) attron(COLOR_PAIR(colourpair_blue));
                if(i == 5) attron(COLOR_PAIR(colourpair_magenta));

                sprintf(buffer, "%c", title[i]);
                mvprintw(2, x, buffer);
                x +=2;
            }
            attroff(COLOR_PAIR(colourpair_red));
            attroff(A_BOLD);

            /* Display menu title */
            y = 4;
            x = (display_size_x / 2) - utf8strlen(pmenu->title);

            attron(A_BOLD);
            attroff(COLOR_PAIR(colourpair_white));
            /* If the title is too long, plot normally */
            if(x < 0)
            {
                x = (display_size_x - utf8strlen(pmenu->title)) / 2;
                mvprintw(y, x, pmenu->title);
            }
            else
            {
                /* Otherwise, spread it out */
                for(i = 0; i < strlen(pmenu->title); i ++)
                {
            j = 0;
            buffer[j] = pmenu->title[i]; j ++;
            while((pmenu->title[i + j] & 0xc0) == 0x80)
            {
            buffer[j] = pmenu->title[i + j]; j ++;
            }
            buffer[j] = 0;
                    mvprintw(y, x, buffer);
            x += 2;  i += j - 1;
                }
            }
            attroff(A_BOLD);
        }
    }

    /* Keep scroll bar within reasonable limits */
    if(pmenu->offset > (menu_height_entries - (menu_y_max - menu_y_min)))
        pmenu->offset = menu_height_entries - (menu_y_max - menu_y_min);
    if(pmenu->offset < 0)
        pmenu->offset = 0;

    /* Display scrollbar, if needed */
    if(menu_height_entries > (menu_y_max - menu_y_min) || pmenu->offset != 0)
    {
        if(redraw >= MENUREDRAW_ENTRIES)
        {
            menu_scroll_y_min = menu_y_min + 1;
            menu_scroll_y_max = menu_y_max - 1;
            menu_scroll_top = menu_scroll_y_min + ((menu_scroll_y_max - menu_scroll_y_min) * pmenu->offset / menu_height_entries);
            menu_scroll_bottom = menu_scroll_top + ((menu_scroll_y_max - menu_scroll_y_min) * (1 + menu_y_max - menu_y_min) / menu_height_entries);

            attron(COLOR_PAIR(colourpair_menugrey));
            x = menu_offset + menu_width + 1;
            mvaddch(menu_y_min, x, '^');
            mvaddch(menu_y_max - 1, x, 'v');

            attron(COLOR_PAIR(colourpair_white));
            for(y = menu_y_min + 1; y < menu_y_max - 1; y ++)
            {
                /* >= and <= to guarantee at least one character scrollbar */
                if(y >= menu_scroll_top && y <= menu_scroll_bottom)
                {
                attron(A_REVERSE);
                mvaddch(y, x, '|');
                attroff(A_REVERSE);
                }
                else
                mvaddch(y, x, '.');
            }
        }
    }

    /* Display notes */
    if((menu_height_notes != 0) && redraw >= MENUREDRAW_ENTRIES)
    {
        if(pmenu->logo)
            y = menu_y_logo_bottom;
        else
            y = menu_y_max + 1;

        pentry = pmenu->entry_first;
        while(pentry != NULL)
        {
            if(pentry->flags & MENU_NOTE)
            {
                menu_displayentry(pmenu, pentry, y, 0);
                y += menu_entryheight(pentry);
            }
            pentry = pentry->next;
        }
    }

    /* Select an entry if the selected one is not on screen */
    if(pmenu->entry_selected == NULL)
        pmenu->entry_selected = pmenu->entry_first;
    y = menu_y_min - pmenu->offset;
    pentry = pmenu->entry_first;
    pmenu->display_first = NULL;
    pmenu->display_last = NULL;
    state = 1;
    while(pentry != NULL)
    {
        /* Don't count notes */
        if(pentry->flags & MENU_NOTE)
        {
            pentry = pentry->next;
            continue;
        }
        /* Is the entry off the top of the screen? */
        if(y < (menu_y_min - menu_entryheight(pentry)))
        {
            if(pentry == pmenu->entry_selected)
                state = -1;
            y += menu_entryheight(pentry);
            pentry = pentry->next;
            continue;
        }
        /* Stop processing once we hit the bottom of the screen */
        if(y > menu_y_max)
        {
            pentry = NULL;
            continue;
        }
        if(pentry == pmenu->entry_selected)
            state = 0;
        
        if(pmenu->display_first == NULL)
            pmenu->display_first = pentry->next;
        pmenu->display_last = pentry->previous;

        y += menu_entryheight(pentry);
        pentry = pentry->next;
    }
    if(state == -1)
        pmenu->entry_selected = pmenu->display_first;
    if(state == 1)
        pmenu->entry_selected = pmenu->display_last;
    if(state != 0 && redraw < MENUREDRAW_ENTRIES)
        redraw = MENUREDRAW_ENTRIES;

    /* Display entries */
    pentry = pmenu->entry_first;
    y = menu_y_min - pmenu->offset;
    y_editing = 0;
    while(pentry != NULL)
    {
        /* Don't display notes */
        if(pentry->flags & MENU_NOTE)
        {
            pentry = pentry->next;
            continue;
        }
        /* Don't display entries off the top of the screen */
        if(y < (menu_y_min - menu_entryheight(pentry)))
        {
            y += menu_entryheight(pentry);
            pentry = pentry->next;
            continue;
        }
        /* Stop processing once we hit the bottom of the screen */
        if(y > menu_y_max)
        {
            pentry = NULL;
            continue;
        }
        selected = (pmenu->entry_selected == pentry) ? 1 : 0;

        if(redraw >= MENUREDRAW_ENTRIES ||
                (redraw >= MENUREDRAW_CHANGED && pentry->redraw))
            menu_displayentry(pmenu, pentry, y, selected);
        if(pentry->flags & MENU_EDITING)
            y_editing = y + 1;


        pentry->redraw = 0;
        y += menu_entryheight(pentry);
        pentry = pentry->next;
    }

    /* Display cursor if we're editing a text field */
    if(y_editing)
    {
    curs_set(1); 
        move(y_editing, menu_offset + menu_width - 2);
    }
    else
    curs_set(0); 

    /* Redraw the screen */
    refresh();
}

int menu_process(struct menu* pmenu)
{
    int ok;
    int redraw;
    int c;
    struct menuentry* pentry;
    char *buffer;

    redraw = pmenu->redraw;

    ok = 0;
    while(!ok)
    {   
        if(redraw != MENUREDRAW_NONE)
        {   
            menu_display(pmenu, redraw);
            redraw = MENUREDRAW_NONE;
        }

        c = getch();

        /* Are we editing a text field? */
        if(pmenu->entry_selected != NULL && pmenu->entry_selected->flags & MENU_EDITING)
        {  
            switch(c)
            {  
                case KEY_RESIZE:
                    getmaxyx(stdscr, display_size_y, display_size_x);
                    redraw = MENUREDRAW_ALL;
                    break;

                case '\n':
                case '\r':
                case 27:
                case KEY_UP:
                case KEY_DOWN:
                case KEY_PPAGE:
                case KEY_NPAGE:
                    pmenu->entry_selected->flags -= MENU_EDITING;
                    pmenu->entry_selected->redraw = 1;
                    redraw = MENUREDRAW_CHANGED;
                    break;

                case KEY_BACKSPACE:
                case KEY_DC:
                case 8:
                    if(strlen(pmenu->entry_selected->text4) == 0)
                        break;

                    buffer = malloc(strlen(pmenu->entry_selected->text4) + 1);
                    if(buffer != NULL)
                    {  
                        strcpy(buffer, pmenu->entry_selected->text4);

                        /* not particularly efficient, but does the job of deleting one UTF8 character */
                        while(strlen(buffer) > 0 && ((buffer[strlen(buffer) - 1] & 0xc0) == 0x80))
                            buffer[strlen(buffer) - 1] = 0;
                        buffer[strlen(buffer) - 1] = 0;
                    }
                    menuentry_extratext(pmenu->entry_selected, NULL, NULL, buffer);
                    free(buffer);

                    pmenu->entry_selected->redraw = 1;
                    redraw = MENUREDRAW_CHANGED;
                    break;

                default:
                    if(c > 31 && c != 127)
                    {  
                        buffer = malloc(strlen(pmenu->entry_selected->text4) + 2);
                        if(buffer != NULL)
                        {  
                            strcpy(buffer, pmenu->entry_selected->text4);
                            buffer[strlen(buffer) + 1] = 0;
                            buffer[strlen(buffer)] = c;
                        }
                        menuentry_extratext(pmenu->entry_selected, NULL, NULL, buffer);
                        free(buffer);

                        pmenu->entry_selected->redraw = 1;
                        redraw = MENUREDRAW_CHANGED;
                        break;
                    }
                    break;
            }
            continue;
        }

        /* Not a text field, but a regular entry */
        /* First, check if the key corresponds to an entry */
        if(c >= 0 && c < 127)
            c = toupper(c);
        pentry = pmenu->entry_first;
        while(pentry != NULL)
        {  
            if(pentry->key == c)
            {   
                if(!(pentry->flags & (MENU_GREY | MENU_INVISIBLE | MENU_SPACE)))
                {
                    if(pmenu->entry_selected != NULL)
                        pmenu->entry_selected->redraw = 1;
                    pmenu->entry_selected = pentry;
                    pentry->redraw = 1;

                    if(pmenu->entry_selected->flags & MENU_EDITABLE)
                    {
                        pmenu->entry_selected->flags |= MENU_EDITING;
                        pmenu->entry_selected->redraw = 1;
                        redraw = MENUREDRAW_CHANGED;
                    }
                    else
                        ok = MENU_SELECT;
                    break;
                }
            }
            pentry = pentry->next;
        }

        if(ok == MENU_SELECT)
            continue;

        if(c < 0)
            continue;

        /* Otherwise, see if it corresponds to an action */
        switch(actions[c])
        {   
            case ACTION_UP:
                pentry = pmenu->entry_selected;
                while(pentry != NULL)
                {   
                    if(pentry == pmenu->display_first || pentry->flags & MENU_TEXT)
                        redraw = MENUREDRAW_ENTRIES;

                    pentry = pentry->previous;

                    if(pentry == NULL)
                        break;
                    if(redraw != MENUREDRAW_NONE)
                        pmenu->offset -= menu_entryheight(pentry);
                    if(!(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE)))
                        break;
                }
                if(pentry != NULL)
                {
                    pentry->redraw = 1;
                    pmenu->entry_selected->redraw = 1;
                    pmenu->entry_selected = pentry;
                    if(redraw == MENUREDRAW_NONE)
                        redraw = MENUREDRAW_CHANGED;
                }
                break;

            case ACTION_DOWN:
                pentry = pmenu->entry_selected;
                while(pentry != NULL)
                {
                    if(pentry == pmenu->display_last || pentry->flags & MENU_TEXT)
                        redraw = MENUREDRAW_ENTRIES;

                    pentry = pentry->next;

                    if(pentry == NULL)
                        break;
                    if(redraw != MENUREDRAW_NONE)
                        pmenu->offset += menu_entryheight(pentry);
                    if(!(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE)))
                        break;
                }
                if(pentry != NULL)
                {
                    pentry->redraw = 1;
                    pmenu->entry_selected->redraw = 1;
                    pmenu->entry_selected = pentry;
                    if(redraw == MENUREDRAW_NONE)
                        redraw = MENUREDRAW_CHANGED;
                }
                break;

            case ACTION_LEFT:
                if(pmenu->entry_selected != NULL && pmenu->entry_selected->flags & MENU_SCROLLABLE)
                    ok = MENU_SCROLLLEFT;
                break;

            case ACTION_RIGHT:
                if(pmenu->entry_selected != NULL && pmenu->entry_selected->flags & MENU_SCROLLABLE)
                    ok = MENU_SCROLLRIGHT;
                break;

            case ACTION_PAGE_UP:
                pmenu->offset -= (menu_y_max - menu_y_min);
                redraw = MENUREDRAW_ENTRIES;
                break;

            case ACTION_PAGE_DOWN:
                pmenu->offset += (menu_y_max - menu_y_min);
                redraw = MENUREDRAW_ENTRIES;
                break;

            case ACTION_ENTER:
                if(pmenu->entry_selected != NULL)
                {  
                   if(pmenu->entry_selected->flags & MENU_EDITABLE)
                   {   
                       pmenu->entry_selected->flags |= MENU_EDITING;
                       pmenu->entry_selected->redraw = 1;
                       redraw = MENUREDRAW_CHANGED;
                   }
                   else
                       ok = MENU_SELECT;
                }
                break;

            case ACTION_DELETE:
                if(pmenu->entry_selected != NULL && pmenu->entry_selected->flags & MENU_DELETABLE)
                    ok = MENU_DELETE;
                break;

            case ACTION_QUIT:
                ok = MENU_QUIT;
                break;

            case ACTION_REDRAW:
                getmaxyx(stdscr, display_size_y, display_size_x);
                redraw = MENUREDRAW_ALL;
                break;

            case ACTION_HIDE:
                display_hide();
                redraw = MENUREDRAW_ALL;
                break;

            default:
                /* See if there is an "any key" entry */
                pentry = pmenu->entry_first;
                while(pentry != NULL)
                {    
                    if(pentry->key == MENU_KEY_ANY)
                    {   
                        if(!(pentry->flags & (MENU_GREY | MENU_INVISIBLE | MENU_SPACE)))
                        {   
                            if(pmenu->entry_selected != NULL)
                                pmenu->entry_selected->redraw = 1;
                            pmenu->entry_selected = pentry;
                            pentry->redraw = 1;

                            ok = MENU_SELECT;
                            break;
                        }
                    }
                    pentry = pentry->next;
                }
                break;
        }
    }

    /* Redraw the whole menu when we next process it */
    pmenu->redraw = MENUREDRAW_ALL;

    if(ok == MENU_SELECT)
    {   
        if(pmenu->entry_selected->flags & MENU_SCROLLABLE)
            ok = MENU_SCROLLRIGHT;
    }
    /* unless this is a scrollable entry */
    if(ok == MENU_SCROLLLEFT || ok == MENU_SCROLLRIGHT)
    {   
        pmenu->redraw = MENUREDRAW_CHANGED;
        pmenu->entry_selected->redraw = 1;
    }

    return ok;
}

int menu_addfile(struct menu *pmenu, char *filename)
{
    FILE *file;
    char word[256], buffer[4096];
    char c;
    int i;
    int ok, wok;

    file = fopen(filename, "r");
    if(file == NULL)
    return 0;

    ok = 0;
    strcpy(buffer, "");
    while(!ok)
    {
    wok = 0; i = 0;
    while(!wok)
    {
        c = fgetc(file);
        if(c == 0 || c == 13 || c == 10 || c == 32 || c == 9 || feof(file) || i == 254)
        wok = 1;
        else
            word[i++] = c;
    }
    word[i] = 0;

    /* We assume menu_width is defined by the time we get here - a safe
       assumption provided this isn't the first menu we see. */
    if(utf8strlen(buffer) + utf8strlen(word) < menu_width - 2 && !(strcmp(word, "") == 0 && (c == 10 || c == 13)) && !(strncmp(word, "===", 3) == 0))
    {
        if(buffer[0] != 0 && word[0] != 0)
            strcat(buffer, " ");
        strcat(buffer, word);
    }
    else
    {
        menuentry_new(pmenu, buffer, 0, MENU_TEXT);
        if(strcmp(word, "") == 0 && (c == 10 || c ==13))
        menuentry_new(pmenu, "", 0, MENU_TEXT);
            if(strncmp(word, "===", 3) == 0)
            {
                strcpy(buffer, "");
                pmenu->entry_last->flags |= MENU_GREY;
            }
            else
            strcpy(buffer, word);
    }

    if(feof(file))
        ok = 1;
    }

    menuentry_new(pmenu, buffer, 0, MENU_TEXT);

    fclose(file);

    return 1;
}
