Logo Search packages:      
Sourcecode: efte version File versions  Download package

menu_text.cpp

/*    menu_text.cpp
 *
 *    Copyright (c) 2008, eFTE SF Group (see AUTHORS file)
 *    Copyright (c) 1994-1996, Marko Macek
 *
 *    You may distribute under the terms of either the GNU General Public
 *    License or the Artistic License, as specified in the README file.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <ctype.h>
#include <stdarg.h>
#if defined(MSVC)
#include <malloc.h>
#endif
#include "console.h"
#include "gui.h"
#include "c_mode.h"
#include "c_color.h"

class UpMenu {
public:
    class UpMenu *up;
    int id;
    int vert;
    int x, y, w, h;
};

static int GetHOfsItem(int id, int cur) {
    int pos = 2;
    int i, len;

    for (i = 0; i < Menus[id].Count; i++) {
        if (i == cur) return pos;
        if (Menus[id].Items[i].Name) {
            len = CStrLen(Menus[id].Items[i].Name);
            pos += len + 2;
        } else
            pos++;
    }
    return -1;
}

static int GetHPosItem(int id, int X) {
    int pos = 1;
    int i, len;

    for (i = 0; i < Menus[id].Count; i++) {
        if (Menus[id].Items[i].Name) {
            len = CStrLen(Menus[id].Items[i].Name);
            if (X >= pos && X <= pos + len + 1) return i;
            pos += len + 2;
        } else
            pos++;
    }
    return -1;
}

static int DrawHMenu(int x, int y, int id, int active) {
    int pos = 1;
    TDrawBuffer B;
    int i, len;
    TAttr color1, color2;
    int Cols, Rows;

    ConQuerySize(&Cols, &Rows);

    MoveChar(B, 0, Cols, ' ', hcMenu_Background, Cols);
    if (id != -1) {
        for (i = 0; i < Menus[id].Count; i++) {
            if (i == active) {
                color1 = hcMenu_ActiveItem;
                color2 = hcMenu_ActiveChar;
            } else {
                color1 = hcMenu_NormalItem;
                color2 = hcMenu_NormalChar;
            }

            if (Menus[id].Items[i].Name) {
                len = CStrLen(Menus[id].Items[i].Name);
                MoveChar(B, pos, Cols, ' ', color1, len + 2);
                MoveCStr(B, pos + 1, Cols, Menus[id].Items[i].Name, color1, color2, len);
                pos += len + 2;
            } else {
                MoveChar(B, pos, Cols, ConGetDrawChar(DCH_V), hcMenu_Background, 1);
                pos++;
            }
        }
    }
    ConPutBox(x, y, Cols - x, 1, B);
    return 1;
}

static int GetVPosItem(int id, int w, int X, int Y) {
    if (Y <= 0 || Y > Menus[id].Count) return -1;
    if (Menus[id].Items[Y - 1].Name == 0) return -1;
    if (X <= 0 || X >= w - 1) return -1;
    return Y - 1;
}

static int GetVSize(int id, int &X, int &Y) {
    int xsize = 0;
    int len;

    Y = Menus[id].Count;
    for (int i = 0; i < Y; i++) {
        len = 0;
        if (Menus[id].Items[i].Name)
            len = CStrLen(Menus[id].Items[i].Name);
        if (len > xsize)
            xsize = len;
    }
    X = xsize;
    return 0;
}


static int DrawVMenu(int x, int y, int id, int active) {
    TDrawBuffer B;
    int i, len;
    TAttr color1, color2;
    int w, h;

    if (id == -1) return -1;

    GetVSize(id, w, h);
    w += 4;
    h += 2;

    MoveChar(B, 0, w, ConGetDrawChar(DCH_H), hcMenu_Background, w);
    MoveCh(B, ConGetDrawChar(DCH_C1), hcMenu_Background, 1);
    MoveCh(B + w - 1, ConGetDrawChar(DCH_C2), hcMenu_Background, 1);
    ConPutBox(x, y, w, 1, B);
    for (i = 0; i < Menus[id].Count; i++) {
        if (i == active) {
            color1 = hcMenu_ActiveItem;
            color2 = hcMenu_ActiveChar;
        } else {
            color1 = hcMenu_NormalItem;
            color2 = hcMenu_NormalChar;
        }
        if (Menus[id].Items[i].Name) {
            char name[128];
            char *arg = 0;
            int len2 = 0;

            strcpy(name, Menus[id].Items[i].Name);
            arg = strchr(name, '\t');
            if (arg)
                *arg++ = 0;

            len = CStrLen(name);
            if (arg)
                len2 = CStrLen(arg);

            MoveChar(B, 0, w, ' ', color1, w);
            MoveCh(B, ConGetDrawChar(DCH_V), hcMenu_Background, 1);
            MoveCh(B + w - 1, ConGetDrawChar(DCH_V), hcMenu_Background, 1);

            MoveCStr(B, 2, len + 2, Menus[id].Items[i].Name, color1, color2, len);
            if (arg)
                MoveCStr(B, w - len2 - 2, w + 4, arg, color1, color2, len2);

            if (Menus[id].Items[i].SubMenu != -1) {
                MoveCh(B + w - 2, ConGetDrawChar(DCH_RPTR), color1, 1);
            }
        } else {
            MoveChar(B, 0, w, ConGetDrawChar(DCH_H), hcMenu_Background, w);
            MoveCh(B, ConGetDrawChar(DCH_V), hcMenu_Background, 1);
            MoveCh(B + w - 1, ConGetDrawChar(DCH_V), hcMenu_Background, 1);
        }
        ConPutBox(x, y + i + 1, w, 1, B);
    }
    MoveChar(B, 0, w, ConGetDrawChar(DCH_H), hcMenu_Background, w);
    MoveCh(B, ConGetDrawChar(DCH_C3), hcMenu_Background, 1);
    MoveCh(B + w - 1, ConGetDrawChar(DCH_C4), hcMenu_Background, 1);
    ConPutBox(x, y + Menus[id].Count + 1, w, 1, B);
    return 1;
}

int ExecVertMenu(int x, int y, int id, TEvent &E, UpMenu *up) {
    int cur = 0;
    int abort;
    int w, h;
    PCell c;
    PCell SaveC = 0;
    int SaveX, SaveY, SaveW, SaveH;
    int wasmouse = 0;
    UpMenu here;
    int dovert = 0;
    int rx;
    int Cols, Rows;

    ConQuerySize(&Cols, &Rows);

    here.up = up;

    if (x < 0) x = 0;
    if (y < 0) y = 0;

    GetVSize(id, w, h);
    w += 4;
    h += 2;

    if (w > Cols) w = Cols;
    if (h > Rows) h = Rows;

    if ((x + w) > Cols)
        if (up && up->x == 0 && up->y == 0 && up->h == 1) {
            x = Cols - w;
        } else {
            if (up)
                x = up->x - w + 1;
            else
                x = x - w + 1;
        }
    if ((y + h) > Rows)
        if (up)
            y = y - h + 3;
        else {
            y = y - h + 1;
        }
    if (x < 0) x = 0;
    if (y < 0) y = 0;

    here.x = x;
    here.y = y;
    here.w = w;
    here.h = h;
    here.id = id;
    here.vert = 1;

    c = (PCell) malloc(w * h * sizeof(TCell));
    if (c)
        ConGetBox(x, y, w, h, c);

    SaveC = c;
    SaveX = x;
    SaveY = y;
    SaveW = w;
    SaveH = h;

    if (E.What == evMouseMove || E.What == evMouseDown) {
    }
    if (E.What & evMouse) {
        cur = GetVPosItem(id, w, E.Mouse.X - x, E.Mouse.Y - y);
        dovert = 0;
        wasmouse = 1;
        E.What = evNone;
    }
    abort = -2;
    while (abort == -2) {
        DrawVMenu(x, y, id, cur);
        if (dovert) {
            if (cur != -1) {
                if (Menus[id].Items[cur].SubMenu != -1) {
                    rx = ExecVertMenu(x + w - 1, y + cur,
                                      Menus[id].Items[cur].SubMenu, E, &here);
                    if (rx == 1) {
                        abort = 1;
                        continue;
                    } else if (rx == -3) {
                        abort = -3;
                        break;
                    } else
                        abort = -2;

                }
            }
        }
        ConHideCursor();
        do {
            ConGetEvent(evCommand | evMouseDown | evMouseMove | evMouseUp | evKeyDown | evNotify, &E, -1, 1);
            if (E.What & evNotify)
                gui->DispatchEvent(frames, frames->Active, E);
        } while (E.What & evNotify);
        if (E.What & evMouse) {
            //fprintf(stderr, "Mouse: %d %d %d\n", E.What, E.Mouse.X, E.Mouse.Y);
        }
        dovert = 0;
        switch (E.What) {
        case evCommand:
            if (E.Msg.Command == cmResize) abort = -3;
            break;
        case evKeyDown:
            switch (kbCode(E.Key.Code)) {
            case kbPgDn:
            case kbEnd:
                cur = Menus[id].Count;
            case kbUp: {
                int xcur = cur;

                do {
                    cur--;
                    if (cur < 0) cur = Menus[id].Count - 1;
                } while (cur != xcur && Menus[id].Items[cur].Name == 0);
            }
            break;
            case kbPgUp:
            case kbHome:
                cur = -1;
            case kbDown: {
                int xcur = cur;
                do {
                    cur++;
                    if (cur >= Menus[id].Count) cur = 0;
                } while (cur != xcur && Menus[id].Items[cur].Name == 0);
            }
            break;
            case kbEsc:
                abort = -1;
                break;
            case kbEnter:
                if (cur != -1) {
                    if (Menus[id].Items[cur].SubMenu < 0) {
                        E.What = evCommand;
                        E.Msg.View = frames->Active;
                        E.Msg.Command = Menus[id].Items[cur].Cmd;
                        abort = 1;
                    } else {
                        dovert = 1;
                    }
                }
                break;
            case kbLeft:
            case kbRight:
                gui->ConPutEvent(E);
                abort = -1;
                break;
            default:
                if (isAscii(E.Key.Code)) {
                    char cc;
                    int i;

                    cc = char(toupper(char(E.Key.Code & 0xFF)));

                    for (i = 0; i < Menus[id].Count; i++) {
                        if (Menus[id].Items[i].Name) {
                            char *o = strchr(Menus[id].Items[i].Name, '&');
                            if (o)
                                if (toupper(o[1]) == cc) {
                                    cur = i;
                                    if (cur != -1) {
                                        if (Menus[id].Items[cur].SubMenu == -1) {
                                            E.What = evCommand;
                                            E.Msg.View = frames->Active;
                                            E.Msg.Command = Menus[id].Items[cur].Cmd;
                                            abort = 1;
                                        } else {
                                            dovert = 1;
                                        }
                                    }
                                    break;
                                }
                        }
                    }
                }
            }
            break;
        case evMouseDown:
            if (E.Mouse.X >= x && E.Mouse.Y >= y &&
                    E.Mouse.X < x + w && E.Mouse.Y < y + h) {
                cur = GetVPosItem(id, w, E.Mouse.X - x, E.Mouse.Y - y);
            } else {
                if (up)
                    gui->ConPutEvent(E);
                abort = -1;
            }
            wasmouse = 1;
            dovert = 1;
            break;
        case evMouseMove:
            if (E.Mouse.Buttons)  {
                dovert = 1;
                if (E.Mouse.X >= x && E.Mouse.Y >= y &&
                        E.Mouse.X < x + w && E.Mouse.Y < y + h) {
                    cur = GetVPosItem(id, w, E.Mouse.X - x, E.Mouse.Y - y);
                } else {
                    UpMenu *p = up;
                    int first = 1;

                    if (wasmouse) {
                        while (p) {
                            if (E.Mouse.X >= p->x && E.Mouse.Y >= p->y &&
                                    E.Mouse.X < p->x + p->w && E.Mouse.Y < p->y + p->h) {
                                if (first == 1) {
                                    if (p->vert) {
                                        int i = GetVPosItem(p->id, p->w, E.Mouse.X - p->x, E.Mouse.Y - p->y);
                                        if (i != -1)
                                            if (Menus[p->id].Items[i].SubMenu == id) break;
                                    } else {
                                        int i = GetHPosItem(p->id, E.Mouse.X);
                                        if (i != -1)
                                            if (Menus[p->id].Items[i].SubMenu == id) break;
                                    }
                                    first = 0;
                                }
                                gui->ConPutEvent(E);
                                abort = -1;
                                break;
                            }
                            first = 0;
                            p = p->up;
                        }
                        cur = -1;
                    } else
                        cur = -1;
                }
            }
            break;
        case evMouseUp:
            if (E.Mouse.X >= x && E.Mouse.Y >= y &&
                    E.Mouse.X < x + w && E.Mouse.Y < y + h) {
                cur = GetVPosItem(id, w, E.Mouse.X - x, E.Mouse.Y - y);
            }
            if (cur == -1) {
                if (up) {
                    UpMenu *p = up;
                    cur = 0;
                    if (E.Mouse.X >= p->x && E.Mouse.Y >= p->y &&
                            E.Mouse.X < p->x + p->w && E.Mouse.Y < p->y + p->h) {
                        if (p->vert) {
                            int i = GetVPosItem(p->id, p->w, E.Mouse.X - p->x, E.Mouse.Y - p->y);
                            if (i != -1)
                                if (Menus[p->id].Items[i].SubMenu == id) break;
                        } else {
                            int i = GetHPosItem(p->id, E.Mouse.X);
                            if (i != -1)
                                if (Menus[p->id].Items[i].SubMenu == id) break;
                        }
                        abort = -1;
                    }
                } else
                    abort = -1;
                if (E.Mouse.X >= x && E.Mouse.Y >= y &&
                        E.Mouse.X < x + w && E.Mouse.Y < y + h);
                else {
                    gui->ConPutEvent(E);
                    abort = -3;
                }
            } else {
                if (Menus[id].Items[cur].Name != 0 &&
                        Menus[id].Items[cur].SubMenu == -1) {
                    E.What = evCommand;
                    E.Msg.View = frames->Active;
                    E.Msg.Command = Menus[id].Items[cur].Cmd;
                    //fprintf(stderr, "Command set = %d %d %d\n", id, cur, Menus[id].Items[cur].Cmd);
                    abort = 1;
                }
            }
            break;
        }
    }
    if (SaveC) {
        ConPutBox(SaveX, SaveY, SaveW, SaveH, SaveC);
        free(SaveC);
        SaveC = 0;
    }
    ConShowCursor();
    if (up && abort == -3) return -3;
    return (abort == 1) ? 1 : -1;
}

int ExecMainMenu(TEvent &E, char sub) {
    int cur = 0;
    int id = GetMenuId(frames->Menu);
    int abort;
    int dovert = 1;
    int rx;
    static UpMenu top = { 0, 0, 0, 0, 0, 0, 1 };
    PCell topline[ConMaxCols];
    int Cols, Rows;

    ConQuerySize(&Cols, &Rows);

    top.x = 0;
    top.y = 0;
    top.h = 1;
    top.w = Cols;
    top.id = id;
    top.vert = 0;

    ConGetBox(0, 0, Cols, 1, (PCell) topline);

    if (sub != 0) {
        int i;

        for (i = 0; i < Menus[id].Count; i++) {
            if (Menus[id].Items[i].Name) {
                char *o = strchr(Menus[id].Items[i].Name, '&');
                if (o)
                    if (toupper(o[1]) == toupper(sub)) {
                        cur = i;
                        break;
                    }
            }
        }
    }

    if (E.What == evMouseDown) {
        cur = GetHPosItem(id, E.Mouse.X);
        dovert = 1;
    }

    abort = -2;
    while (abort == -2) {
        DrawHMenu(0, 0, id, cur);
        if (dovert) {
            if (cur != -1) {
                if (Menus[id].Items[cur].SubMenu != -1) {
                    rx = ExecVertMenu(GetHOfsItem(id, cur) - 2, 1,
                                      Menus[id].Items[cur].SubMenu, E, &top);
                    if (rx == 1) {
                        abort = 1;
                        continue;
                    } else if (rx == -3) {
                        abort = -1;
                        break;
                    } else
                        abort = -2;
                }
            }
        }
        ConHideCursor();
        do {
            ConGetEvent(evCommand | evMouseDown | evMouseMove | evMouseUp | evKeyDown | evNotify, &E, -1, 1);
            if (E.What & evNotify)
                gui->DispatchEvent(frames, frames->Active, E);
        } while (E.What & evNotify);
        dovert = 0;
        switch (E.What) {
        case evCommand:
            if (E.Msg.Command == cmResize) abort = -1;
            break;
        case evKeyDown:
            switch (kbCode(E.Key.Code)) {
            case kbEnd:
                cur = Menus[id].Count;
            case kbLeft:
                dovert = 1;
                {
                    int x = cur;
                    do {
                        cur--;
                        if (cur < 0) cur = Menus[id].Count - 1;
                    } while (cur != x && Menus[id].Items[cur].Name == 0);
                }
                break;
            case kbHome:
                cur = -1;
            case kbRight:
                dovert = 1;
                {
                    int x = cur;
                    do {
                        cur++;
                        if (cur >= Menus[id].Count) cur = 0;
                    } while (cur != x && Menus[id].Items[cur].Name == 0);
                }
                break;
            case kbEsc:
                abort = -1;
                dovert = 0;
                break;
            case kbEnter:
                if (cur != -1) {
                    if (Menus[id].Items[cur].SubMenu == -1) {
                        E.What = evCommand;
                        E.Msg.View = frames->Active;
                        E.Msg.Command = Menus[id].Items[cur].Cmd;
                        abort = 1;
                    } else {
                        dovert = 1;
                    }
                }
                break;
            default:
                if (isAscii(E.Key.Code)) {
                    char cc;
                    int i;

                    cc = char(toupper(char(E.Key.Code & 0xFF)));

                    for (i = 0; i < Menus[id].Count; i++) {
                        if (Menus[id].Items[i].Name) {
                            char *o = strchr(Menus[id].Items[i].Name, '&');
                            if (o)
                                if (toupper(o[1]) == cc) {
                                    cur = i;
                                    if (cur != -1) {
                                        if (Menus[id].Items[cur].SubMenu == -1) {
                                            E.What = evCommand;
                                            E.Msg.View = frames->Active;
                                            E.Msg.Command = Menus[id].Items[cur].Cmd;
                                            abort = 1;
                                        } else {
                                            dovert = 1;
                                        }
                                    }
                                    break;
                                }
                        }
                    }
                }
                break;
            }
            break;
        case evMouseDown:
            if (E.Mouse.Y == 0) {
                int oldcur = cur;
                cur = GetHPosItem(id, E.Mouse.X);
                if (cur == oldcur) {
                    abort = -1;
                }
            } else {
                cur = -1;
                abort = -1;
            }
            dovert = 1;
            break;
        case evMouseMove:
            if (E.Mouse.Buttons) {
                if (E.Mouse.Y == 0)
                    cur = GetHPosItem(id, E.Mouse.X);
                else
                    cur = -1;
                dovert = 1;
            }
            break;
        case evMouseUp:
            if (E.Mouse.Y == 0)
                cur = GetHPosItem(id, E.Mouse.X);
            if (cur == -1)
                abort = -1;
            else {
                if (Menus[id].Items[cur].Name != 0 &&
                        Menus[id].Items[cur].SubMenu == -1) {
                    E.What = evCommand;
                    E.Msg.View = frames->Active;
                    E.Msg.Command = Menus[id].Items[cur].Cmd;
                    abort = 1;
                }
            }
            break;
        }
    }
    DrawHMenu(0, 0, id, -1);
    ConPutBox(0, 0, Cols, 1, (PCell) topline);
    ConShowCursor();
    return (abort == 1) ? 1 : -1;
}

void GFrame::DrawMenuBar() {
    int id = GetMenuId(Menu);

    DrawHMenu(0, 0, id, -1);
}

extern TEvent NextEvent;

int GFrame::PopupMenu(const char *Name) {
    NextEvent.What = evCommand;
    NextEvent.Msg.Command = cmPopupMenu;
    NextEvent.Msg.Param1 = GetMenuId(Name);
    return 0;
}

Generated by  Doxygen 1.6.0   Back to index