OpenTTD Source 20260711-master-g3fb3006dff
music_gui.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD 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, version 2.
4 * OpenTTD 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.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "openttd.h"
12#include "base_media_base.h"
13#include "base_media_music.h"
15#include "window_gui.h"
16#include "strings_func.h"
17#include "window_func.h"
18#include "sound_func.h"
19#include "gfx_func.h"
20#include "zoom_func.h"
21#include "core/random_func.hpp"
22#include "error.h"
24#include "string_func.h"
25#include "settings_type.h"
26#include "settings_gui.h"
27#include "dropdown_func.h"
28#include "dropdown_type.h"
29#include "slider_func.h"
30#include "mixer.h"
31
33
34#include "table/strings.h"
35#include "table/sprites.h"
36
37#include "safeguards.h"
38
39
41 struct PlaylistEntry : MusicSongInfo {
42 const MusicSet *set;
43 uint set_index;
44
45 PlaylistEntry(const MusicSet *set, uint set_index) : MusicSongInfo(set->songinfo[set_index]), set(set), set_index(set_index) { }
46 bool IsValid() const { return !this->songname.empty(); }
47 };
48 typedef std::vector<PlaylistEntry> Playlist;
49
50 Playlist active_playlist{};
51 Playlist music_set{};
52
53 PlaylistChoice selected_playlist{};
54
55 void BuildPlaylists();
56
58 void ChangeMusicSet(const std::string &set_name);
59 void Shuffle();
60 void Unshuffle();
61
62 void Play();
63 void Stop();
64 void Next();
65 void Prev();
66 void CheckStatus();
67
68 bool IsPlaying() const;
69 bool IsShuffle() const;
71
72 bool IsCustomPlaylist() const;
73 void PlaylistAdd(size_t song_index);
74 void PlaylistRemove(size_t song_index);
75 void PlaylistClear();
76
77private:
78 uint GetSetIndex();
79 void SetPositionBySetIndex(uint set_index);
80 void ChangePlaylistPosition(int ofs);
81 int playlist_position = 0;
82
84
86};
87
89
90
93{
94 const MusicSet *set = BaseMusic::GetUsedSet();
95
96 /* Clear current playlists */
97 for (auto &playlist : this->standard_playlists) playlist.clear();
98 this->music_set.clear();
99
100 /* Build standard playlists, and a list of available music */
101 for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) {
102 PlaylistEntry entry(set, i);
103 if (!entry.IsValid()) continue;
104
105 this->music_set.push_back(entry);
106
107 /* Add theme song to theme-only playlist */
108 if (i == 0) this->standard_playlists[PlaylistChoice::ThemeOnly].push_back(std::move(entry));
109
110 /* Don't add the theme song to standard playlists */
111 if (i > 0) {
112 this->standard_playlists[PlaylistChoice::All].push_back(entry);
114 this->standard_playlists[theme].push_back(std::move(entry));
115 }
116 }
117
118 /* Load custom playlists
119 * Song index offsets are 1-based, zero indicates invalid/end-of-list value */
120 for (uint i = 0; i < NUM_SONGS_PLAYLIST; i++) {
121 if (_settings_client.music.custom_1[i] > 0 && _settings_client.music.custom_1[i] <= NUM_SONGS_AVAILABLE) {
122 PlaylistEntry entry(set, _settings_client.music.custom_1[i] - 1);
123 if (entry.IsValid()) this->standard_playlists[PlaylistChoice::Custom1].push_back(std::move(entry));
124 }
125 if (_settings_client.music.custom_2[i] > 0 && _settings_client.music.custom_2[i] <= NUM_SONGS_AVAILABLE) {
126 PlaylistEntry entry(set, _settings_client.music.custom_2[i] - 1);
127 if (entry.IsValid()) this->standard_playlists[PlaylistChoice::Custom2].push_back(std::move(entry));
128 }
129 }
130}
131
137{
138 assert(pl < PlaylistChoice::End && pl >= PlaylistChoice::All);
139
140 if (pl != PlaylistChoice::ThemeOnly) _settings_client.music.playlist = pl;
141
142 if (_game_mode != GameMode::Menu || pl == PlaylistChoice::ThemeOnly) {
143 this->selected_playlist = pl;
144 this->active_playlist = this->standard_playlists[this->selected_playlist];
145 this->playlist_position = 0;
146
147 if (_settings_client.music.shuffle) this->Shuffle();
148 if (_settings_client.music.playing) this->Play();
149 }
150
151 InvalidateWindowData(WindowClass::MusicTrackSelection, 0);
152 InvalidateWindowData(WindowClass::Music, 0);
153}
154
159void MusicSystem::ChangeMusicSet(const std::string &set_name)
160{
161 BaseMusic::SetSetByName(set_name);
162 BaseMusic::ini_set = set_name;
163
164 this->BuildPlaylists();
165 this->ChangePlaylist(this->selected_playlist);
166
167 InvalidateWindowData(WindowClass::GameOptions, GameOptionsWindowNumber::GameOptions, 0, true);
168 InvalidateWindowData(WindowClass::MusicTrackSelection, 0, 1, true);
169 InvalidateWindowData(WindowClass::Music, 0, 1, true);
170}
171
177{
178 auto it = std::ranges::find(this->active_playlist, set_index, &PlaylistEntry::set_index);
179 if (it != std::end(this->active_playlist)) this->playlist_position = std::distance(std::begin(this->active_playlist), it);
180}
181
187{
188 return static_cast<size_t>(this->playlist_position) < this->active_playlist.size()
189 ? this->active_playlist[this->playlist_position].set_index
190 : UINT_MAX;
191}
192
197{
198 _settings_client.music.shuffle = true;
199
200 uint set_index = this->GetSetIndex();
201 this->active_playlist = this->standard_playlists[this->selected_playlist];
202 for (size_t i = 0; i < this->active_playlist.size(); i++) {
203 size_t shuffle_index = InteractiveRandom() % (this->active_playlist.size() - i);
204 std::swap(this->active_playlist[i], this->active_playlist[i + shuffle_index]);
205 }
206 this->SetPositionBySetIndex(set_index);
207
208 InvalidateWindowData(WindowClass::MusicTrackSelection, 0);
209 InvalidateWindowData(WindowClass::Music, 0);
210}
211
216{
217 _settings_client.music.shuffle = false;
218
219 uint set_index = this->GetSetIndex();
220 this->active_playlist = this->standard_playlists[this->selected_playlist];
221 this->SetPositionBySetIndex(set_index);
222
223 InvalidateWindowData(WindowClass::MusicTrackSelection, 0);
224 InvalidateWindowData(WindowClass::Music, 0);
225}
226
229{
230 /* Always set the playing flag, even if there is no music */
231 _settings_client.music.playing = true;
233 /* Make sure playlist_position is a valid index, if playlist has changed etc. */
234 this->ChangePlaylistPosition(0);
235
236 /* If there is no music, don't try to play it */
237 if (this->active_playlist.empty()) return;
238
239 MusicSongInfo song = this->active_playlist[this->playlist_position];
240 if (_game_mode == GameMode::Menu && this->selected_playlist == PlaylistChoice::ThemeOnly) song.loop = true;
242
243 InvalidateWindowData(WindowClass::Music, 0);
244}
245
248{
250 _settings_client.music.playing = false;
251
252 InvalidateWindowData(WindowClass::Music, 0);
253}
254
257{
258 this->ChangePlaylistPosition(+1);
259 if (_settings_client.music.playing) this->Play();
260
261 InvalidateWindowData(WindowClass::Music, 0);
262}
263
266{
267 this->ChangePlaylistPosition(-1);
268 if (_settings_client.music.playing) this->Play();
269
270 InvalidateWindowData(WindowClass::Music, 0);
271}
272
275{
276 if ((_game_mode == GameMode::Menu) != (this->selected_playlist == PlaylistChoice::ThemeOnly)) {
277 /* Make sure the theme-only playlist is active when on the title screen, and not during gameplay */
279 }
280 if (this->active_playlist.empty()) return;
281 /* If we were supposed to be playing, but music has stopped, move to next song */
282 if (this->IsPlaying() && !MusicDriver::GetInstance()->IsSongPlaying()) this->Next();
283}
284
290{
291 return _settings_client.music.playing && !this->active_playlist.empty();
292}
293
299{
300 return _settings_client.music.shuffle;
301}
302
308{
309 if (!this->IsPlaying()) return PlaylistEntry(BaseMusic::GetUsedSet(), 0);
310 return this->active_playlist[this->playlist_position];
311}
312
318{
319 return (this->selected_playlist == PlaylistChoice::Custom1) || (this->selected_playlist == PlaylistChoice::Custom2);
320}
321
327void MusicSystem::PlaylistAdd(size_t song_index)
328{
329 if (!this->IsCustomPlaylist()) return;
330
331 /* Pick out song from the music set */
332 if (song_index >= this->music_set.size()) return;
333 PlaylistEntry entry = this->music_set[song_index];
334
335 /* Check for maximum length */
336 if (this->standard_playlists[this->selected_playlist].size() >= NUM_SONGS_PLAYLIST) return;
337
338 /* Add it to the appropriate playlist, and the display */
339 this->standard_playlists[this->selected_playlist].push_back(entry);
340
341 /* Add it to the active playlist, if playback is shuffled select a random position to add at */
342 if (this->active_playlist.empty()) {
343 this->active_playlist.push_back(std::move(entry));
344 if (this->IsPlaying()) this->Play();
345 } else if (this->IsShuffle()) {
346 /* Generate a random position between 0 and n (inclusive, new length) to insert at */
347 size_t maxpos = this->active_playlist.size() + 1;
348 size_t newpos = InteractiveRandom() % maxpos;
349 this->active_playlist.insert(this->active_playlist.begin() + newpos, entry);
350 /* Make sure to shift up the current playback position if the song was inserted before it */
351 if ((int)newpos <= this->playlist_position) this->playlist_position++;
352 } else {
353 this->active_playlist.push_back(std::move(entry));
354 }
355
356 this->SaveCustomPlaylist(this->selected_playlist);
357
358 InvalidateWindowData(WindowClass::MusicTrackSelection, 0);
359}
360
365void MusicSystem::PlaylistRemove(size_t song_index)
366{
367 if (!this->IsCustomPlaylist()) return;
368
369 if (song_index >= this->active_playlist.size()) return;
370
371 PlaylistEntry song = this->active_playlist[song_index];
372 this->active_playlist.erase(std::next(std::begin(this->active_playlist), song_index));
373
374 Playlist &playlist = this->standard_playlists[this->selected_playlist];
375 auto it = std::end(playlist);
376 if (this->IsShuffle()) {
377 /* Playlist is shuffled, so remove the first instance. */
378 it = std::ranges::find_if(playlist, [&song](const auto &s) { return s.filename == song.filename && s.cat_index == song.cat_index; });
379 } else if (song_index < playlist.size()) {
380 /* Not shuffled, we can remove the entry directly. */
381 it = std::next(std::begin(playlist), song_index);
382 }
383
384 if (it == std::end(playlist)) return;
385 it = playlist.erase(it);
386
387 /* If it's the current song restart playback. */
388 if (this->IsPlaying() && std::distance(std::begin(playlist), it) == this->playlist_position) this->Play();
389
390 this->SaveCustomPlaylist(this->selected_playlist);
391
392 InvalidateWindowData(WindowClass::MusicTrackSelection, 0);
393}
394
400{
401 if (!this->IsCustomPlaylist()) return;
402
403 this->standard_playlists[this->selected_playlist].clear();
404 this->ChangePlaylist(this->selected_playlist);
405
406 this->SaveCustomPlaylist(this->selected_playlist);
407}
408
415{
416 if (this->active_playlist.empty()) {
417 this->playlist_position = 0;
418 } else {
419 this->playlist_position += ofs;
420 while (this->playlist_position >= (int)this->active_playlist.size()) this->playlist_position -= (int)this->active_playlist.size();
421 while (this->playlist_position < 0) this->playlist_position += (int)this->active_playlist.size();
422 }
423}
424
430{
431 uint8_t *settings_pl;
432 if (pl == PlaylistChoice::Custom1) {
433 settings_pl = _settings_client.music.custom_1;
434 } else if (pl == PlaylistChoice::Custom2) {
435 settings_pl = _settings_client.music.custom_2;
436 } else {
437 return;
438 }
439
440 size_t num = 0;
441 std::fill_n(settings_pl, NUM_SONGS_PLAYLIST, 0);
442
443 for (const auto &song : this->standard_playlists[pl]) {
444 /* Music set indices in the settings playlist are 1-based, 0 means unused slot */
445 settings_pl[num++] = (uint8_t)song.set_index + 1;
446 }
447}
448
449
455{
456 _music.CheckStatus();
457}
458
463void ChangeMusicSet(int index)
464{
465 if (BaseMusic::GetIndexOfUsedSet() == index) return;
466 _music.ChangeMusicSet(BaseMusic::GetSet(index)->name);
467}
468
474{
475 _music.BuildPlaylists();
476}
477
483static bool IsCustomPlaylist(PlaylistChoice playlist)
484{
485 return playlist == PlaylistChoice::Custom1 || playlist == PlaylistChoice::Custom2;
486}
487
488struct MusicTrackSelectionWindow : public Window {
489 MusicTrackSelectionWindow(WindowDesc &desc, WindowNumber number) : Window(desc)
490 {
491 this->InitNested(number);
495 this->LowerWidget(WID_MTS_ALL + to_underlying(_settings_client.music.playlist));
496 }
497
498 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
499 {
500 switch (widget) {
501 case WID_MTS_PLAYLIST:
502 return GetString(STR_PLAYLIST_PROGRAM, STR_MUSIC_PLAYLIST_ALL + to_underlying(_settings_client.music.playlist));
503
504 case WID_MTS_CAPTION:
505 return GetString(STR_PLAYLIST_MUSIC_SELECTION_SETNAME, BaseMusic::GetUsedSet()->name);
506
507 default:
508 return this->Window::GetWidgetString(widget, stringid);
509 }
510 }
511
517 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
518 {
519 if (!gui_scope) return;
521 this->SetWidgetLoweredState(WID_MTS_ALL + to_underlying(playlist), playlist == _settings_client.music.playlist);
522 }
524
525 if (data == 1) {
526 this->ReInit();
527 } else {
528 this->SetDirty();
529 }
530 }
531
532 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
533 {
534 switch (widget) {
535 case WID_MTS_PLAYLIST: {
536 Dimension d = {0, 0};
537
538 for (int i = 0; i < 6; i++) {
539 d = maxdim(d, GetStringBoundingBox(GetString(STR_PLAYLIST_PROGRAM, STR_MUSIC_PLAYLIST_ALL + i)));
540 }
541 d.width += padding.width;
542 d.height += padding.height;
543 size = maxdim(size, d);
544 break;
545 }
546
548 Dimension d = {0, 0};
549
550 for (const auto &song : _music.music_set) {
551 d = maxdim(d, GetStringBoundingBox(GetString(STR_PLAYLIST_TRACK_NAME, song.tracknr, 2, song.songname)));
552 }
553 d.height *= std::max(NUM_SONGS_AVAILABLE, NUM_SONGS_PLAYLIST);
554
555 d.width += padding.width;
556 d.height += padding.height;
557 size = maxdim(size, d);
558 break;
559 }
560 }
561 }
562
563 void DrawWidget(const Rect &r, WidgetID widget) const override
564 {
565 switch (widget) {
566 case WID_MTS_LIST_LEFT: {
568
569 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
570 for (const auto &song : _music.music_set) {
571 DrawString(tr, GetString(STR_PLAYLIST_TRACK_NAME, song.tracknr, 2, song.songname));
573 }
574 break;
575 }
576
577 case WID_MTS_LIST_RIGHT: {
579
580 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
581 for (const auto &song : _music.active_playlist) {
582 DrawString(tr, GetString(STR_PLAYLIST_TRACK_NAME, song.tracknr, 2, song.songname));
584 }
585 break;
586 }
587 }
588 }
589
590 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
591 {
592 switch (widget) {
593 case WID_MTS_LIST_LEFT: { // add to playlist
594 int y = this->GetRowFromWidget(pt.y, widget, WidgetDimensions::scaled.framerect.top, GetCharacterHeight(FontSize::Small));
595 _music.PlaylistAdd(y);
596 break;
597 }
598
599 case WID_MTS_LIST_RIGHT: { // remove from playlist
600 int y = this->GetRowFromWidget(pt.y, widget, WidgetDimensions::scaled.framerect.top, GetCharacterHeight(FontSize::Small));
601 _music.PlaylistRemove(y);
602 break;
603 }
604
605 case WID_MTS_MUSICSET: {
606 int selected = 0;
607 ShowDropDownList(this, BuildSetDropDownList<BaseMusic>(&selected), selected, widget, 0, DropDownOption::Filterable);
608 break;
609 }
610
611 case WID_MTS_CLEAR: // clear
612 _music.PlaylistClear();
613 break;
614
615 case WID_MTS_ALL: case WID_MTS_OLD: case WID_MTS_NEW:
616 case WID_MTS_EZY: case WID_MTS_CUSTOM1: case WID_MTS_CUSTOM2: // set playlist
617 _music.ChangePlaylist(static_cast<PlaylistChoice>(widget - WID_MTS_ALL));
618 break;
619 }
620 }
621
622 void OnDropdownSelect(WidgetID widget, int index, int) override
623 {
624 switch (widget) {
625 case WID_MTS_MUSICSET:
626 ChangeMusicSet(index);
627 break;
628 default:
629 NOT_REACHED();
630 }
631 }
632};
633
634static constexpr std::initializer_list<NWidgetPart> _nested_music_track_selection_widgets = {
638 NWidget(WWT_DROPDOWN, Colours::Grey, WID_MTS_MUSICSET), SetStringTip(STR_PLAYLIST_CHANGE_SET, STR_PLAYLIST_TOOLTIP_CHANGE_SET),
639 EndContainer(),
641 NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
642 /* Left panel. */
644 NWidget(WWT_LABEL, Colours::Invalid), SetFill(1, 0), SetStringTip(STR_PLAYLIST_TRACK_INDEX),
645 NWidget(WWT_PANEL, Colours::Grey, WID_MTS_LIST_LEFT), SetFill(1, 1), SetMinimalSize(180, 194), SetToolTip(STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK), EndContainer(),
647 EndContainer(),
648 /* Middle buttons. */
650 NWidget(NWID_SPACER), SetMinimalSize(60, 30), // Space above the first button from the title bar.
651 NWidget(WWT_TEXTBTN, Colours::Grey, WID_MTS_ALL), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM),
652 NWidget(WWT_TEXTBTN, Colours::Grey, WID_MTS_OLD), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC),
653 NWidget(WWT_TEXTBTN, Colours::Grey, WID_MTS_NEW), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC),
654 NWidget(WWT_TEXTBTN, Colours::Grey, WID_MTS_EZY), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE),
655 NWidget(WWT_TEXTBTN, Colours::Grey, WID_MTS_CUSTOM1), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED),
656 NWidget(WWT_TEXTBTN, Colours::Grey, WID_MTS_CUSTOM2), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED),
657 NWidget(NWID_SPACER), SetMinimalSize(0, 16), // Space above 'clear' button
658 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_MTS_CLEAR), SetFill(1, 0), SetStringTip(STR_PLAYLIST_CLEAR, STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1),
660 EndContainer(),
661 /* Right panel. */
664 NWidget(WWT_PANEL, Colours::Grey, WID_MTS_LIST_RIGHT), SetFill(1, 1), SetMinimalSize(180, 194), SetToolTip(STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK), EndContainer(),
666 EndContainer(),
667 EndContainer(),
668 EndContainer(),
669};
670
674 WindowClass::MusicTrackSelection, WindowClass::None,
675 {},
676 _nested_music_track_selection_widgets
677);
678
679static void ShowMusicTrackSelection()
680{
682}
683
684struct MusicWindow : public Window {
685 MusicWindow(WindowDesc &desc, WindowNumber number) : Window(desc)
686 {
687 this->InitNested(number);
688 this->LowerWidget(WID_M_ALL + to_underlying(_settings_client.music.playlist));
690
691 UpdateDisabledButtons();
692 }
693
694 void UpdateDisabledButtons()
695 {
696 /* Disable stop and play if there is no music. */
698 /* Disable most music control widgets if there is no music, or we are in the intro menu. */
700 BaseMusic::GetUsedSet()->num_available == 0 || _game_mode == GameMode::Menu,
703 );
704 /* Also disable programme button in the intro menu (not in game; it is desirable to allow change of music set.) */
706 }
707
708 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
709 {
710 switch (widget) {
711 /* Make sure that WID_M_SHUFFLE and WID_M_PROGRAMME have the same size.
712 * This can't be done by using NWidContainerFlag::EqualSize as the WID_M_INFO is
713 * between those widgets and of different size. */
714 case WID_M_SHUFFLE: case WID_M_PROGRAMME: {
715 Dimension d = maxdim(GetStringBoundingBox(STR_MUSIC_PROGRAM), GetStringBoundingBox(STR_MUSIC_SHUFFLE));
716 d.width += padding.width;
717 d.height += padding.height;
718 size = maxdim(size, d);
719 break;
720 }
721
722 case WID_M_TRACK_NR: {
723 Dimension d = GetStringBoundingBox(STR_MUSIC_TRACK_NONE);
724 d = maxdim(d, GetStringBoundingBox(GetString(STR_MUSIC_TRACK_DIGIT, GetParamMaxDigits(2, FontSize::Small), 2)));
725 d.width += padding.width;
726 d.height += padding.height + WidgetDimensions::scaled.fullbevel.bottom;
727 size = maxdim(size, d);
728 break;
729 }
730
731 case WID_M_TRACK_NAME: {
732 Dimension d = GetStringBoundingBox(STR_MUSIC_TITLE_NONE);
733 for (const auto &song : _music.music_set) {
734 d = maxdim(d, GetStringBoundingBox(GetString(STR_MUSIC_TITLE_NAME, song.songname)));
735 }
736 d.width += padding.width;
737 d.height += padding.height + WidgetDimensions::scaled.fullbevel.bottom;
738 size = maxdim(size, d);
739 break;
740 }
741
742 /* Hack-ish: set the proper widget data; only needs to be done once
743 * per (Re)Init as that's the only time the language changes. */
747 }
748 }
749
750 void DrawWidget(const Rect &r, WidgetID widget) const override
751 {
752 switch (widget) {
753 case WID_M_TRACK_NR: {
755 if (BaseMusic::GetUsedSet()->num_available == 0) {
756 break;
757 }
758 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
759 if (_music.IsPlaying()) {
760 DrawString(ir, GetString(STR_MUSIC_TRACK_DIGIT, _music.GetCurrentSong().tracknr, 2), TextColour::FromString, AlignmentH::Centre);
761 } else {
762 DrawString(ir, STR_MUSIC_TRACK_NONE, TextColour::FromString, AlignmentH::Centre);
763 }
764 break;
765 }
766
767 case WID_M_TRACK_NAME: {
769 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
770
771 MusicSystem::PlaylistEntry entry(_music.GetCurrentSong());
772 if (BaseMusic::GetUsedSet()->num_available == 0) {
773 DrawString(ir, STR_MUSIC_TITLE_NOMUSIC, TextColour::FromString, AlignmentH::Centre);
774 } else if (_music.IsPlaying()) {
775 DrawString(ir, GetString(STR_MUSIC_TITLE_NAME, entry.songname), TextColour::FromString, AlignmentH::Centre);
776 } else {
777 DrawString(ir, STR_MUSIC_TITLE_NONE, TextColour::FromString, AlignmentH::Centre);
778 }
779
780 break;
781 }
782
783 case WID_M_MUSIC_VOL:
784 DrawSliderWidget(r, Colours::Grey, Colours::Grey, TextColour::Black, 0, INT8_MAX, 0, _settings_client.music.music_vol, nullptr);
785 break;
786
787 case WID_M_EFFECT_VOL:
788 DrawSliderWidget(r, Colours::Grey, Colours::Grey, TextColour::Black, 0, INT8_MAX, 0, _settings_client.music.effect_vol, nullptr);
789 break;
790 }
791 }
792
798 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
799 {
800 if (!gui_scope) return;
802 this->SetWidgetLoweredState(WID_M_ALL + to_underlying(playlist), playlist == _settings_client.music.playlist);
803 }
804
805 UpdateDisabledButtons();
806
807 if (data == 1) {
808 this->ReInit();
809 } else {
810 this->SetDirty();
811 }
812 }
813
814 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
815 {
816 switch (widget) {
817 case WID_M_PREV: // skip to prev
818 _music.Prev();
819 break;
820
821 case WID_M_NEXT: // skip to next
822 _music.Next();
823 break;
824
825 case WID_M_STOP: // stop playing
826 _music.Stop();
827 break;
828
829 case WID_M_PLAY: // start playing
830 _music.Play();
831 break;
832
833 case WID_M_MUSIC_VOL: case WID_M_EFFECT_VOL: { // volume sliders
834 uint8_t &vol = (widget == WID_M_MUSIC_VOL) ? _settings_client.music.music_vol : _settings_client.music.effect_vol;
835 if (ClickSliderWidget(this->GetWidget<NWidgetBase>(widget)->GetCurrentRect(), pt, 0, INT8_MAX, 0, vol)) {
836 if (widget == WID_M_MUSIC_VOL) {
838 } else {
839 SetEffectVolume(vol);
840 }
841 this->SetWidgetDirty(widget);
842 SetWindowClassesDirty(WindowClass::GameOptions);
843 }
844
845 if (click_count > 0) this->mouse_capture_widget = widget;
846 break;
847 }
848
849 case WID_M_SHUFFLE: // toggle shuffle
850 if (_music.IsShuffle()) {
851 _music.Unshuffle();
852 } else {
853 _music.Shuffle();
854 }
855 this->SetWidgetLoweredState(WID_M_SHUFFLE, _music.IsShuffle());
857 break;
858
859 case WID_M_PROGRAMME: // show track selection
860 ShowMusicTrackSelection();
861 break;
862
863 case WID_M_ALL: case WID_M_OLD: case WID_M_NEW:
864 case WID_M_EZY: case WID_M_CUSTOM1: case WID_M_CUSTOM2: // playlist
865 _music.ChangePlaylist(static_cast<PlaylistChoice>(widget - WID_M_ALL));
866 break;
867 }
868 }
869};
870
871static constexpr std::initializer_list<NWidgetPart> _nested_music_window_widgets = {
874 NWidget(WWT_CAPTION, Colours::Grey), SetStringTip(STR_MUSIC_JAZZ_JUKEBOX_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
877 EndContainer(),
878
884 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_M_NEXT), SetToolbarMinimalSize(1), SetSpriteTip(SPR_IMG_SKIP_TO_NEXT, STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION),
887 EndContainer(),
889 EndContainer(),
893 NWidget(WWT_LABEL, Colours::Invalid), SetFill(1, 0), SetStringTip(STR_MUSIC_MUSIC_VOLUME),
894 NWidget(WWT_EMPTY, Colours::Invalid, WID_M_MUSIC_VOL), SetMinimalSize(67, 0), SetMinimalTextLines(1, 0), SetFill(1, 0), SetToolTip(STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC),
895 EndContainer(),
897 NWidget(WWT_LABEL, Colours::Invalid), SetFill(1, 0), SetStringTip(STR_MUSIC_EFFECTS_VOLUME),
898 NWidget(WWT_EMPTY, Colours::Invalid, WID_M_EFFECT_VOL), SetMinimalSize(67, 0), SetMinimalTextLines(1, 0), SetFill(1, 0), SetToolTip(STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC),
899 EndContainer(),
900 EndContainer(),
901 EndContainer(),
902 EndContainer(),
906 NWidget(WWT_TEXTBTN, Colours::Grey, WID_M_SHUFFLE), SetMinimalSize(50, 0), SetStringTip(STR_MUSIC_SHUFFLE, STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE),
907 EndContainer(),
911 EndContainer(),
915 EndContainer(),
917 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_M_PROGRAMME), SetMinimalSize(50, 0), SetStringTip(STR_MUSIC_PROGRAM, STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION),
918 EndContainer(),
919 EndContainer(),
920 EndContainer(),
922 NWidget(WWT_TEXTBTN, Colours::Grey, WID_M_ALL), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM),
923 NWidget(WWT_TEXTBTN, Colours::Grey, WID_M_OLD), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC),
924 NWidget(WWT_TEXTBTN, Colours::Grey, WID_M_NEW), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC),
925 NWidget(WWT_TEXTBTN, Colours::Grey, WID_M_EZY), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE),
926 NWidget(WWT_TEXTBTN, Colours::Grey, WID_M_CUSTOM1), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED),
927 NWidget(WWT_TEXTBTN, Colours::Grey, WID_M_CUSTOM2), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED),
928 EndContainer(),
929};
930
933 WindowPosition::Automatic, "music", 0, 0,
934 WindowClass::Music, WindowClass::None,
935 {},
936 _nested_music_window_widgets
937);
938
939void ShowMusicWindow()
940{
942}
Generic functions for replacing base data (graphics, sounds).
Generic functions for replacing base music data.
static const uint NUM_SONGS_AVAILABLE
Maximum number of songs in the full playlist; theme song + the classes.
static const uint NUM_SONGS_CLASS
Maximum number of songs in the 'class' playlists.
static const uint NUM_SONGS_PLAYLIST
Maximum number of songs in the (custom) playlist.
static const MusicSet * GetUsedSet()
static const MusicSet * GetSet(int index)
static int GetIndexOfUsedSet()
static bool SetSetByName(const std::string &name)
static std::string ini_set
The set as saved in the config file.
Iterate a range of enum values.
virtual void StopSong()=0
Stop playing the current song.
static MusicDriver * GetInstance()
Get the currently active instance of the music driver.
virtual void PlaySong(const MusicSongInfo &song)=0
Play a particular song.
virtual void SetVolume(uint8_t vol)=0
Set the volume, if possible.
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:95
static IDirectMusic * _music
The direct music object manages buffers and ports.
Definition dmusic.cpp:189
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options, std::string *const persistent_filter_text)
Show a drop down list.
Definition dropdown.cpp:587
Functions related to the drop down widget.
Types related to the drop down widget.
@ Filterable
Set if the dropdown is filterable.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
Functions related to errors.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:88
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
@ Centre
Align to the centre.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:899
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:116
int DrawString(int left, int right, int top, std::string_view str, ExtendedTextColour colour, Alignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:668
Functions related to the gfx engine.
@ Small
Index of the small font in the font tables.
Definition gfx_type.h:250
@ Invalid
Invalid marker.
Definition gfx_type.h:302
@ Grey
Grey.
Definition gfx_type.h:299
@ FromString
Marker for telling to use the colour from the string.
Definition gfx_type.h:317
@ Black
Black colour.
Definition gfx_type.h:334
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetToolbarMinimalSize(int width)
Widget part function to setting the minimal size for a toolbar button.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FontSize::Normal)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
Widget part function for setting a pre/inter/post ratio.
void SetDirty() const
Mark entire window as dirty (in need of re-paint).
Definition window.cpp:972
#define Point
Macro that prevents name conflicts between included headers.
Functions to mix sound samples.
Base for all music playback.
void MusicLoop()
Check music playback status and start/stop/song-finished.
static WindowDesc _music_window_desc(WindowPosition::Automatic, "music", 0, 0, WindowClass::Music, WindowClass::None, {}, _nested_music_window_widgets)
Window definition for the music window.
static WindowDesc _music_track_selection_desc(WindowPosition::Automatic, {}, 0, 0, WindowClass::MusicTrackSelection, WindowClass::None, {}, _nested_music_track_selection_widgets)
Window definition for the music track selection window.
void ChangeMusicSet(int index)
Change the configured music set and reset playback.
static bool IsCustomPlaylist(PlaylistChoice playlist)
Test if a PlaylistChoice is a custom playlist.
void InitializeMusic()
Prepare the music system for use.
Types related to the music widgets.
@ WID_MTS_OLD
Old button.
@ WID_MTS_CUSTOM2
Custom2 button.
@ WID_MTS_ALL
All button.
@ WID_MTS_CUSTOM1
Custom1 button.
@ WID_MTS_LIST_LEFT
Left button.
@ WID_MTS_EZY
Ezy button.
@ WID_MTS_CLEAR
Clear button.
@ WID_MTS_LIST_RIGHT
Right button.
@ WID_MTS_NEW
New button.
@ WID_MTS_PLAYLIST
Playlist.
@ WID_MTS_MUSICSET
Music set selection.
@ WID_MTS_CAPTION
Window caption.
@ WID_M_PREV
Previous button.
@ WID_M_TRACK_NAME
Track name.
@ WID_M_NEXT
Next button.
@ WID_M_NEW
New button.
@ WID_M_TRACK_TITLE
Track title.
@ WID_M_STOP
Stop button.
@ WID_M_BACKGROUND
Background of the window.
@ WID_M_ALL
All button.
@ WID_M_CUSTOM2
Custom2 button.
@ WID_M_CUSTOM1
Custom1 button.
@ WID_M_TRACK
Track playing.
@ WID_M_OLD
Old button.
@ WID_M_SLIDERS
Sliders.
@ WID_M_SHUFFLE
Shuffle button.
@ WID_M_EZY
Ezy button.
@ WID_M_MUSIC_VOL
Music volume.
@ WID_M_EFFECT_VOL
Effect volume.
@ WID_M_TRACK_NR
Track number.
@ WID_M_PROGRAMME
Program button.
@ WID_M_PLAY
Play button.
Some generic types.
@ Menu
In the main menu.
Definition openttd.h:19
static constexpr PixelColour PC_BLACK
Black palette colour.
Pseudo random number generator.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Functions for setting GUIs.
Types related to global configuration settings.
PlaylistChoice
Playlists.
@ Custom2
Play the second custom playlist.
@ ThemeOnly
Play only the theme music.
@ All
Play all music (except theme).
@ Custom1
Play the first custom playlist.
@ OldStyle
Play "old style" music.
void DrawSliderWidget(Rect r, Colours wedge_colour, Colours handle_colour, TextColour text_colour, int min_value, int max_value, int nmarks, int value, SliderMarkFunc *mark_func)
Draw a slider widget with knob at given value.
Definition slider.cpp:34
bool ClickSliderWidget(Rect r, Point pt, int min_value, int max_value, int nmarks, int &value)
Handle click on a slider widget to change the value.
Definition slider.cpp:94
Functions related to the horizontal slider widget.
Functions related to sound.
This file contains all sprite-related enums and defines.
static const SpriteID SPR_IMG_STOP_MUSIC
Definition sprites.h:1466
static const SpriteID SPR_IMG_PLAY_MUSIC
Definition sprites.h:1467
static const SpriteID SPR_IMG_SKIP_TO_NEXT
Definition sprites.h:1465
static const SpriteID SPR_IMG_PLAY_MUSIC_RTL
Play music button, but then for RTL users.
Definition sprites.h:81
static const SpriteID SPR_IMG_SKIP_TO_PREV
Definition sprites.h:1464
Definition of base types and functions in a cross-platform compatible way.
Functions related to low-level strings.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:218
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
Dimensions (a width and height) of a rectangle in 2D.
All data of a music set.
Metadata about a music track.
std::string songname
name of song displayed in UI
std::string filename
file on disk containing song (when used in MusicSet class)
bool loop
song should play in a tight loop if possible, never ending
int cat_index
entry index in CAT file, for filetype==MTT_MPSMIDI
const MusicSet * set
music set the song comes from
Definition music_gui.cpp:42
uint set_index
index of song in set
Definition music_gui.cpp:43
void CheckStatus()
Check that music is playing if it should, and that appropriate playlist is active for game/main menu.
void ChangeMusicSet(const std::string &set_name)
Change to named music set, and reset playback.
void Shuffle()
Enable shuffle mode.
void Stop()
Stop playback and set flag that we don't intend to play music.
void BuildPlaylists()
Rebuild all playlists for the current music set.
Definition music_gui.cpp:92
void Next()
Skip to next track.
void Play()
Start/restart playback at current song.
bool IsPlaying() const
Is the player getting music right now?
void Unshuffle()
Disable shuffle mode.
void PlaylistRemove(size_t song_index)
Remove a song from a custom playlist.
void ChangePlaylist(PlaylistChoice pl)
Switch to another playlist, or reload the current one.
PlaylistEntry GetCurrentSong() const
Return the current song, or a dummy if none.
void PlaylistAdd(size_t song_index)
Append a song to a custom playlist.
void ChangePlaylistPosition(int ofs)
Change playlist position pointer by the given offset, making sure to keep it within valid range.
Playlist active_playlist
current play order of songs, including any shuffle
Definition music_gui.cpp:50
void Prev()
Skip to previous track.
void PlaylistClear()
Remove all songs from the current custom playlist.
void SaveCustomPlaylist(PlaylistChoice pl)
Save a custom playlist to settings after modification.
void SetPositionBySetIndex(uint set_index)
Set playlist position by set index.
bool IsCustomPlaylist() const
Is one of the custom playlists selected?
bool IsShuffle() const
Is shuffle mode enabled?
Playlist music_set
all songs in current music set, in set order
Definition music_gui.cpp:51
uint GetSetIndex()
Get set index from current playlist position.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
High level window description.
Definition window_gui.h:172
Number to differentiate different windows of the same class.
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:984
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:562
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:510
WidgetID mouse_capture_widget
ID of current mouse capture widget (e.g. dragged scrollbar). INVALID_WIDGET if no widget has mouse ca...
Definition window_gui.h:326
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:515
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:441
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1838
int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
Definition window.cpp:215
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:989
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:460
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1828
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:381
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition widget_type.h:40
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ WWT_LABEL
Centered label.
Definition widget_type.h:48
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:70
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:44
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX).
Definition widget_type.h:57
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX).
Definition widget_type.h:55
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:37
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
@ EqualSize
Containers should keep all their (resizing) children equally large.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3223
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3315
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ Automatic
Find a place automatically.
Definition window_gui.h:146
int WidgetID
Widget ID.
Definition window_type.h:21
@ GameOptions
Game options.
Definition window_type.h:32
Functions related to zooming.