metanohi-misc-subsites/projects/algo/js/screen.js

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()
}