Pop.Box/elements/window.moon
2017-04-30 16:40:29 -07:00

161 lines
6.1 KiB
Plaintext

--- A generic window element. Built-in support for minimize, maximize, and close
--- buttons, as well as drag-to-resize and drag-to-move. Title bar customizable.
--- @classmod window
--- @copyright Paul Liverman III (2016)
--- @license The MIT License (MIT)
--- @todo Implement missing features.
local pop
import mouse from love
path = (...)\sub 1, -7
element = require "#{path}/element"
box = require "#{path}/box"
text = require "#{path}/text"
-- images would go here
class window extends element
load: (pop_lib) ->
pop = pop_lib
--- Constructor expects nothing, or a data table describing it.
--- @todo document containMethod values
new: (@parent, @data={}, title="Window") =>
super @parent, @data
@data.type = "window"
@data.w = 100 unless @data.w > 0
@data.h = 80 unless @data.h > 0
@data.containMethod = "mouse" unless @data.containMethod
@header = pop.box @, @data.titleBackground or {25, 180, 230, 255}
@title = pop.text @header, {horizontal: "center"}, title, @data.titleColor or {255, 255, 255, 255}
@window_area = pop.box @, @data.windowBackground or {200, 200, 210, 255}
-- closeButton, minimizeButton, etc
height = @title\getHeight!
@header\setSize @data.w, height
@window_area\setSize @data.w, @data.h - height
@window_area\move nil, height
-- window area steals mouse events to prevent propagation to elements under it
@window_area.mousepressed = (x, y, button) ->
-- attempted to also make them pull to foreground, but it doesn't work
if button == pop.constants.left_mouse
grandparent = @parent.parent
table.insert grandparent.child, table.remove(grandparent.child, grandparent\indexOf @parent)
return nil
@window_area.clicked = ->
return nil
selected = false
mx = 0
my = 0
@header.mousemoved = (x, y, dx, dy) =>
if selected
@parent\move dx, dy
-- do not leave area of grandparent (based on containMethod)
grandparent = @parent.parent
switch @parent.data.containMethod
when "title" -- the window title can't leave
@parent\move(grandparent.data.x - @data.x) if @data.x < grandparent.data.x
@parent\move(nil, grandparent.data.y - @data.y) if @data.y < grandparent.data.y
@parent\move(grandparent.data.x + grandparent.data.w - (@data.x + @data.w)) if @data.x + @data.w > grandparent.data.x + grandparent.data.w
@parent\move(nil, grandparent.data.y + grandparent.data.h - (@data.y + @data.h)) if @data.y + @data.h > grandparent.data.y + grandparent.data.h
when "body" -- the entire window can't leave
@parent\move(grandparent.data.x - @data.x) if @data.x < grandparent.data.x
@parent\move(nil, grandparent.data.y - @data.y) if @data.y < grandparent.data.y
@parent\move(grandparent.data.x + grandparent.data.w - (@parent.data.x + @parent.data.w)) if @parent.data.x + @parent.data.w > grandparent.data.x + grandparent.data.w
@parent\move(nil, grandparent.data.y + grandparent.data.h - (@parent.data.y + @parent.data.h)) if @parent.data.y + @parent.data.h > grandparent.data.y + grandparent.data.h
when "mouse" -- wherever the mouse has clicked can't leave
@parent\setPosition(grandparent.data.x + @data.w - mx) if mouse.getX! < grandparent.data.x
@parent\setPosition(nil, grandparent.data.y + @parent.data.h - my) if mouse.getY! < grandparent.data.y
@parent\setPosition(grandparent.data.x + grandparent.data.w + @data.w - mx) if mouse.getX! > grandparent.data.x + grandparent.data.w
@parent\setPosition(nil, grandparent.data.y + grandparent.data.h + @parent.data.h - my) if mouse.getY! > grandparent.data.y + grandparent.data.h
return true
return false
@header.mousepressed = (x, y, button) =>
if button == pop.constants.left_mouse
grandparent = @parent.parent
table.insert grandparent.child, table.remove(grandparent.child, grandparent\indexOf @parent)
selected = true
mx = x
my = y
return true
return false
@header.mousereleased = (x, y, button) =>
if button == pop.constants.left_mouse
selected = false
--pop.focused = false -- we have to manually clear our focus
return true
return false
-- unsure if needed or how needed
--@setSize @data.w, @data.h -- or 100, 80
@align!
align: (...) =>
unless @data.align return @
super ...
-- don't know if this is needed or why
--for i = 1, #@child
-- @child[i]\align!
@header\align!
@title\align!
@window_area\align!
@window_area\move nil, @header\getHeight!
return @
setSize: (w, h) =>
x = 0
y = 0
if w
switch @data.horizontal
when "center"
x -= (w - @data.w) / 2
when "right"
x -= w - @data.w
-- close button stuff
@header\setWidth w
@window_area\setWidth w
@data.w = w
@data.x += x
@title\align!
-- close button stuff 2 ?
if h
switch @data.vertical
when "center"
y -= (h - @data.h) / 2
when "right"
y -= h - @data.h
@window_area\setHeight h - @header\getHeight!
@window_area\move nil, @header\getHeight!
@data.h = h
@data.y += y
@header\move x, y
@window_area\move x, y
return @
setWidth: (w) =>
return @setSize w
setHeight: (h) =>
return @setSize nil, h