/*
(c) Copyright 1988-1994 Microsoft Corporation.

Microsoft Bars&Pipes Professional Source Code License

This License governs use of the accompanying Software.  
Microsoft hopes you find this Software useful.

You are licensed to do anything you want with the Software. 

In return, we simply require that you agree:

1.      Not to remove any copyright notices from the Software.

2.      That the Software comes "as is", with no warranties.  
        None whatsoever. This means no implied warranty of merchantability or 
        fitness for a particular purpose or any warranty of non-infringement.  
        Also, you must pass this disclaimer on whenever you distribute the Software.

3.      That we will not be liable for any of those types of damages known as indirect, 
        special, consequential, or incidental related to the Software or this License, 
        to the maximum extent the law permits. Also, you must pass this limitation of 
        liability on whenever you distribute the Software.

4.      That if you sue anyone over patents that you think may apply to the Software 
        for that person’s use of the Software, your license to the Software ends automatically.

5.      That the patent rights Microsoft is licensing only apply to the Software, 
        not to any derivatives you make.

6.      That your rights under the License end automatically if you breach this in any way.
*/

#include "/CompilerSpecific.h"
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <string.h>
#include "tools.h"
#include <exec/memory.h>
#include "display.h"
#include "edit.h"
#include "all.h"

extern struct Functions functions;

struct ScrollPort {
    struct ScrollPort *next;
    long leftedge, topedge, width, height;
    long oldleftedge, oldtopedge, oldwidth, oldheight;
    struct Gadget *gadget;      /* Gadget whose left edge pulls this. */
    unsigned short id;          /* ID of this scrollport. */
    unsigned short drawid;      /* Refresh bit for this scrollport. */
    unsigned long indent;       /* Indentation into list of display. */
    unsigned short itemwidth;   /* Width of one data item. */
    unsigned short scrollid;    /* ID for scroll gadget. */
    unsigned short displaywidth;/* Width of display window. */
    long datawidth;             /* Total width of data. */
};

extern struct Track *topdisplaytrack;
static struct ScrollPort scrollportarray[8];
static struct ScrollPort *scrollportlist = scrollportarray;

void createscrollportlist()

{
    register struct ScrollPort *port;
    static unsigned short itemwidth[8] = { 8,24,24,24,48,24,24,24 };
    static unsigned short scrollid[8] = { 6,0,9,0,12,0,15,0 };
    register unsigned short i = 1;
    for (;i <= 8;i++) {
        port = &scrollportarray[i-1];
        memset(port,0,sizeof(struct ScrollPort));
        if (i < 8) port->next = &scrollportarray[i];
        port->topedge = DISPLAYSTART;
        port->id = i;
        port->drawid = 1 << (i-1);
        port->itemwidth = itemwidth[i-1];
        port->scrollid = scrollid[i-1];
    }
}

static struct ScrollPort *getscrollport(id)

register unsigned short id;

{
    register struct ScrollPort *scroll;
    for (scroll = scrollportlist;scroll->id != id;scroll = scroll->next);
    return(scroll);
}

unsigned long timestart = 0;
unsigned long timeend = 0;
static short trackheight = 192;

static void computetrackdimension(id)

short id;

