365 lines
11 KiB
JavaScript
365 lines
11 KiB
JavaScript
|
/*
|
||
|
Algo: a dekstop environment look-a-like in your web browser
|
||
|
Copyright (C) 2009 Niels Serup
|
||
|
|
||
|
This file is part of Algo.
|
||
|
|
||
|
Algo 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 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
Algo 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 Algo. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
The screen class creates the screen on which all the windows appear.
|
||
|
As a matter of fact, the screen class simply serves as a layer for adding
|
||
|
windows. That's all. */
|
||
|
function screen() {
|
||
|
this.elem = document.createElement('div')
|
||
|
this.elem.className = 'area'
|
||
|
this.elem.style.width = '100%' // Height determined by JavaScript later on
|
||
|
wrapper.appendChild(this.elem)
|
||
|
|
||
|
/* len and olen dynamically increases as new windows are opened. But while
|
||
|
len is decreased when windows are closed, olen is never decreases. This
|
||
|
proves helpful when the windows in objects/iframes must be able to access
|
||
|
their own windows. */
|
||
|
this.len = 0
|
||
|
this.olen = 0
|
||
|
/* wndpos holds information about the windows on the screen. Each wndpos
|
||
|
entry is a link to a scr_window class. wndpos keeps the links in their
|
||
|
index order. */
|
||
|
this.wndpos = new Array()
|
||
|
|
||
|
/* It is neccessary to create an overlay, as the window objects/iframes will
|
||
|
catch focus if the mouse is moved over them. The overlay is on whenever a
|
||
|
window is being moved or adjusted */
|
||
|
this.overlay = document.createElement('div')
|
||
|
this.overlay.className = 'overlay'
|
||
|
this.elem.appendChild(this.overlay)
|
||
|
}
|
||
|
|
||
|
screen.prototype.rethink = function() {
|
||
|
// rethink() reorganises the screen top and height based on the navbars.
|
||
|
var navil = navi.length
|
||
|
var mh, th, borders, bl, border
|
||
|
mh = 0
|
||
|
th = 0
|
||
|
/* The following loop uses the height and the border height of the navbars
|
||
|
to compute the space on which the screen should be positioned. */
|
||
|
for (var i = 0; i < navil; i++) {
|
||
|
border = 0
|
||
|
borders = navi[i].border
|
||
|
bl = borders.length
|
||
|
for (var ii = 0; ii < bl; ii += 2) {
|
||
|
border += borders[ii]
|
||
|
}
|
||
|
mh += navi[i].height
|
||
|
if (navi[i].pos[0] != -1)
|
||
|
th += navi[i].height + border
|
||
|
if (navi[i].pos[0] != -1 || navi[i].pos[2] != -1)
|
||
|
mh += border
|
||
|
}
|
||
|
// bi = the heights of the navbars plus the border heights of the navbars
|
||
|
this.bi = mh
|
||
|
this.elem.style.top = th + 'px'
|
||
|
}
|
||
|
|
||
|
screen.prototype.update = function() {
|
||
|
// Updates width and height and adjusts the height
|
||
|
this.wh()
|
||
|
this.elem.style.height = sh + 'px'
|
||
|
}
|
||
|
|
||
|
screen.prototype.wh = function() {
|
||
|
// Get screen width and height
|
||
|
if (self.innerHeight) {
|
||
|
h = self.innerHeight
|
||
|
w = self.innerWidth
|
||
|
}
|
||
|
else if (document.documentElement && document.documentElement.clientHeight) {
|
||
|
h = document.documentElement.clientHeight
|
||
|
w = document.documentElement.clientWidth
|
||
|
}
|
||
|
else if (document.body) {
|
||
|
h = document.body.clientHeight
|
||
|
w = document.body.clientWidth
|
||
|
}
|
||
|
|
||
|
// sh = screen height - navbars heights. The height of the screen area is sh
|
||
|
sh = h - this.bi
|
||
|
}
|
||
|
|
||
|
screen.prototype.change_focus = function(num, det) {
|
||
|
/* This function changes focus to the window specified in "num". "det" is a
|
||
|
special identifier that tells this function what to do. Or whatever. */
|
||
|
if (det == undefined) var det = 0
|
||
|
|
||
|
var num = num * 1
|
||
|
for (var i = 0; i < this.len; i++) {
|
||
|
// Delete link from the wndpos list
|
||
|
if (this.wndpos[i] == num) this.wndpos.splice(i, 1)
|
||
|
}
|
||
|
/*
|
||
|
if det == 0: add window to front
|
||
|
if det == 1: add window to back
|
||
|
if det == 2: remove and close window
|
||
|
*/
|
||
|
if (det == 0)
|
||
|
this.wndpos.splice(0, 0, num)
|
||
|
else if (det == 1)
|
||
|
this.wndpos.splice(this.len, this.len, num)
|
||
|
else if (det == 2) {
|
||
|
this.len--
|
||
|
this.elem.removeChild(wnds[num].elem)
|
||
|
navi[posis['appboxes']].appboxes.removeChild(wnds[num].appbox)
|
||
|
|
||
|
for (i = 0; i < this.len; i++) {
|
||
|
if (this.wndpos[i] > num) {
|
||
|
wnds[this.wndpos[i]].renum(-1) // Readjust windows with a higher index
|
||
|
this.wndpos[i]--
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Different actions based on different variables
|
||
|
if (moving_window > num) moving_window--
|
||
|
else if (moving_window == num) this.move_end()
|
||
|
|
||
|
if (adjusting_window > num) adjusting_window--
|
||
|
else if (adjusting_window == num) this.adjust_end()
|
||
|
|
||
|
delete wnds[num]
|
||
|
wnds.splice(num, 1)
|
||
|
|
||
|
}
|
||
|
// This function has no done anything visually. setindex takes care of that.
|
||
|
this.setindex()
|
||
|
}
|
||
|
|
||
|
screen.prototype.setindex = function() {
|
||
|
/* This function writes any changes made in the classes in the wndpos to the
|
||
|
screen. If focus has changed from one window to another, setindex makes
|
||
|
the user see that. */
|
||
|
for (var i = 1; i < this.len; i++) {
|
||
|
wnds[this.wndpos[i]].elem.style.zIndex = this.len - i + 1
|
||
|
wnds[this.wndpos[i]].elem.id = ''
|
||
|
wnds[this.wndpos[i]].appbox.className = ''
|
||
|
}
|
||
|
if (this.len > 0) {
|
||
|
// The first window in the hierarchy gets the focus
|
||
|
wnds[this.wndpos[0]].elem.style.zIndex = this.len + 2
|
||
|
wnds[this.wndpos[0]].elem.id = 'active'
|
||
|
wnds[this.wndpos[0]].appbox.className = ''
|
||
|
this.overlay.style.zIndex = this.len + 1
|
||
|
}
|
||
|
|
||
|
// vis will turn true if any window is visible
|
||
|
var vis = false
|
||
|
for (i = 0; i < this.len; i++) {
|
||
|
if (wnds[i].visible) vis = true
|
||
|
}
|
||
|
// Only make the current window current if at least one window is visible
|
||
|
if (vis) wnds[this.wndpos[0]].appbox.className = 'current'
|
||
|
|
||
|
// Check if there's enough space for the appboxes
|
||
|
navi[posis['appboxes']].check_abs_height(true)
|
||
|
}
|
||
|
|
||
|
screen.prototype.set_overlay = function() {
|
||
|
this.overlay.style.display = 'block'
|
||
|
}
|
||
|
|
||
|
screen.prototype.del_overlay = function() {
|
||
|
this.overlay.style.display = 'none'
|
||
|
}
|
||
|
|
||
|
screen.prototype.move_start = function(what) {
|
||
|
/* "move_start" sets the global value "moving_window" to the active window
|
||
|
and thereby makes it recognisable by the set_coor function. */
|
||
|
moving_window = what * 1
|
||
|
|
||
|
/* The overlays are needed to keep the objects/iframes from getting the
|
||
|
mouse focus. In theory this should not happen, but as the mouse is often
|
||
|
moved faster than the window, this happens.
|
||
|
There are two overlays: one that covers the window and on that covers the
|
||
|
other windows. */
|
||
|
wnds[moving_window].cn('data_overlay').style.display = 'block'
|
||
|
this.set_overlay()
|
||
|
|
||
|
// These are needed later on to determine the position of the window.
|
||
|
diff_x = x - wnds[moving_window].elem.offsetLeft
|
||
|
diff_y = y - wnds[moving_window].elem.offsetTop
|
||
|
}
|
||
|
|
||
|
screen.prototype.move_end = function() {
|
||
|
if (moving_window > -1)
|
||
|
wnds[moving_window].cn('data_overlay').style.display = 'none'
|
||
|
moving_window = -1
|
||
|
this.blurfocus()
|
||
|
}
|
||
|
|
||
|
screen.prototype.adjust_start = function(what, dir) {
|
||
|
/* This is the same as "move_start" except that this does not start moving
|
||
|
the window, but instead it starts adjusting (resizing) it. */
|
||
|
adjusting_window = what * 1
|
||
|
adjusting_dir = dir * 1
|
||
|
wnds[adjusting_window].cn('data_overlay').style.display = 'block'
|
||
|
this.set_overlay()
|
||
|
|
||
|
// Different variables are set depending on the direction of the adjusting.
|
||
|
/*
|
||
|
The directions are:
|
||
|
0: top-left
|
||
|
1: top
|
||
|
2: top-right
|
||
|
3: right
|
||
|
4: bottom-right
|
||
|
5: bottom
|
||
|
6: bottom-left
|
||
|
7: left
|
||
|
|
||
|
If the resize direction is diagonal, both of the below options are true.
|
||
|
*/
|
||
|
if (adjusting_dir != 1 && adjusting_dir != 5) {
|
||
|
// If vertical
|
||
|
start_x = x
|
||
|
start_w = wnds[adjusting_window].width
|
||
|
diff_x = start_x - wnds[adjusting_window].elem.offsetLeft
|
||
|
}
|
||
|
if (adjusting_dir != 3 && adjusting_dir != 7) {
|
||
|
// If horizontal
|
||
|
start_y = y
|
||
|
start_h = wnds[adjusting_window].height
|
||
|
diff_y = start_y - wnds[adjusting_window].elem.offsetTop
|
||
|
}
|
||
|
}
|
||
|
|
||
|
screen.prototype.adjust_end = function() {
|
||
|
if (adjusting_window > -1)
|
||
|
wnds[adjusting_window].cn('data_overlay').style.display = 'none'
|
||
|
adjusting_window = -1
|
||
|
adjusting_dir = -1
|
||
|
this.blurfocus()
|
||
|
}
|
||
|
|
||
|
screen.prototype.blurfocus = function() {
|
||
|
// Hides the overlay and applies the fix
|
||
|
this.del_overlay()
|
||
|
highlightfix.focus()
|
||
|
highlightfix.select()
|
||
|
}
|
||
|
|
||
|
screen.prototype.setwindow = function(a, b, c, d, e, f, g, h, i, j, k, l, m, n) {
|
||
|
// This function is the one that must be called when creating a new window.
|
||
|
wnds[wnds.length] = new scr_window(a, b, c, d, e, f, g, h, i, j, k, l, m, n)
|
||
|
|
||
|
// Positions itself at the front
|
||
|
this.wndpos.splice(0, 0, this.len)
|
||
|
this.len++
|
||
|
this.olen++
|
||
|
this.setindex()
|
||
|
}
|
||
|
|
||
|
screen.prototype.move_window = function() {
|
||
|
// Moves the window based on current and earlier set variables
|
||
|
var cx = x - diff_x
|
||
|
if (cx < -diff_x) cx = -diff_x
|
||
|
else if (cx > w - diff_x) cx = w - diff_x
|
||
|
var cy = y - diff_y
|
||
|
if (cy < 0) cy = 0
|
||
|
else if (cy > sh - scr.hheight) cy = sh - scr.hheight
|
||
|
if (scr.len > moving_window) {
|
||
|
wnds[moving_window].elem.style.left = cx + 'px'
|
||
|
wnds[moving_window].elem.style.top = cy + 'px'
|
||
|
}
|
||
|
}
|
||
|
|
||
|
screen.prototype.adjust_window = function() {
|
||
|
// Adjusts the window based on current and earlier set variables
|
||
|
|
||
|
// This function uses the same direction principle as "adjust_start".
|
||
|
if (adjusting_dir != 1 && adjusting_dir != 5) {
|
||
|
var cx, cw, cxs
|
||
|
cxs = false
|
||
|
if (adjusting_dir == 0 || adjusting_dir == 6 || adjusting_dir == 7) {
|
||
|
// If to the left
|
||
|
cx = x - diff_x
|
||
|
cw = start_w + start_x - x
|
||
|
if (x - diff_x < 0) {
|
||
|
cx = 0
|
||
|
cxs = true
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// If to the right
|
||
|
cx = start_x - start_w + start_w - diff_x
|
||
|
cw = start_w + x - start_x
|
||
|
if (x + start_w - diff_x > w) cxs = true
|
||
|
}
|
||
|
|
||
|
if (cw < width_min) cxs = true
|
||
|
|
||
|
if (!cxs && scr.len > adjusting_window) {
|
||
|
wnds[adjusting_window].elem.style.left = cx + 'px'
|
||
|
wnds[adjusting_window].width = cw
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (adjusting_dir != 3 && adjusting_dir != 7) {
|
||
|
var cy, ch, cys
|
||
|
cys = false
|
||
|
if (adjusting_dir == 0 || adjusting_dir == 1 || adjusting_dir == 2) {
|
||
|
// If upwards
|
||
|
cy = y - diff_y
|
||
|
ch = start_h + start_y - y
|
||
|
if (y - diff_y < 0) {
|
||
|
cy = 0
|
||
|
cys = true
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// If downwards
|
||
|
cy = start_y - start_y + start_y - diff_y
|
||
|
ch = start_h + y - start_y
|
||
|
if (y + start_h - diff_y > sh) cys = true
|
||
|
}
|
||
|
|
||
|
if (ch < height_min) cys = true
|
||
|
|
||
|
if (!cys && scr.len > adjusting_window) {
|
||
|
wnds[adjusting_window].elem.style.top = cy + 'px'
|
||
|
wnds[adjusting_window].height = ch
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update the window position
|
||
|
wnds[adjusting_window].update()
|
||
|
}
|
||
|
|
||
|
screen.prototype.set_coor = function(e) {
|
||
|
/* This function sets the global coordinates of the screen. If a window
|
||
|
is eiher being moved or adjusted, this function calls the "move_window"
|
||
|
or "adjust_window" functions */
|
||
|
if (!e) var e = window.event
|
||
|
if (e.pageX || e.pageY) {
|
||
|
x = e.pageX
|
||
|
y = e.pageY
|
||
|
}
|
||
|
else if (e.clientX || e.clientY) {
|
||
|
x = e.clientX + document.body.scrollLeft
|
||
|
y = e.clientY + document.body.scrollTop
|
||
|
}
|
||
|
|
||
|
if (moving_window != -1)
|
||
|
scr.move_window()
|
||
|
else if (adjusting_window != -1)
|
||
|
scr.adjust_window()
|
||
|
}
|