1--[[ Copyright (c) 2010 Manuel "Roujin" Wolf
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of
4this software and associated documentation files (the "Software"), to deal in
5the Software without restriction, including without limitation the rights to
6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7of the Software, and to permit persons to whom the Software is furnished to do
8so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE. --]]
20
21--! Options window used in the main menu and ingame.
22class "UIOptions" (UIResizable)
23
24---@type UIOptions
25local UIOptions = _G["UIOptions"]
26
27-- Constants for most button's width and height
28local BTN_WIDTH = 135
29local BTN_HEIGHT = 20
30
31local col_bg = {
32  red = 154,
33  green = 146,
34  blue = 198,
35}
36
37local col_textbox = {
38  red = 0,
39  green = 0,
40  blue = 0,
41}
42
43local col_highlight = {
44  red = 174,
45  green = 166,
46  blue = 218,
47}
48
49local col_shadow = {
50  red = 134,
51  green = 126,
52  blue = 178,
53}
54
55local col_caption = {
56  red = 174,
57  green = 166,
58  blue = 218,
59}
60
61-- Private functions
62
63--- Calculates the Y position for the dialog box in the option menu
64-- and increments along the current position for the next element
65-- @return The Y position to place the element at
66
67function UIOptions:_getOptionYPos()
68  -- Offset from top of options box
69  local STARTING_Y_POS = 15
70  -- Y Height is 20 for panel size + 10 for spacing
71  local Y_HEIGHT = 30
72
73  -- Multiply by the index so that index=1 is at STARTING_Y_POS
74  local calculated_pos = STARTING_Y_POS + Y_HEIGHT * (self._current_option_index - 1)
75  self._current_option_index = self._current_option_index + 1
76  return calculated_pos
77end
78
79
80function UIOptions:UIOptions(ui, mode)
81  self:UIResizable(ui, 320, 430, col_bg)
82
83  local app = ui.app
84  self.mode = mode
85  self.modal_class = mode == "menu" and "main menu" or "options"
86  self.on_top = mode == "menu"
87  self.esc_closes = true
88  self.resizable = false
89  self:setDefaultPosition(0.5, 0.25)
90  self.default_button_sound = "selectx.wav"
91  self.app = app
92
93  -- Tracks the current position of the object
94  self._current_option_index = 1
95
96  self:checkForAvailableLanguages()
97
98  -- Set up list of resolutions
99  self.available_resolutions = {
100    {text = "640x480 (4:3)",    width = 640,  height = 480},
101    {text = "800x600 (4:3)",    width = 800,  height = 600},
102    {text = "1024x768 (4:3)",   width = 1024, height = 768},
103    {text = "1280x960 (4:3)",   width = 1280, height = 960},
104    {text = "1600x1200 (4:3)",  width = 1600, height = 1200},
105    {text = "1280x1024 (5:4)",  width = 1280, height = 1024},
106    {text = "1280x720 (16:9)",  width = 1280, height = 720},
107    {text = "1366x768 (16:9)",  width = 1366, height = 768},
108    {text = "1600x900 (16:9)",  width = 1600, height = 900},
109    {text = "1920x1080 (16:9)", width = 1920, height = 1080},
110    {text = "1280x800 (16:10)",  width = 1280, height = 800},
111    {text = "1440x900 (16:10)",  width = 1440, height = 900},
112    {text = "1680x1050 (16:10)",  width = 1680, height = 1050},
113    {text = "1920x1200 (16:10)", width = 1920, height = 1200},
114    {text = _S.options_window.custom_resolution, custom = true},
115  }
116
117  -- Window parts definition
118  -- Title
119  local title_y_pos = self:_getOptionYPos()
120  self:addBevelPanel(80, title_y_pos, 165, 20, col_caption):setLabel(_S.options_window.caption)
121    .lowered = true
122
123  -- Fullscreen
124  local fullscreen_y_pos = self:_getOptionYPos()
125  self:addBevelPanel(20, fullscreen_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg)
126    :setLabel(_S.options_window.fullscreen):setTooltip(_S.tooltip.options_window.fullscreen).lowered = true
127  self.fullscreen_panel =
128    self:addBevelPanel(165, fullscreen_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.fullscreen and _S.options_window.option_on or _S.options_window.option_off)
129  self.fullscreen_button = self.fullscreen_panel:makeToggleButton(0, 0, 140, BTN_HEIGHT, nil, self.buttonFullscreen)
130    :setToggleState(app.fullscreen):setTooltip(_S.tooltip.options_window.fullscreen_button)
131
132  -- Screen resolution
133  local screen_res_y_pos = self:_getOptionYPos()
134  self:addBevelPanel(20, screen_res_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg)
135    :setLabel(_S.options_window.resolution):setTooltip(_S.tooltip.options_window.resolution).lowered = true
136  self.resolution_panel = self:addBevelPanel(165, screen_res_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.config.width .. "x" .. app.config.height)
137
138  self.resolution_button = self.resolution_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.dropdownResolution):setTooltip(_S.tooltip.options_window.select_resolution)
139
140  -- Mouse capture
141  local capture_mouse_y_pos = self:_getOptionYPos()
142  self:addBevelPanel(20, capture_mouse_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg)
143    :setLabel(_S.options_window.capture_mouse):setTooltip(_S.tooltip.options_window.capture_mouse).lowered = true
144
145  self.mouse_capture_panel =
146    self:addBevelPanel(165, capture_mouse_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.config.capture_mouse and _S.options_window.option_on or _S.options_window.option_off)
147
148  self.mouse_capture_button = self.mouse_capture_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.buttonMouseCapture)
149    :setToggleState(app.config.capture_mouse):setTooltip(_S.tooltip.options_window.capture_mouse)
150
151
152  -- Language
153  -- Get language name in the language to normalize display.
154  -- If it doesn't exist, display the current config option.
155  local lang = self.app.strings:getLanguageNames(app.config.language)
156  if lang then
157    lang = lang[1]
158  else
159    lang = app.config.language
160  end
161
162  local lang_y_pos = self:_getOptionYPos()
163  self:addBevelPanel(20, lang_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg)
164    :setLabel(_S.options_window.language):setTooltip(_S.tooltip.options_window.language).lowered = true
165  self.language_panel = self:addBevelPanel(165, lang_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(lang)
166  self.language_button = self.language_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.dropdownLanguage):setTooltip(_S.tooltip.options_window.select_language)
167
168  -- add the Audio global switch.
169  local audio_status = app:isAudioEnabled()
170  local audio_y_pos = self:_getOptionYPos()
171  self:addBevelPanel(20, audio_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg)
172    :setLabel(_S.options_window.audio):setTooltip(_S.tooltip.options_window.audio_button).lowered = true
173  self.volume_panel =
174    self:addBevelPanel(165, audio_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(app.config.audio and audio_status and _S.customise_window.option_on or _S.customise_window.option_off)
175  self.volume_button = self.volume_panel:makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.buttonAudioGlobal)
176    :setToggleState(app.config.audio and audio_status):setTooltip(_S.tooltip.options_window.audio_toggle)
177  self.volume_button.enabled = audio_status
178
179  -- Set scroll speed.
180  local scroll_y_pos = self:_getOptionYPos()
181  self:addBevelPanel(20, scroll_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg) : setLabel(_S.options_window.scrollspeed):setTooltip(_S.tooltip.options_window.scrollspeed).lowered = true
182  self.scrollspeed_panel = self:addBevelPanel(165, scroll_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel(tostring(self.ui.app.config.scroll_speed))
183  self.scrollspeed_button = self.scrollspeed_panel : makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.buttonScrollSpeed) : setTooltip(_S.tooltip.options_window.scrollspeed)
184
185  -- Set shift scroll speed.
186  local shiftscroll_y_pos = self:_getOptionYPos()
187  self:addBevelPanel(20, shiftscroll_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg) : setLabel(_S.options_window.shift_scrollspeed):setTooltip(_S.tooltip.options_window.shift_scrollspeed).lowered = true
188  self.shift_scrollspeed_panel = self:addBevelPanel(165, shiftscroll_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel( tostring(self.ui.app.config.shift_scroll_speed) )
189  self.shift_scrollspeed_button = self.shift_scrollspeed_panel : makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.buttonShiftScrollSpeed) : setTooltip(_S.tooltip.options_window.shift_scrollspeed)
190
191  -- Set zoom speed.
192  local zoom_y_pos = self:_getOptionYPos()
193  self:addBevelPanel(20, zoom_y_pos, BTN_WIDTH, BTN_HEIGHT, col_shadow, col_bg, col_bg) : setLabel(_S.options_window.zoom_speed):setTooltip(_S.tooltip.options_window.zoom_speed).lowered = true
194  self.zoomspeed_panel = self:addBevelPanel(165, zoom_y_pos, BTN_WIDTH, BTN_HEIGHT, col_bg):setLabel( tostring(self.ui.app.config.zoom_speed) )
195  self.zoomspeed_button = self.zoomspeed_panel : makeToggleButton(0, 0, BTN_WIDTH, BTN_HEIGHT, nil, self.buttonZoomSpeed) : setTooltip(_S.tooltip.options_window.zoom_speed)
196
197  -- "Customise" button
198  local customise_y_pos = self:_getOptionYPos()
199  self:addBevelPanel(20, customise_y_pos, BTN_WIDTH, 30, col_bg):setLabel(_S.options_window.customise)
200    :makeButton(0, 0, BTN_WIDTH, 30, nil, self.buttonCustomise):setTooltip(_S.tooltip.options_window.customise_button)
201
202  -- "Folders" button
203  self:addBevelPanel(165, customise_y_pos, BTN_WIDTH, 30, col_bg):setLabel(_S.options_window.folder)
204    :makeButton(0, 0, BTN_WIDTH, 30, nil, self.buttonFolder):setTooltip(_S.tooltip.options_window.folder_button)
205
206  -- "Hotkeys" button
207  local hotkey_y_pos = self:_getOptionYPos() + 10
208  self:addBevelPanel(20, hotkey_y_pos, 280, 40, col_bg):setLabel(_S.options_window.hotkey)
209    :makeButton(0, 0, 280, 40, nil, self.buttonHotkey):setTooltip(_S.tooltip.options_window.hotkey)
210
211  -- "Back" button
212  -- Give some extra space to back button. This is fine as long as it is the last button in the options menu
213  local back_button_y_pos = self:_getOptionYPos() + 30
214  self:addBevelPanel(20, back_button_y_pos, 280, 40, col_bg):setLabel(_S.options_window.back)
215    :makeButton(0, 0, 280, 40, nil, self.buttonBack):setTooltip(_S.tooltip.options_window.back)
216end
217
218-- Stubs for backward compatibility
219local --[[persistable:options_window_language_button]] function language_button() end
220local --[[persistable:options_width_textbox_reset]] function width_textbox_reset() end
221local --[[persistable:options_height_textbox_reset]] function height_textbox_reset() end
222
223function UIOptions:checkForAvailableLanguages()
224  local app = self.app
225  -- Set up list of available languages
226  local langs, c = {}, 1
227  for _, lang in pairs(app.strings.languages) do
228    local font = app.strings:getFont(lang)
229    if app.gfx:hasLanguageFont(font) and app.strings.languages_english[lang] then
230      local eng_name = app.strings.languages_english[lang]
231      c = c + 1
232      font = font and app.gfx:loadLanguageFont(font, app.gfx:loadSpriteTable("QData", "Font01V"))
233      langs[#langs + 1] = { text = lang, font = font,
234      tooltip = { _S.tooltip.options_window.language_dropdown_item:format(eng_name), nil, BTN_HEIGHT * c } }
235    end
236  end
237  self.available_languages = langs
238end
239
240function UIOptions:dropdownLanguage(activate)
241  if activate then
242    self:dropdownResolution(false)
243    self.language_dropdown = UIDropdown(self.ui, self, self.language_button, self.available_languages, self.selectLanguage)
244    self:addWindow(self.language_dropdown)
245  else
246    self.language_button:setToggleState(false)
247    if self.language_dropdown then
248      self.language_dropdown:close()
249      self.language_dropdown = nil
250    end
251  end
252end
253
254function UIOptions:selectLanguage(number)
255  local lang = self.app.strings.languages_english[self.available_languages[number]["text"]]
256  local app = self.ui.app
257  app.config.language = (lang)
258  app:initLanguage()
259  app:saveConfig()
260end
261
262function UIOptions:dropdownResolution(activate)
263  if activate then
264    self:dropdownLanguage(false)
265    self.resolution_dropdown = UIDropdown(self.ui, self, self.resolution_button, self.available_resolutions, self.selectResolution)
266    self:addWindow(self.resolution_dropdown)
267  else
268    self.resolution_button:setToggleState(false)
269    if self.resolution_dropdown then
270      self.resolution_dropdown:close()
271      self.resolution_dropdown = nil
272    end
273  end
274end
275
276function UIOptions:selectResolution(number)
277  local res = self.available_resolutions[number]
278
279  local callback = --[[persistable:options_resolution_callback]] function(width, height)
280    if not self.ui:changeResolution(width, height) then
281      local err = {_S.errors.unavailable_screen_size}
282      self.ui:addWindow(UIInformation(self.ui, err))
283    end
284    self.resolution_panel:setLabel(self.ui.app.config.width .. "x" .. self.ui.app.config.height)
285  end
286
287  if res.custom then
288    self.resolution_panel:setLabel(self.ui.app.config.width .. "x" .. self.ui.app.config.height)
289    self.ui:addWindow(UIResolution(self.ui, callback))
290  else
291    callback(res.width, res.height)
292  end
293end
294
295function UIOptions:buttonFullscreen(checked)
296  if not self.ui:toggleFullscreen() then
297      local err = {_S.errors.unavailable_screen_size}
298      self.ui:addWindow(UIInformation(self.ui, err))
299      self.fullscreen_button:toggle()
300  end
301  self.fullscreen_panel:setLabel(self.ui.app.fullscreen and _S.options_window.option_on or _S.options_window.option_off)
302end
303
304function UIOptions:buttonMouseCapture(checked)
305  local app = self.ui.app
306  app.config.capture_mouse = not app.config.capture_mouse
307  app:saveConfig()
308  app:setCaptureMouse()
309  self.mouse_capture_button:setLabel(app.config.capture_mouse and _S.options_window.option_on or _S.options_window.option_off)
310end
311
312function UIOptions:buttonCustomise()
313  local window = UICustomise(self.ui, "menu")
314  self.ui:addWindow(window)
315end
316
317function UIOptions:buttonFolder()
318  local window = UIFolder(self.ui, "menu")
319  self.ui:addWindow(window)
320end
321
322function UIOptions:buttonHotkey()
323  local window = UIHotkeyAssign(self.ui, "menu")
324  self.ui:addWindow(window)
325end
326
327function UIOptions:buttonBrowseForTHInstall()
328  local function callback(path)
329    local app = TheApp
330    app.config.theme_hospital_install = path
331    app:saveConfig()
332    debug.getregistry()._RESTART = true
333    app.running = false
334  end
335  local browser = UIDirectoryBrowser(self.ui, self.mode, _S.options_window.new_th_directory, "InstallDirTreeNode", callback)
336  self.ui:addWindow(browser)
337end
338
339function UIOptions:buttonAudioGlobal(checked)
340  local app = self.ui.app
341  app.config.audio = not app.config.audio
342  app:saveConfig()
343  self.volume_button:setLabel(app.config.audio and _S.customise_window.option_on or _S.customise_window.option_off)
344  -- Reinit audio
345  app.audio:stopBackgroundTrack()
346  app.audio.has_bg_music = false
347  app.audio.not_loaded = not app.config.audio
348  app.audio.speech_file_name = nil
349  app.audio:init()
350  app:initLanguage()
351end
352
353function UIOptions:buttonScrollSpeed()
354  local callback = function(scrollspeed_number)
355    self.scrollspeed_panel : setLabel(tostring(scrollspeed_number))
356    self.scrollspeed_button : setToggleState(false)
357  end
358
359  self.ui:addWindow(UIScrollSpeed(self.ui, callback))
360end
361
362function UIOptions:buttonBack()
363  self:close()
364end
365
366function UIOptions:buttonShiftScrollSpeed()
367  local callback = function(shift_scrollspeed_number)
368    self.shift_scrollspeed_panel : setLabel( tostring(shift_scrollspeed_number) )
369    self.shift_scrollspeed_button : setToggleState(false)
370  end
371
372  self.ui:addWindow(UIShiftScrollSpeed(self.ui, callback))
373end
374
375function UIOptions:buttonBack()
376  self:close()
377end
378
379function UIOptions:buttonZoomSpeed()
380  local callback = function(zoomspeed_number)
381    self.zoomspeed_panel : setLabel( tostring(zoomspeed_number) )
382    self.zoomspeed_button : setToggleState(false)
383  end
384
385  self.ui:addWindow( UIZoomSpeed(self.ui, callback) )
386end
387
388function UIOptions:close()
389  UIResizable.close(self)
390  if self.mode == "menu" then
391    self.ui:addWindow(UIMainMenu(self.ui))
392  end
393end
394
395--! A custom resolution selection window
396class "UIResolution" (UIResizable)
397
398---@type UIResolution
399local UIResolution = _G["UIResolution"]
400
401function UIResolution:UIResolution(ui, callback)
402  self:UIResizable(ui, 200, 140, col_bg)
403
404  local app = ui.app
405  self.modal_class = "resolution"
406  self.on_top = true
407  self.esc_closes = true
408  self.resizable = false
409  self:setDefaultPosition(0.5, 0.5)
410  self.default_button_sound = "selectx.wav"
411
412  self.callback = callback
413
414  -- Window parts definition
415  -- Title
416  self:addBevelPanel(20, 10, 160, 20, col_caption):setLabel(_S.options_window.resolution)
417    .lowered = true
418
419  -- Textboxes
420  self:addBevelPanel(20, 40, 80, 20, col_shadow, col_bg, col_bg):setLabel(_S.options_window.width)
421  self.width_textbox = self:addBevelPanel(100, 40, 80, 20, col_textbox, col_highlight, col_shadow)
422    :setTooltip(_S.tooltip.options_window.width)
423    :makeTextbox():allowedInput("numbers"):characterLimit(4):setText(tostring(app.config.width))
424
425  self:addBevelPanel(20, 60, 80, 20, col_shadow, col_bg, col_bg):setLabel(_S.options_window.height)
426  self.height_textbox = self:addBevelPanel(100, 60, 80, 20, col_textbox, col_highlight, col_shadow)
427    :setTooltip(_S.tooltip.options_window.height)
428    :makeTextbox():allowedInput("numbers"):characterLimit(4):setText(tostring(app.config.height))
429
430  -- Apply and cancel
431  self:addBevelPanel(20, 90, 80, 40, col_bg):setLabel(_S.options_window.apply)
432    :makeButton(0, 0, 80, 40, nil, self.ok):setTooltip(_S.tooltip.options_window.apply)
433  self:addBevelPanel(100, 90, 80, 40, col_bg):setLabel(_S.options_window.cancel)
434    :makeButton(0, 0, 80, 40, nil, self.cancel):setTooltip(_S.tooltip.options_window.cancel)
435end
436
437function UIResolution:cancel()
438  self:close(false)
439end
440
441function UIResolution:ok()
442  local width, height = tonumber(self.width_textbox.text) or 0, tonumber(self.height_textbox.text) or 0
443  if width < 640 or height < 480 then
444    local err = {_S.errors.minimum_screen_size}
445    self.ui:addWindow(UIInformation(self.ui, err))
446  elseif width > 3000 or height > 2000 then
447    self.ui:addWindow(UIConfirmDialog(self.ui, false,
448      _S.confirmation.maximum_screen_size,
449      --[[persistable:maximum_screen_size_confirm_dialog]]function()
450      self:close(true)
451      self:close(false)
452      end
453      ))
454  else
455    self:close(true)
456  end
457end
458
459--! Closes the resolution dialog
460--!param ok (boolean or nil) whether the resolution entry was confirmed (true) or aborted (false)
461function UIResolution:close(ok)
462  UIResizable.close(self)
463  if ok and self.callback then
464    self.callback(tonumber(self.width_textbox.text) or 0, tonumber(self.height_textbox.text) or 0)
465  end
466end
467
468--! A window for setting the scroll speed of the camera.
469class "UIScrollSpeed" (UIResizable)
470
471---@type UIScrollSpeed
472local UIScrollSpeed = _G["UIScrollSpeed"]
473
474function UIScrollSpeed:UIScrollSpeed(ui, callback)
475  self:UIResizable(ui, 200, 140, col_bg)
476
477  self.on_top = true
478  self.esc_closes = true
479  self.resizable = false
480  self:setDefaultPosition(0.5, 0.5)
481  self.default_button_sound = "selectx.wav"
482  self.scrollspeed_temp = 2
483
484  self.callback = callback
485
486  self:addBevelPanel(20, 10, 160, 20, col_caption):setLabel(_S.options_window.scrollspeed).lowered = true
487
488  self:addBevelPanel(20, 50, 90, 20, col_shadow, col_bg, col_bg):setLabel(_S.options_window.scrollspeed)
489  --
490  self.scrollspeed_textbox = self:addBevelPanel(110, 50, 70, 20, col_textbox, col_highlight, col_shadow)
491    :setTooltip(_S.tooltip.options_window.scrollspeed)
492    :makeTextbox():allowedInput("numbers"):characterLimit(4):setText(tostring(self.ui.app.config.scroll_speed))
493
494  --Apply and cancel.
495  self:addBevelPanel(20, 90, 80, 40, col_bg):setLabel(_S.options_window.apply)
496    :makeButton(0, 0, 80, 40, nil, self.ok):setTooltip(_S.tooltip.options_window.apply_scrollspeed)
497  self:addBevelPanel(100, 90, 80, 40, col_bg):setLabel(_S.options_window.cancel)
498    :makeButton(0, 0, 80, 40, nil, self.cancel):setTooltip(_S.tooltip.options_window.cancel_scrollspeed)
499end
500
501function UIScrollSpeed:ok()
502  self.scrollspeed_temp = tonumber(self.scrollspeed_textbox.text) or 2
503
504  if self.scrollspeed_temp < 1 then
505    self.scrollspeed_temp = 1
506  elseif self.scrollspeed_temp > 10 then
507    self.scrollspeed_temp = 10
508  end
509
510  self:close(true)
511end
512
513function UIScrollSpeed:cancel()
514  self:close(false)
515end
516
517--!param ok (boolean or nil) whether the resolution entry was confirmed (true) or aborted (false)
518function UIScrollSpeed:close(ok)
519  UIResizable.close(self)
520
521  if ok then
522    self.scrollspeed_textbox.text = self.scrollspeed_temp or 2
523    self.ui.app.config.scroll_speed = self.scrollspeed_textbox.text
524    self.callback(self.scrollspeed_textbox.text)
525  else
526    self.callback(self.ui.app.config.scroll_speed)
527  end
528end
529
530
531--! A window for setting the scroll speed of the camera while pressing the SHIFT key..
532class "UIShiftScrollSpeed" (UIResizable)
533
534---@type UIShiftScrollSpeed
535local UIShiftScrollSpeed = _G["UIShiftScrollSpeed"]
536
537function UIShiftScrollSpeed:UIShiftScrollSpeed(ui, callback)
538  self:UIResizable(ui, 200, 140, col_bg)
539
540  self.on_top = true
541  self.esc_closes = true
542  self.resizable = false
543  self:setDefaultPosition(0.5, 0.5)
544  self.default_button_sound = "selectx.wav"
545  self.shift_scrollspeed_temp = 4
546
547  self.callback = callback
548
549  self:addBevelPanel(20, 10, 160, 20, col_caption):setLabel(_S.options_window.shift_scrollspeed).lowered = true
550
551  self:addBevelPanel(20, 50, 120, 20, col_shadow, col_bg, col_bg):setLabel(_S.options_window.shift_scrollspeed)
552  --
553  self.shift_scrollspeed_textbox = self:addBevelPanel(140, 50, 40, 20, col_textbox, col_highlight, col_shadow)
554    :setTooltip(_S.tooltip.options_window.shift_scrollspeed)
555    :makeTextbox():allowedInput("numbers"):characterLimit(4):setText(tostring(self.ui.app.config.shift_scroll_speed))
556
557  --Apply and cancel.
558  self:addBevelPanel(20, 90, 80, 40, col_bg):setLabel(_S.options_window.apply)
559    :makeButton(0, 0, 80, 40, nil, self.ok):setTooltip(_S.tooltip.options_window.apply_shift_scrollspeed)
560  self:addBevelPanel(100, 90, 80, 40, col_bg):setLabel(_S.options_window.cancel)
561    :makeButton(0, 0, 80, 40, nil, self.cancel):setTooltip(_S.tooltip.options_window.cancel_shift_scrollspeed)
562end
563
564function UIShiftScrollSpeed:ok()
565  self.shift_scrollspeed_temp = tonumber(self.shift_scrollspeed_textbox.text) or 4
566
567  if self.shift_scrollspeed_temp < 1 then
568    self.shift_scrollspeed_temp = 1
569  elseif self.shift_scrollspeed_temp > 10 then
570    self.shift_scrollspeed_temp = 10
571  end
572
573  self:close(true)
574end
575
576function UIShiftScrollSpeed:cancel()
577  self:close(false)
578end
579
580--!param ok (boolean or nil) whether the resolution entry was confirmed (true) or aborted (false)
581function UIShiftScrollSpeed:close(ok)
582  UIResizable.close(self)
583
584  if ok then
585    self.shift_scrollspeed_textbox.text = self.shift_scrollspeed_temp or 4
586    self.ui.app.config.shift_scroll_speed = self.shift_scrollspeed_textbox.text
587    self.callback(self.shift_scrollspeed_textbox.text)
588  else
589    self.callback(self.ui.app.config.shift_scroll_speed)
590  end
591end
592
593--! Window to set the zoom speed of the scroll wheel while in-game.
594class "UIZoomSpeed" (UIResizable)
595
596---@type UIZoomSpeed
597local UIZoomSpeed = _G["UIZoomSpeed"]
598
599function UIZoomSpeed:UIZoomSpeed(ui, callback)
600  self:UIResizable(ui, 200, 140, col_bg)
601
602  self.on_top = true
603  self.esc_closes = true
604  self.resizable = false
605  self:setDefaultPosition(0.5, 0.5)
606  self.default_button_sound = "selectx.wav"
607  self.zoomspeed_temp = 80
608
609  self.callback = callback
610
611  --
612  self:addBevelPanel(20, 10, 160, 20, col_caption):setLabel(_S.options_window.zoom_speed).lowered = true
613
614  --
615  self:addBevelPanel(20, 50, 90, 20, col_shadow, col_bg, col_bg):setLabel(_S.options_window.zoom_speed)
616
617  --
618  self.zoomspeed_textbox = self:addBevelPanel(110, 50, 70, 20, col_textbox, col_highlight, col_shadow)
619    :setTooltip(_S.tooltip.options_window.zoom_speed)
620    :makeTextbox():allowedInput("numbers"):characterLimit(4):setText( tostring(self.ui.app.config.zoom_speed) )
621
622  --Apply and cancel.
623  self:addBevelPanel(20, 90, 80, 40, col_bg):setLabel(_S.options_window.apply)
624    :makeButton(0, 0, 80, 40, nil, self.ok):setTooltip(_S.tooltip.options_window.apply_zoomspeed)
625  self:addBevelPanel(100, 90, 80, 40, col_bg):setLabel(_S.options_window.cancel)
626    :makeButton(0, 0, 80, 40, nil, self.cancel):setTooltip(_S.tooltip.options_window.cancel_zoomspeed)
627end
628
629function UIZoomSpeed:ok()
630  self.zoomspeed_temp = tonumber( self.zoomspeed_textbox.text ) or 80
631
632  if self.zoomspeed_temp < 10 then
633    self.zoomspeed_temp = 10
634  elseif self.zoomspeed_temp > 1000 then
635    self.zoomspeed_temp = 1000
636  end
637
638  self:close(true)
639end
640
641function UIZoomSpeed:cancel()
642  self:close(false)
643end
644
645--!param ok (boolean or nil) whether the resolution entry was confirmed (true) or aborted (false)
646function UIZoomSpeed:close(ok)
647  UIResizable.close(self)
648
649  if ok then
650    self.zoomspeed_textbox.text = self.zoomspeed_temp or 2
651    self.ui.app.config.zoom_speed = self.zoomspeed_textbox.text
652    self.callback(self.zoomspeed_textbox.text)
653  else
654    self.callback(self.ui.app.config.zoom_speed)
655  end
656end