{
    struct Track *track;
    struct ScrollPort *scroll = getscrollport(id);
    short i = 0;
    for (track = functions.tracklist;track;track = track->next) {
        if (track == topdisplaytrack) i = DISPLAYSTART + 1;
        track->height = i;
        switch (id) {
            case 1 :
                track->nameleft = scroll->leftedge + 2;
                track->namewidth = (scroll->width - 4) >> 3;
                track->nameindent = scroll->indent;
                break;
            case 2 :
                track->channelinleft = scroll->leftedge + 2;
                break;
            case 3 :
                track->toolsinleft = scroll->leftedge + 2;
                track->toolsinwidth = (scroll->width - 4) / 24;
                track->toolsinindent = scroll->indent;
                break;
            case 4 :
                track->playrecordleft = scroll->leftedge + 2;
                break;
            case 5 :
                track->sequenceleft = scroll->leftedge + 2;
                track->sequencewidth = (scroll->width - 4) << 4;
                track->sequenceindent = measuretotime(0,scroll->indent);
                timestart = measuretotime(0,scroll->indent);
                timeend = measuretotime(0,scroll->displaywidth + 1);
                break;
            case 6 :
                track->muteleft = scroll->leftedge + 2;
                break;
            case 7 :
                track->toolsoutleft = scroll->leftedge + 2;
                track->toolsoutwidth = (scroll->width - 4) / 24;
                track->toolsoutindent = scroll->indent;
                track->toolsouttotalwidth = scroll->datawidth;
                break;
            case 8 :
                track->channeloutleft = scroll->leftedge + 2;
                break;
        }
        if (i) i += 12;
    }
}

settrackscrollbar(window)

struct Window *window;

{
    unsigned long p,len,count;
    long changedtop;
    len = List_Len((struct ListItem *)functions.tracklist);
    count = (scrollportlist->height - 1) / 12;
    if (changedtop = (count >= len)) topdisplaytrack = functions.tracklist;
    p = List_Position((struct ListItem *)functions.tracklist,(struct ListItem *)topdisplaytrack);
    ModifyEmbossedProp(window,18,0,p,0,len,0,count);
    DrawEmbossedPropNR(window,18);
    return(changedtop);
}

void setscrollbar(window,id)

struct Window *window;
unsigned short id;

{
    register struct ScrollPort *scroll = getscrollport(id);
    if (id == 5) scroll->displaywidth = timetomeasure(0,scroll->width << 4);
    else scroll->displaywidth = (scroll->width / scroll->itemwidth);
    if ((id != 5) && (scroll->displaywidth >= scroll->datawidth)) scroll->indent = 0;
    ModifyEmbossedProp(window,scroll->scrollid,
        scroll->indent,0,scroll->datawidth,0,scroll->displaywidth,0);
    DrawEmbossedPropNR(window,scroll->scrollid);
}

computenamescrollwidth()

{
    register struct Track *track = functions.tracklist;
    struct ScrollPort *scroll = getscrollport(1);
    long namesize = 0;
    for (;track;track = track->next) {
        if (track->clip.name) {
            if (track->clip.name->length > namesize)
                namesize = track->clip.name->length;
        }
    }
    scroll->datawidth = namesize;
    return(scroll->datawidth);
}

computetoolsinscrollwidth()

{
    register struct Tool *tool;
    register struct Track *track = functions.tracklist;
    struct ScrollPort *scroll = getscrollport(3);
    long toolcount = 0;
    register unsigned short i;
    for (;track;track = track->next) {
        tool = track->toollist;
        i = 0;
        for (;!(tool->tooltype & TOOL_SEQUENCE);tool = tool->next)
            i = tool->xindex;
        if (i > toolcount) toolcount = i;
    }
    scroll->datawidth = toolcount + 1;
    return(scroll->datawidth+1);
}

void computesonglength()

{
    register struct Track *track = functions.tracklist;
    unsigned long songtime;
    struct Section *aba = functions.sectionlist;
    functions.songlength = 6912;
    for (;aba;aba = aba->next) {
        if (!aba->next) functions.songlength = aba->time;
    }
    for (;track;track = track->next) {
        songtime = cliplength(&track->clip);
        if (track->edit && (track->edit->end > songtime))
            songtime = track->edit->end;
        if (songtime > functions.songlength) functions.songlength = songtime;
    }
    if (functions.songlength < functions.stoptime)
        functions.songlength = functions.stoptime;
/*
    if (functions.userlength) {
        if (functions.userlength > functions.songlength)
            functions.songlength = functions.userlength;
        else if (functions.songlength > functions.userlength)
        {
                functions.userlength = functions.songlength;
        }
    }
*/
    if (functions.userlength) functions.songlength = functions.userlength;
    functions.songlength = nextmeasure(0,functions.songlength + 1,0);
}

