1 Menu_background_color
= {r
=0.6, g
=0.8, b
=0.6}
2 Menu_border_color
= {r
=0.6, g
=0.7, b
=0.6}
3 Menu_command_color
= {r
=0.2, g
=0.2, b
=0.2}
4 Menu_highlight_color
= {r
=0.5, g
=0.7, b
=0.3}
6 function source
.draw_menu_bar()
7 if App
.run_tests
then return end -- disable in tests
8 App
.color(Menu_background_color
)
9 love
.graphics
.rectangle('fill', 0,0, App
.screen
.width
, Menu_status_bar_height
)
10 App
.color(Menu_border_color
)
11 love
.graphics
.rectangle('line', 0,0, App
.screen
.width
, Menu_status_bar_height
)
12 App
.color(Menu_command_color
)
14 if Show_file_navigator
then
15 source
.draw_file_navigator()
18 add_hotkey_to_menu('ctrl+e: run')
19 if Focus
== 'edit' then
20 add_hotkey_to_menu('ctrl+g: switch file')
21 if Show_log_browser_side
then
22 add_hotkey_to_menu('ctrl+l: hide log browser')
24 add_hotkey_to_menu('ctrl+l: show log browser')
26 add_hotkey_to_menu('ctrl+k: clear logs')
27 if Editor_state
.expanded
then
28 add_hotkey_to_menu('alt+b: collapse debug prints')
30 add_hotkey_to_menu('alt+b: expand debug prints')
32 add_hotkey_to_menu('alt+d: create/edit debug print')
33 add_hotkey_to_menu('ctrl+f: find in file')
34 add_hotkey_to_menu('alt+left alt+right: prev/next word')
35 elseif Focus
== 'log_browser' then
38 assert(false, 'unknown focus "'..Focus
..'"')
40 add_hotkey_to_menu('ctrl+z ctrl+y: undo/redo')
41 add_hotkey_to_menu('ctrl+x ctrl+c ctrl+v: cut/copy/paste')
42 add_hotkey_to_menu('ctrl+= ctrl+- ctrl+0: zoom')
45 function add_hotkey_to_menu(s
)
46 local s_text
= to_text(s
)
47 local width
= App
.width(s_text
)
48 if Menu_cursor
> App
.screen
.width
- 30 then
51 App
.color(Menu_command_color
)
52 App
.screen
.draw(s_text
, Menu_cursor
,5)
53 Menu_cursor
= Menu_cursor
+ width
+ 30
56 function source
.draw_file_navigator()
57 App
.color(Menu_command_color
)
58 local filter_text
= to_text(File_navigation
.filter
)
59 App
.screen
.draw(filter_text
, 5, 5)
60 draw_cursor(5 + App
.width(filter_text
), 5)
61 if File_navigation
.num_lines
== nil then
62 File_navigation
.num_lines
= source
.num_lines_for_file_navigator(File_navigation
.candidates
)
64 App
.color(Menu_background_color
)
65 love
.graphics
.rectangle('fill', 0,Menu_status_bar_height
, App
.screen
.width
, File_navigation
.num_lines
* Editor_state
.line_height
+ --[[highlight padding]] 2)
66 local x
,y
= 5, Menu_status_bar_height
67 for i
,filename
in ipairs(File_navigation
.candidates
) do
68 x
,y
= add_file_to_menu(x
,y
, filename
, i
== File_navigation
.index
)
69 if Menu_cursor
>= App
.screen
.width
- 5 then
75 function draw_cursor(x
, y
)
77 if math
.floor(Cursor_time
*2)%2 == 0 then
78 App
.color(Cursor_color
)
79 love
.graphics
.rectangle('fill', x
,y
, 3,Editor_state
.line_height
)
83 function source
.file_navigator_candidates()
84 if File_navigation
.filter
== '' then
85 return File_navigation
.all_candidates
88 for _
,filename
in ipairs(File_navigation
.all_candidates
) do
89 if starts_with(filename
, File_navigation
.filter
) then
90 table.insert(result
, filename
)
96 function source
.num_lines_for_file_navigator(candidates
)
99 for i
,filename
in ipairs(candidates
) do
100 local width
= App
.width(to_text(filename
))
101 if x
+ width
> App
.screen
.width
- 5 then
111 function add_file_to_menu(x
,y
, s
, cursor_highlight
)
112 local s_text
= to_text(s
)
113 local width
= App
.width(s_text
)
114 if x
+ width
> App
.screen
.width
- 5 then
115 y
= y
+ Editor_state
.line_height
118 local color
= Menu_background_color
119 if cursor_highlight
then
120 color
= Menu_highlight_color
122 button(Editor_state
, 'menu', {x
=x
-5, y
=y
-2, w
=width
+5*2, h
=Editor_state
.line_height
+2*2, color
=colortable(color
),
123 onpress1
= function()
127 App
.color(Menu_command_color
)
128 App
.screen
.draw(s_text
, x
,y
)
133 function navigate_to_file(s
)
134 move_candidate_to_front(s
)
135 local candidate
= guess_source(s
..'.lua')
136 source
.switch_to_file(candidate
)
137 reset_file_navigator()
140 function move_candidate_to_front(s
)
141 local index
= array
.find(File_navigation
.all_candidates
, s
)
143 table.remove(File_navigation
.all_candidates
, index
)
144 table.insert(File_navigation
.all_candidates
, 1, s
)
147 function reset_file_navigator()
148 Show_file_navigator
= false
149 File_navigation
.index
= 1
150 File_navigation
.filter
= ''
151 File_navigation
.candidates
= File_navigation
.all_candidates
154 function keychord_press_on_file_navigator(chord
, key
)
155 log(2, 'file navigator: '..chord
)
156 log(2, {name
='file_navigator_state', files
=File_navigation
.candidates
, index
=File_navigation
.index
})
157 if chord
== 'escape' then
158 reset_file_navigator()
159 elseif chord
== 'return' then
160 navigate_to_file(File_navigation
.candidates
[File_navigation
.index
])
161 elseif chord
== 'backspace' then
162 local len
= utf8
.len(File_navigation
.filter
)
163 local byte_offset
= Text
.offset(File_navigation
.filter
, len
)
164 File_navigation
.filter
= string.sub(File_navigation
.filter
, 1, byte_offset
-1)
165 File_navigation
.index
= 1
166 File_navigation
.candidates
= source
.file_navigator_candidates()
167 elseif chord
== 'left' then
168 if File_navigation
.index
> 1 then
169 File_navigation
.index
= File_navigation
.index
-1
171 elseif chord
== 'right' then
172 if File_navigation
.index
< #File_navigation
.candidates
then
173 File_navigation
.index
= File_navigation
.index
+1
175 elseif chord
== 'down' then
176 file_navigator_down()
177 elseif chord
== 'up' then
182 function log_render
.file_navigator_state(o
, x
,y
, w
)
183 -- duplicate structure of source.draw_file_navigator
184 local num_lines
= source
.num_lines_for_file_navigator(o
.files
)
185 local h
= num_lines
* Editor_state
.line_height
186 App
.color(Menu_background_color
)
187 love
.graphics
.rectangle('fill', x
,y
, w
,h
)
188 -- compute the x,y,width of the current index (in offsets from top left)
191 for i
,filename
in ipairs(o
.files
) do
192 local filename_text
= to_text(filename
)
193 width
= App
.width(filename_text
)
194 if x2
+ width
> App
.screen
.width
- 5 then
195 y2
= y2
+ Editor_state
.line_height
203 -- figure out how much of the menu to display
204 local menu_xmin
= math
.max(0, x2
-w
/2)
205 local menu_xmax
= math
.min(App
.screen
.width
, x2
+w
/2)
206 -- now selectively print out entries
207 local x3
,y3
= 0,y
-- x3 is relative, y3 is absolute
209 for i
,filename
in ipairs(o
.files
) do
210 local filename_text
= to_text(filename
)
211 width
= App
.width(filename_text
)
212 if x3
+ width
> App
.screen
.width
- 5 then
213 y3
= y3
+ Editor_state
.line_height
217 App
.color(Menu_highlight_color
)
218 love
.graphics
.rectangle('fill', x
+ x3
-menu_xmin
- 5, y3
-2, width
+5*2, Editor_state
.line_height
+2*2)
220 if x3
>= menu_xmin
and x3
+ width
< menu_xmax
then
221 App
.color(Menu_command_color
)
222 App
.screen
.draw(filename_text
, x
+ x3
-menu_xmin
, y3
)
230 function file_navigator_up()
231 local y
, x
, width
= file_coord(File_navigation
.index
)
232 local index
= file_index(y
-Editor_state
.line_height
, x
, width
)
234 File_navigation
.index
= index
238 function file_navigator_down()
239 local y
, x
, width
= file_coord(File_navigation
.index
)
240 local index
= file_index(y
+Editor_state
.line_height
, x
, width
)
242 File_navigation
.index
= index
246 function file_coord(index
)
247 local y
,x
= Menu_status_bar_height
, 5
248 for i
,filename
in ipairs(File_navigation
.candidates
) do
249 local width
= App
.width(to_text(filename
))
250 if x
+ width
> App
.screen
.width
- 5 then
251 y
= y
+ Editor_state
.line_height
261 function file_index(fy
, fx
, fwidth
)
262 log_start('file index')
263 log(2, ('for %d %d %d'):format(fy
, fx
, fwidth
))
264 local y
,x
= Menu_status_bar_height
, 5
265 local best_guess
, best_guess_x
, best_guess_width
266 for i
,filename
in ipairs(File_navigation
.candidates
) do
267 local width
= App
.width(to_text(filename
))
268 if x
+ width
> App
.screen
.width
- 5 then
269 y
= y
+ Editor_state
.line_height
273 log(2, ('%d: correct row; considering %d %s %d %d'):format(y
, i
, filename
, x
, width
))
274 if best_guess
== nil then
278 best_guess_width
= width
279 elseif math
.abs(fx
+ fwidth
/2 - x
- width
/2) < math
.abs(fx
+ fwidth
/2 - best_guess_x
- best_guess_width
/2) then
282 best_guess_width
= width
284 log(2, ('best guess now %d %s %d %d'):format(best_guess
, File_navigation
.candidates
[best_guess
], best_guess_x
, best_guess_width
))
288 log_end('file index')
292 function text_input_on_file_navigator(t
)
293 File_navigation
.filter
= File_navigation
.filter
..t
294 File_navigation
.candidates
= source
.file_navigator_candidates()