aboutsummaryrefslogtreecommitdiff
path: root/data/core/nagview.lua
blob: 69dd50f0df76629adf0c13c9cb7088b4c5e64404 (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
local core = require "core"
local config = require "core.config"
local common = require "core.common"
local View = require "core.view"
local style = require "core.style"

local BORDER_WIDTH = common.round(2 * SCALE)
local BORDER_PADDING = common.round(5 * SCALE)

local noop = function() end

local NagView = View:extend()

function NagView:new()
  NagView.super.new(self)
  self.size.y = 0
  self.force_focus = false
  self.title = "Warning"
  self.message = ""
  self.options = {}
  self.submit = noop
end

function NagView:get_title()
  return self.title
end

function NagView:each_option()
  return coroutine.wrap(function()
    for i = #self.options, 1, -1 do
      coroutine.yield(i, self.options[i])
    end
  end)
end

function NagView:get_options_height()
  local max = 0
  for _, opt in ipairs(self.options) do
    local lh = style.font:get_height(opt.text)
    if lh > max then max = lh end
  end
  return max
end

function NagView:get_line_height()
  local maxlh = math.max(style.font:get_height(self.message), self:get_options_height())
  return 2 * BORDER_WIDTH + 2 * BORDER_PADDING + maxlh + 2 * style.padding.y
end

function NagView:update()
  NagView.super.update(self)

  local dest = core.active_view == self and self:get_line_height() or 0
  self:move_towards(self.size, "y", dest)
end

function NagView:draw_overlay()
  local ox, oy = self:get_content_offset()
  oy = oy + self.size.y
  local w, h = core.root_view.size.x, core.root_view.size.y - oy
  core.root_view:defer_draw(function()
    renderer.draw_rect(ox, oy, w, h, style.nagbar_dim)
  end)
end

function NagView:each_visible_option()
  return coroutine.wrap(function()
    local halfh = math.floor(self.size.y / 2)
    local ox, oy = self:get_content_offset()
    ox = ox + self.size.x - style.padding.x

    for i, opt in self:each_option() do
      local lw, lh = opt.font:get_width(opt.text), opt.font:get_height(opt.text)
      local bw, bh = (lw + 2 * BORDER_WIDTH + 2 * BORDER_PADDING), (lh + 2 * BORDER_WIDTH + 2 * BORDER_PADDING)
      local halfbh = math.floor(bh / 2)
      local bx, by = math.max(0, ox - bw), math.max(0, oy + halfh - halfbh)
      local fw, fh = bw - 2 * BORDER_WIDTH, bh - 2 * BORDER_WIDTH
      local fx, fy = bx + BORDER_WIDTH, by + BORDER_WIDTH
      coroutine.yield(i, opt, bx,by,bw,bh, fx,fy,fw,fh)
      ox = ox - bw - style.padding.x
    end
  end)
end

function NagView:on_mouse_moved(mx, my, ...)
  NagView.super.on_mouse_moved(self, mx, my, ...)
  local selected = false
  for i, _, x,y,w,h in self:each_visible_option() do
    if mx >= x and my >= y and mx < x + w and my < y + h then
      self.selected = i
      selected = true
      break
    end
  end

  if not selected then self.selected = nil end
end

function NagView:on_mouse_pressed(...)
  if not NagView.super.on_mouse_pressed(self, ...) and self.selected then
    self.force_focus = false
    core.set_active_view(core.last_active_view)
    self.submit(self.options[self.selected])
  end
end

function NagView:draw()
  if self.size.y <= 0 then return end

  self:draw_overlay()
  self:draw_background(style.nagbar)

  -- draw message
  local ox, oy = self:get_content_offset()
  common.draw_text(style.font, style.nagbar_text, self.message, "left", ox + style.padding.x, oy, self.size.x, self.size.y)

  -- draw buttons
  for i, opt, bx,by,bw,bh, fx,fy,fw,fh in self:each_visible_option() do
    local fill = i == self.selected and style.nagbar_text or style.nagbar
    local text_color = i == self.selected and style.nagbar or style.nagbar_text

    renderer.draw_rect(bx,by,bw,bh, style.nagbar_text)

    if i ~= self.selected then
      renderer.draw_rect(fx,fy,fw,fh, fill)
    end

    common.draw_text(opt.font, text_color, opt.text, "center", fx,fy,fw,fh)
  end
end

function NagView:show(title, message, options, on_select, on_cancel)
  self.title = title or "Warning"
  self.message = message or "Empty?"
  self.options = options or {}
  if on_cancel then table.insert(options, { key = "cancel", font = style.icon_font, text = "C" }) end
  self.force_focus = true
  self.submit = function(item)
    self.submit = noop -- reset the submit function
    if item.key == "cancel" and on_cancel then
      on_cancel()
    elseif on_select then
      on_select(item)
    end
  end
  core.set_active_view(self)
end

return NagView