computesequencescrollwidth()

{
    struct ScrollPort *scroll = getscrollport(5);
    unsigned long songtime;
    computesonglength();
    songtime = timetomeasure(0,functions.songlength) + 3;
    scroll->datawidth = songtime;
    timestart = measuretotime(0,scroll->indent);
    timeend = measuretotime(0,scroll->displaywidth + 1);
    return((long)songtime);
}

computetoolsoutscrollwidth()

{
    register struct Tool *tool;
    register struct Track *track = functions.tracklist;
    struct ScrollPort *scroll = getscrollport(7);
    long toolcount = 0;
    register unsigned short i;
    for (;track;track = track->next) {
        tool = track->tool.next;
        i = 0;
        for (;tool;tool = tool->next) i = tool->xindex;
        if (i > toolcount) toolcount = i;
    }
    scroll->datawidth = toolcount + 1;
    return(scroll->datawidth);
}

/*
setsequenceindent(window,time)

struct Window *window;
long time;

{
    struct ScrollPort *scroll = getscrollport(5);
    long offset = measuretotime(0,scroll->displaywidth);
    time -= (offset >> 1);
    if (time < 0) time = 0;
    time = timetomeasure(0,time);
    if (scroll->indent != time) {
        scroll->indent = time;
        setscrollbar(window,5);
        return(1);
    }
    return(0);
}
*/

scrollsequenceindent(window,time)

struct Window *window;
long time;

{
    struct ScrollPort *scroll = getscrollport(5);
    if (!window) return(0);
    time = timetomeasure(0,time);
    if (scroll->indent != time) {
        scroll->indent = time;
        setscrollbar(window,5);
        return(1);
    }
    return(0);
}

changescroll(id,position)

short id;
long position;

{
    struct ScrollPort *scroll = getscrollport(id);
    long movemade;
    if (scroll->displaywidth >= scroll->datawidth) {
        if (scroll->scrollid != 5) position = 0;
    }
    movemade = (scroll->indent != position);
    scroll->indent = position;
    computetrackdimension(id);
    return(movemade);
}

extern struct Image pipeimage;

void drawscrollport(rp,scroll,track)

register struct RastPort *rp;
register struct ScrollPort *scroll;
register struct Track *track;

{
    if (!track) return;
    switch (scroll->id) {
        case 1 :
            drawtrackname(rp,track);
            break;
        case 2 :
            drawtrackchannelin(rp,track);
            break;
        case 3 :
            drawtracktoolsin(rp,track);
            break;
        case 4 :
            drawtrackplayrecord(rp,track);
            break;
        case 5 :
            drawtracksequence(rp,track);
            break;
        case 6 :
            drawtrackmutethrough(rp,track);
            break;
        case 7 :
            drawtracktoolsout(rp,track);
            break;
        case 8 :
            drawtrackchannelout(rp,track);
            break;
    }
}

void drawscrollline(rp,track,what)

struct RastPort *rp;
struct Track *track;
register short what;

{
    register struct ScrollPort *scroll = scrollportlist;
    register long x,w;
    for (;scroll;scroll = scroll->next) {
        if (track && (scroll->drawid & what)) {
            if (scroll->id != 6) {
                x = scroll->leftedge + 2;
                w = scroll->width - 4;
                rectfill(rp,0,x,track->height,x+w,track->height + 11);
            }
            drawscrollport(rp,scroll,track);
        }
    }
}

void drawscrolls(window,tracklist,what)

struct Window *window;
struct Track *tracklist;
long what;

