aboutsummaryrefslogtreecommitdiffstats
path: root/front/window.ts
blob: 840f7a2471111c3da57b1709c32846b15ce33b7f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import { mk } from './util';

// An array with all the windows on the screen
export var windows: BaseWindow[] = [];

// The focused window
export var focused_window: BaseWindow = null;


import * as drag from './dragging'


// Windows have a z-index. When we click a window it is sent to the top this will be its new z-index
// We then increment the depth, and the next window we click will go on top of the current one
var depth = 20;

export class WindowResizeHandleDraggable extends drag.Draggable {
    window: HTMLDivElement;
    xDir: number;
    yDir: number;

    constructor(window: HTMLDivElement, el: HTMLElement, xDir: number, yDir: number) {
        super(el);
        this.window   = window;
        this.reparent = false;
        this.lockSize = false;
        this.xDir = xDir;
        this.yDir = yDir;

        this.customMoveHandler = (x, y) => {
            if (this.xDir == -1) {
                const oldX = parseInt(this.window.style.left.slice(0, -2));
                const oldWidth = parseInt(this.window.style.width.slice(0, -2));
                this.window.style.left = x + "px";
                this.window.style.width = (oldWidth + (oldX - x)).toString() + "px";
            }
            if (this.yDir == -1) {
                const oldY = parseInt(this.window.style.top.slice(0, -2));
                const oldHeight = parseInt(this.window.style.height.slice(0, -2));
                this.window.style.top = y + "px";
                this.window.style.height = (oldHeight + (oldY - y)).toString() + "px";
            }
            if (this.xDir == 1) {
                const oldX = parseInt(this.window.style.left.slice(0, -2));
                this.window.style.width = (x - oldX).toString() + "px";
            }
            if (this.yDir == 1) {
                const oldY = parseInt(this.window.style.top.slice(0, -2));
                this.window.style.height = (y - oldY).toString() + "px";
            }
        }
    }
}

export class BaseWindow {
    pwd: string[];
    visuals: HTMLElement;
    h2: HTMLElement;      // The titlebar of the window
    fileview: any; // TODO what is this
    files: any[];
    txt_editor: HTMLElement; // For editable text files, this is the DOM element the user can edit

    grid: HTMLElement;
    wc: HTMLElement;


    constructor(pwd, x, y, w, h) {
        this.pwd = pwd;      // pwd = [ "Folder1", "Folder2" ] means the current directory of that window is /Folder1/Folder2
        this.visuals = null; // The DOM object
        this.h2 = null;      // The titlebar of the window
        this.fileview = null;
        this.files = [];
        this.txt_editor = null; // For editable text files, this is the DOM element the user can edit

        make_window_base(this, pwd, x, y, w, h);
    }

    destroy() {
        var index = windows.indexOf(this);

        if (index >= 0)
            windows.splice(index, 1);

        this.visuals.parentNode.removeChild(this.visuals);
        if (this == focused_window)
            focused_window = null;
    }

    focus() {
        if (focused_window == this)
            return;

        // Unfocus the old window
        if (focused_window)
            focused_window.visuals.classList.remove('focus');

        focused_window = this;
        // And focus the new one!
        this.visuals.classList.add('focus');
        this.visuals.style.zIndex = (depth++).toString();
    }

    get_path(max_length?: number) {
        if (max_length == undefined) {
            max_length = this.pwd.length;
        }

        var path = "/";
        for (let i = 0; i < max_length; i++) {
            path += this.pwd[i];
            if (i != max_length - 1)
                path += "/";
        }
        return path;
    }
}



export function unfocus_window() {
    if (focused_window) {
        focused_window.visuals.classList.remove('focus');
        focused_window = null;
    }
}

function mkdraghandle(wnd, _class, x, y) {
    const d = mk(wnd.grid, 'div', _class);
    const dd = new WindowResizeHandleDraggable(wnd.visuals as HTMLDivElement, d, x, y);
    d.onmousedown = (e) => drag.begin_drag(e, dd);
}


// This creates the parts of a window that are common between all window types
// This should only really be called by another function that will then fill up the window
function make_window_base(wnd: BaseWindow, pwd, x, y, w, h) {
    windows.push(wnd);

    wnd.visuals = mk(document.body, 'div', 'window');
    wnd.grid = mk(wnd.visuals, 'div', 'windowgrid');
    wnd.wc = mk(wnd.grid, 'div', 'wc');

    wnd.visuals.style.width    = w + "px";
    wnd.visuals.style.height   = h ? (h + "px") : "unset";
    wnd.visuals.style.position = "absolute";
    wnd.visuals.style.left     = x + "px";
    wnd.visuals.style.top      = y + "px";

    wnd.h2 = mk(wnd.wc, 'h2');


    mkdraghandle(wnd, 'nw-resize', -1, -1)
    mkdraghandle(wnd, 'w-resize', -1, 0);
    mkdraghandle(wnd, 'sw-resize', -1, 1);
    mkdraghandle(wnd, 's-resize', 0, 1);
    mkdraghandle(wnd, 'se-resize', 1, 1);
    mkdraghandle(wnd, 'e-resize', 1, 0);
    mkdraghandle(wnd, 'ne-resize', 1, -1);
    mkdraghandle(wnd, 'n-resize', 0, -1);

    wnd.visuals.onmousedown = (_e) => { 
        wnd.focus();
    }

    wnd.h2.onmousedown = (e) => {
        if (!drag.dragging)
            drag.set_dragging_candidate(e, new drag.Draggable(wnd.visuals));
    };

    return wnd;
}