{
    struct RastPort *rp = window->RPort;
    register long i;
    register long max = (scrollportlist->height - 1) / 12;
    if (what & DRAW_NAMES) {
        computenamescrollwidth();
        computetrackdimension(1);
    }
    if (what & DRAW_CHANNELSIN) {
        computetrackdimension(2);
    }
    if (what & DRAW_TOOLSIN) {
        computetoolsinscrollwidth();
        computetrackdimension(3);
    }
    if (what & DRAW_RECORD) {
        computetrackdimension(4);
    }
    if (what & DRAW_SEQUENCE) {
        computesequencescrollwidth();
        computetrackdimension(5);
    }
    if (what & DRAW_MUTE) {
        computetrackdimension(6);
    }
    if (what & DRAW_TOOLSOUT) {
        computetoolsoutscrollwidth();
        computetrackdimension(7);
    }
    if (what & DRAW_CHANNELSOUT) {
        computetrackdimension(8);
    }
    max = max * 12;
    trackheight = List_Len((struct ListItem *)topdisplaytrack) * 12;
    if (max < trackheight) trackheight = max;
    trackheight += DISPLAYSTART;
    for (i = 0;i < max;i+=12) {
        drawscrollline(rp,tracklist,what);
        if (tracklist) tracklist = tracklist->next;
    }
    for (;tracklist;tracklist = tracklist->next) tracklist->height = 0;
}

static void computebounds(window,left1,left2,left3,left4)

struct Window *window;
short *left1, *left2, *left3, *left4;

{
    short l1,l2,l3,l4;
    struct Gadget *gadget;
    gadget = (struct Gadget *) GetGadget(window,1);
    l1 = gadget->LeftEdge + 2;
    gadget = (struct Gadget *) GetGadget(window,2);
    l2 = gadget->LeftEdge + 2;
    gadget = (struct Gadget *) GetGadget(window,3);
    l3 = gadget->LeftEdge + 2;
    l4 = window->Width - 25;
    if (l1 < MINWIDTH) l1 = MINWIDTH;
    if ((l2 - l1) < LEFTMINWIDTH) l2 = l1 + LEFTMINWIDTH;
    if ((l3 - l2) < BIGMINWIDTH) l3 = l2 + BIGMINWIDTH;
    if ((l4 - l3) < RIGHTMINWIDTH) l4 = l3 + RIGHTMINWIDTH;
    if (l4 > (window->Width - 25))
        l4 = window->Width - 25;
    if ((l4 - l3) < RIGHTMINWIDTH) l3 = l4 - RIGHTMINWIDTH;
    if ((l3 - l2) < LEFTMINWIDTH) l2 = l3 - LEFTMINWIDTH;
    if ((l2 - l1) < BIGMINWIDTH) l1 = l2 - BIGMINWIDTH;
    *left1 = l1;
    *left2 = l2;
    *left3 = l3;
    *left4 = l4;
}

void computescrolllist(window)

struct Window *window;

{
    register struct ScrollPort *scroll = scrollportlist;
    short height;
    short left1, left2, left3, left4;
    computebounds(window,&left1,&left2,&left3,&left4);
    height = window->Height - 13 - DISPLAYSTART;
    scroll->leftedge = 6;
    scroll->width = left1 - 8;
    scroll->height = height;
    scroll = scroll->next;
    scroll->leftedge = left1 - 2;
    scroll->width = DOUBLEWIDTH + 3;
    scroll->height = height;
    scroll = scroll->next;
    scroll->leftedge = left1 + DOUBLEWIDTH + 1;
    scroll->width = left2 - (left1 + DOUBLEWIDTH + 3);
    scroll->height = height;
    scroll = scroll->next;
    scroll->leftedge = left2 - 2;
    scroll->width = DOUBLEWIDTH + 3;
    scroll->height = height;
    scroll = scroll->next;
    scroll->leftedge = left2 + DOUBLEWIDTH + 1;
    scroll->width = left3 - (left2 + DOUBLEWIDTH + 3);
    scroll->height = height;
    scroll = scroll->next;
    scroll->leftedge = left3 - 2;
    scroll->width = DOUBLEWIDTH + 3;
    scroll->height = height;
    scroll = scroll->next;
    scroll->leftedge = left3 + DOUBLEWIDTH + 1;
    scroll->width = left4 - (left3 + DOUBLEWIDTH + DOUBLEWIDTH + 6)+2;
    scroll->height = height;
    scroll = scroll->next;
    scroll->leftedge = left4 - DOUBLEWIDTH - 3;
    scroll->width = DOUBLEWIDTH + 3;
    scroll->height = height;
}

void drawscrolllist(window,mode,erase)

struct Window *window;
long mode;
char erase;

{
    register struct ScrollPort *scroll = scrollportlist;
    register struct RastPort *rp;
    register long x,y,w,h;
    computescrolllist(window);
    rp = window->RPort;
    SetAPen(rp,1);
    SetDrMd(rp,mode);
    for (;scroll;scroll = scroll->next) {
        if (erase) {
            x = scroll->oldleftedge;
            y = scroll->oldtopedge;
            w = scroll->oldwidth;
            h = scroll->oldheight;
            Move(rp,x+w,y+h);
            Draw(rp,x,y+h);
            Draw(rp,x,y);
            Draw(rp,x+w,y);
            if (!scroll->next) Draw(rp,x+w,y+h);
        }
        x = scroll->leftedge;
        y = scroll->topedge;
        w = scroll->width;
        h = scroll->height;
        scroll->oldleftedge = x;
        scroll->oldtopedge = y;
        scroll->oldwidth = w;
        scroll->oldheight = h;
        Move(rp,x+w,y+h);
        Draw(rp,x,y+h);
        Draw(rp,x,y);
        Draw(rp,x+w,y);
        if (!scroll->next) Draw(rp,x+w,y+h);
    }
}

static short startbound = 200;
static short endbound = 300;

void initheight()

{
/*    height = functions.window->Height - 12;*/
}

unsigned long markerposition(time)

register unsigned long time;

{
    register long displayendtime;
    if (time <= timestart) return(0);
    displayendtime = ((endbound - startbound) << 4) + timestart;
    if (time >= displayendtime) return(-1);
    time = time - timestart;
    time = time >> 4;
    return(time + startbound);
}

scrollstart()

{
    return((long)startbound);
}

scrollend()

{
    return((long)endbound);
}

scrollheight()

{
    return((long)trackheight);
}

static void refreshscrollgadget(window,id)

struct Window *window;
short id;

{
    switch(id) {
        case 1 :
        case 2 :
        case 3 :
        case 17 :
        case 19 :
            RefreshGadget(window,id);
            break;
        case 5 :
        case 7 :
        case 8 :
        case 10 :
        case 11 :
        case 13 :
        case 14 :
        case 16 :
            DrawEmbossed(window,id);
            break;
        case 6 :
        case 9 :
        case 12 :
        case 15 :
        case 18 :
            EmbossOff(window,id);
            EmbossOn(window,id,0);
            DrawEmbossedProp(window,id);
            break;
    }
}

void adjustgadgets(window)

struct Window *window;

{
    register struct Gadget *gadget;
    register struct DragInfo *drag;
    struct ScrollPort *scroll = scrollportlist;
    struct RastPort *rp;
    unsigned short top;
    register long i;
    short left1, left2, left3, left4;
    computebounds(window,&left1,&left2,&left3,&left4);
    top = window->Height - 11;
    startbound = left2 + DOUBLEWIDTH + 4;
    endbound = left3 - 3;
    gadget = (struct Gadget *) GetGadget(window,1);
    gadget->TopEdge = top;
    gadget->LeftEdge = left1 - 2;
    drag = (struct DragInfo *) gadget->UserData;
    drag->TopEdge = top;
    drag->BottomEdge = top + 8;
    gadget = (struct Gadget *) GetGadget(window,2);
    gadget->TopEdge = top;
    gadget->LeftEdge = left2 - 2;
    drag = (struct DragInfo *) gadget->UserData;
    drag->TopEdge = top;
    drag->BottomEdge = top + 8;
    gadget = (struct Gadget *) GetGadget(window,3);
    gadget->TopEdge = top;
    gadget->LeftEdge = left3 - 2;
    drag = (struct DragInfo *) gadget->UserData;
    drag->TopEdge = top;
    drag->BottomEdge = top + 8;
    gadget = (struct Gadget *) GetGadget(window,5);
    gadget->LeftEdge = 8;
    gadget->TopEdge = top + 1;
    gadget = (struct Gadget *) GetGadget(window,6);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = 6 + ARROWWIDTH + 2;
    gadget->Width = left1 - ARROWWIDTH - ARROWWIDTH - 12;
    gadget = (struct Gadget *) GetGadget(window,7);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left1 - ARROWWIDTH;
    gadget = (struct Gadget *) GetGadget(window,8);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left1 + DOUBLEWIDTH + 4;
    gadget = (struct Gadget *) GetGadget(window,9);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left1 + DOUBLEWIDTH + ARROWWIDTH + 4;
    gadget->Width = left2 - left1 - MINWIDTH + 2;
    gadget = (struct Gadget *) GetGadget(window,10);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left2 - ARROWWIDTH;
    gadget = (struct Gadget *) GetGadget(window,11);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left2 + DOUBLEWIDTH + 4;
    gadget = (struct Gadget *) GetGadget(window,12);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left2 + DOUBLEWIDTH + ARROWWIDTH + 4;
    gadget->Width = left3 - left2 - ARROWWIDTH - ARROWWIDTH - DOUBLEWIDTH - 8;
    gadget = (struct Gadget *) GetGadget(window,13);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left3 - ARROWWIDTH;
    gadget = (struct Gadget *) GetGadget(window,14);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left3 + DOUBLEWIDTH + 4;
    gadget = (struct Gadget *) GetGadget(window,15);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left3 + DOUBLEWIDTH + ARROWWIDTH + 4;
    gadget->Width = left4 - left3 - ARROWWIDTH - ARROWWIDTH -
        DOUBLEWIDTH - DOUBLEWIDTH - 9;
    gadget = (struct Gadget *) GetGadget(window,16);
    gadget->TopEdge = top + 1;
    gadget->LeftEdge = left4 - ARROWWIDTH - DOUBLEWIDTH - 1;
    gadget = (struct Gadget *) GetGadget(window,17);
    gadget->TopEdge = DISPLAYSTART;
    gadget->LeftEdge = left4 + 3;
    gadget = (struct Gadget *) GetGadget(window,18);
    gadget->TopEdge = DISPLAYSTART + ARROWHEIGHT;
    gadget->Height = top - DISPLAYSTART - ARROWHEIGHT - ARROWHEIGHT - 1;
    gadget->LeftEdge = left4 + 5;
    gadget = (struct Gadget *) GetGadget(window,19);
    gadget->TopEdge = top - ARROWHEIGHT;
    gadget->LeftEdge = left4 + 3;
    setdragboundaries(window,window->Width);
    rp = window->RPort;
    rectfill(rp,0,4,DISPLAYSTART,window->Width - 5,
        window->Height-3);
    RefreshGadget(window,0xFFD);
    for (i=1;i<20;i++) refreshscrollgadget(window,i);
    for (i=31;scroll;scroll = scroll->next) {
        if (i == 38) i = 40;
        gadget = (struct Gadget *) GetGadget(window,i);
        if (gadget) {
            gadget->LeftEdge = scroll->leftedge;
            gadget->TopEdge = scroll->topedge;
            gadget->Height = scroll->height;
            gadget->Width = scroll->width;
        }
        i++;
    }
    scroll = getscrollport(5);
    gadget = GetGadget(window,38);
    gadget->LeftEdge = scroll->leftedge;
    gadget->Width = scroll->width;
}
