OpenTTD Source 20260218-master-g2123fca5ea
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 enum PlaylistChoices : uint8_t {
51 PLCH_ALLMUSIC,
52 PLCH_OLDSTYLE,
53 PLCH_NEWSTYLE,
54 PLCH_EZYSTREET,
55 PLCH_CUSTOM1,
56 PLCH_CUSTOM2,
57 PLCH_THEMEONLY,
58 PLCH_MAX,
59 };
60
61 Playlist active_playlist{};
62 Playlist music_set{};
63
64 PlaylistChoices selected_playlist{};
65
66 void BuildPlaylists();
67
68 void ChangePlaylist(PlaylistChoices pl);
69 void ChangeMusicSet(const std::string &set_name);
70 void Shuffle();
71 void Unshuffle();
72
73 void Play();
74 void Stop();
75 void Next();
76 void Prev();
77 void CheckStatus();
78
79 bool IsPlaying() const;
80 bool IsShuffle() const;
82
83 bool IsCustomPlaylist() const;
84 void PlaylistAdd(size_t song_index);
85 void PlaylistRemove(size_t song_index);
86 void PlaylistClear();
87
88private:
89 uint GetSetIndex();
90 void SetPositionBySetIndex(uint set_index);
91 void ChangePlaylistPosition(int ofs);
92 int playlist_position = 0;
93
94 void SaveCustomPlaylist(PlaylistChoices pl);
95
96 std::array<Playlist, PLCH_MAX> standard_playlists{};
97};
98
100
101
104{
105 const MusicSet *set = BaseMusic::GetUsedSet();
106
107 /* Clear current playlists */
108 for (auto &playlist : this->standard_playlists) playlist.clear();
109 this->music_set.clear();
110
111 /* Build standard playlists, and a list of available music */
112 for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) {
113 PlaylistEntry entry(set, i);
114 if (!entry.IsValid()) continue;
115
116 this->music_set.push_back(entry);
117
118 /* Add theme song to theme-only playlist */
119 if (i == 0) this->standard_playlists[PLCH_THEMEONLY].push_back(std::move(entry));
120
121 /* Don't add the theme song to standard playlists */
122 if (i > 0) {
123 this->standard_playlists[PLCH_ALLMUSIC].push_back(entry);
124 uint theme = (i - 1) / NUM_SONGS_CLASS;
125 this->standard_playlists[PLCH_OLDSTYLE + theme].push_back(std::move(entry));
126 }
127 }
128
129 /* Load custom playlists
130 * Song index offsets are 1-based, zero indicates invalid/end-of-list value */
131 for (uint i = 0; i < NUM_SONGS_PLAYLIST; i++) {
132 if (_settings_client.music.custom_1[i] > 0 && _settings_client.music.custom_1[i] <= NUM_SONGS_AVAILABLE) {
133 PlaylistEntry entry(set, _settings_client.music.custom_1[i] - 1);
134 if (entry.IsValid()) this->standard_playlists[PLCH_CUSTOM1].push_back(std::move(entry));
135 }
136 if (_settings_client.music.custom_2[i] > 0 && _settings_client.music.custom_2[i] <= NUM_SONGS_AVAILABLE) {
137 PlaylistEntry entry(set, _settings_client.music.custom_2[i] - 1);
138 if (entry.IsValid()) this->standard_playlists[PLCH_CUSTOM2].push_back(std::move(entry));
139 }
140 }
141}
142
147void MusicSystem::ChangePlaylist(PlaylistChoices pl)
148{
149 assert(pl < PLCH_MAX && pl >= PLCH_ALLMUSIC);
150
151 if (pl != PLCH_THEMEONLY) _settings_client.music.playlist = pl;
152
153 if (_game_mode != GM_MENU || pl == PLCH_THEMEONLY) {
154 this->selected_playlist = pl;
155 this->active_playlist = this->standard_playlists[this->selected_playlist];
156 this->playlist_position = 0;
157
158 if (_settings_client.music.shuffle) this->Shuffle();
159 if (_settings_client.music.playing) this->Play();
160 }
161
164}
165
170void MusicSystem::ChangeMusicSet(const std::string &set_name)
171{
172 BaseMusic::SetSetByName(set_name);
173 BaseMusic::ini_set = set_name;
174
175 this->BuildPlaylists();
176 this->ChangePlaylist(this->selected_playlist);
177
181}
182
188{
189 auto it = std::ranges::find(this->active_playlist, set_index, &PlaylistEntry::set_index);
190 if (it != std::end(this->active_playlist)) this->playlist_position = std::distance(std::begin(this->active_playlist), it);
191}
192
198{
199 return static_cast<size_t>(this->playlist_position) < this->active_playlist.size()
200 ? this->active_playlist[this->playlist_position].set_index
201 : UINT_MAX;
202}
203
208{
209 _settings_client.music.shuffle = true;
210
211 uint set_index = this->GetSetIndex();
212 this->active_playlist = this->standard_playlists[this->selected_playlist];
213 for (size_t i = 0; i < this->active_playlist.size(); i++) {
214 size_t shuffle_index = InteractiveRandom() % (this->active_playlist.size() - i);
215 std::swap(this->active_playlist[i], this->active_playlist[i + shuffle_index]);
216 }
217 this->SetPositionBySetIndex(set_index);
218
221}
222
227{
228 _settings_client.music.shuffle = false;
229
230 uint set_index = this->GetSetIndex();
231 this->active_playlist = this->standard_playlists[this->selected_playlist];
232 this->SetPositionBySetIndex(set_index);
233
236}
237
240{
241 /* Always set the playing flag, even if there is no music */
242 _settings_client.music.playing = true;
244 /* Make sure playlist_position is a valid index, if playlist has changed etc. */
245 this->ChangePlaylistPosition(0);
246
247 /* If there is no music, don't try to play it */
248 if (this->active_playlist.empty()) return;
249
250 MusicSongInfo song = this->active_playlist[this->playlist_position];
251 if (_game_mode == GM_MENU && this->selected_playlist == PLCH_THEMEONLY) song.loop = true;
253
255}
256
259{
261 _settings_client.music.playing = false;
262
264}
265
268{
269 this->ChangePlaylistPosition(+1);
270 if (_settings_client.music.playing) this->Play();
271
273}
274
277{
278 this->ChangePlaylistPosition(-1);
279 if (_settings_client.music.playing) this->Play();
280
282}
283
286{
287 if ((_game_mode == GM_MENU) != (this->selected_playlist == PLCH_THEMEONLY)) {
288 /* Make sure the theme-only playlist is active when on the title screen, and not during gameplay */
289 this->ChangePlaylist((_game_mode == GM_MENU) ? PLCH_THEMEONLY : (PlaylistChoices)_settings_client.music.playlist);
290 }
291 if (this->active_playlist.empty()) return;
292 /* If we were supposed to be playing, but music has stopped, move to next song */
293 if (this->IsPlaying() && !MusicDriver::GetInstance()->IsSongPlaying()) this->Next();
294}
295
301{
302 return _settings_client.music.playing && !this->active_playlist.empty();
303}
304
310{
311 return _settings_client.music.shuffle;
312}
313
319{
320 if (!this->IsPlaying()) return PlaylistEntry(BaseMusic::GetUsedSet(), 0);
321 return this->active_playlist[this->playlist_position];
322}
323
329{
330 return (this->selected_playlist == PLCH_CUSTOM1) || (this->selected_playlist == PLCH_CUSTOM2);
331}
332
338void MusicSystem::PlaylistAdd(size_t song_index)
339{
340 if (!this->IsCustomPlaylist()) return;
341
342 /* Pick out song from the music set */
343 if (song_index >= this->music_set.size()) return;
344 PlaylistEntry entry = this->music_set[song_index];
345
346 /* Check for maximum length */
347 if (this->standard_playlists[this->selected_playlist].size() >= NUM_SONGS_PLAYLIST) return;
348
349 /* Add it to the appropriate playlist, and the display */
350 this->standard_playlists[this->selected_playlist].push_back(entry);
351
352 /* Add it to the active playlist, if playback is shuffled select a random position to add at */
353 if (this->active_playlist.empty()) {
354 this->active_playlist.push_back(std::move(entry));
355 if (this->IsPlaying()) this->Play();
356 } else if (this->IsShuffle()) {
357 /* Generate a random position between 0 and n (inclusive, new length) to insert at */
358 size_t maxpos = this->active_playlist.size() + 1;
359 size_t newpos = InteractiveRandom() % maxpos;
360 this->active_playlist.insert(this->active_playlist.begin() + newpos, entry);
361 /* Make sure to shift up the current playback position if the song was inserted before it */
362 if ((int)newpos <= this->playlist_position) this->playlist_position++;
363 } else {
364 this->active_playlist.push_back(std::move(entry));
365 }
366
367 this->SaveCustomPlaylist(this->selected_playlist);
368
370}
371
376void MusicSystem::PlaylistRemove(size_t song_index)
377{
378 if (!this->IsCustomPlaylist()) return;
379
380 if (song_index >= this->active_playlist.size()) return;
381
382 PlaylistEntry song = this->active_playlist[song_index];
383 this->active_playlist.erase(std::next(std::begin(this->active_playlist), song_index));
384
385 Playlist &playlist = this->standard_playlists[this->selected_playlist];
386 auto it = std::end(playlist);
387 if (this->IsShuffle()) {
388 /* Playlist is shuffled, so remove the first instance. */
389 it = std::ranges::find_if(playlist, [&song](const auto &s) { return s.filename == song.filename && s.cat_index == song.cat_index; });
390 } else if (song_index < playlist.size()) {
391 /* Not shuffled, we can remove the entry directly. */
392 it = std::next(std::begin(playlist), song_index);
393 }
394
395 if (it == std::end(playlist)) return;
396 it = playlist.erase(it);
397
398 /* If it's the current song restart playback. */
399 if (this->IsPlaying() && std::distance(std::begin(playlist), it) == this->playlist_position) this->Play();
400
401 this->SaveCustomPlaylist(this->selected_playlist);
402
404}
405
411{
412 if (!this->IsCustomPlaylist()) return;
413
414 this->standard_playlists[this->selected_playlist].clear();
415 this->ChangePlaylist(this->selected_playlist);
416
417 this->SaveCustomPlaylist(this->selected_playlist);
418}
419
426{
427 if (this->active_playlist.empty()) {
428 this->playlist_position = 0;
429 } else {
430 this->playlist_position += ofs;
431 while (this->playlist_position >= (int)this->active_playlist.size()) this->playlist_position -= (int)this->active_playlist.size();
432 while (this->playlist_position < 0) this->playlist_position += (int)this->active_playlist.size();
433 }
434}
435
440void MusicSystem::SaveCustomPlaylist(PlaylistChoices pl)
441{
442 uint8_t *settings_pl;
443 if (pl == PLCH_CUSTOM1) {
444 settings_pl = _settings_client.music.custom_1;
445 } else if (pl == PLCH_CUSTOM2) {
446 settings_pl = _settings_client.music.custom_2;
447 } else {
448 return;
449 }
450
451 size_t num = 0;
452 std::fill_n(settings_pl, NUM_SONGS_PLAYLIST, 0);
453
454 for (const auto &song : this->standard_playlists[pl]) {
455 /* Music set indices in the settings playlist are 1-based, 0 means unused slot */
456 settings_pl[num++] = (uint8_t)song.set_index + 1;
457 }
458}
459
460
466{
467 _music.CheckStatus();
468}
469
474void ChangeMusicSet(int index)
475{
476 if (BaseMusic::GetIndexOfUsedSet() == index) return;
477 _music.ChangeMusicSet(BaseMusic::GetSet(index)->name);
478}
479
485{
486 _music.BuildPlaylists();
487}
488
489
490struct MusicTrackSelectionWindow : public Window {
491 MusicTrackSelectionWindow(WindowDesc &desc, WindowNumber number) : Window(desc)
492 {
493 this->InitNested(number);
496 this->SetWidgetDisabledState(WID_MTS_CLEAR, _settings_client.music.playlist <= 3);
497 this->LowerWidget(WID_MTS_ALL + _settings_client.music.playlist);
498 }
499
500 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
501 {
502 switch (widget) {
503 case WID_MTS_PLAYLIST:
504 return GetString(STR_PLAYLIST_PROGRAM, STR_MUSIC_PLAYLIST_ALL + _settings_client.music.playlist);
505
506 case WID_MTS_CAPTION:
507 return GetString(STR_PLAYLIST_MUSIC_SELECTION_SETNAME, BaseMusic::GetUsedSet()->name);
508
509 default:
510 return this->Window::GetWidgetString(widget, stringid);
511 }
512 }
513
519 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
520 {
521 if (!gui_scope) return;
522 for (int i = 0; i < 6; i++) {
523 this->SetWidgetLoweredState(WID_MTS_ALL + i, i == _settings_client.music.playlist);
524 }
525 this->SetWidgetDisabledState(WID_MTS_CLEAR, _settings_client.music.playlist <= 3);
526
527 if (data == 1) {
528 this->ReInit();
529 } else {
530 this->SetDirty();
531 }
532 }
533
534 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
535 {
536 switch (widget) {
537 case WID_MTS_PLAYLIST: {
538 Dimension d = {0, 0};
539
540 for (int i = 0; i < 6; i++) {
541 d = maxdim(d, GetStringBoundingBox(GetString(STR_PLAYLIST_PROGRAM, STR_MUSIC_PLAYLIST_ALL + i)));
542 }
543 d.width += padding.width;
544 d.height += padding.height;
545 size = maxdim(size, d);
546 break;
547 }
548
550 Dimension d = {0, 0};
551
552 for (const auto &song : _music.music_set) {
553 d = maxdim(d, GetStringBoundingBox(GetString(STR_PLAYLIST_TRACK_NAME, song.tracknr, 2, song.songname)));
554 }
555 d.height *= std::max(NUM_SONGS_AVAILABLE, NUM_SONGS_PLAYLIST);
556
557 d.width += padding.width;
558 d.height += padding.height;
559 size = maxdim(size, d);
560 break;
561 }
562 }
563 }
564
565 void DrawWidget(const Rect &r, WidgetID widget) const override
566 {
567 switch (widget) {
568 case WID_MTS_LIST_LEFT: {
570
571 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
572 for (const auto &song : _music.music_set) {
573 DrawString(tr, GetString(STR_PLAYLIST_TRACK_NAME, song.tracknr, 2, song.songname));
574 tr.top += GetCharacterHeight(FS_SMALL);
575 }
576 break;
577 }
578
579 case WID_MTS_LIST_RIGHT: {
581
582 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
583 for (const auto &song : _music.active_playlist) {
584 DrawString(tr, GetString(STR_PLAYLIST_TRACK_NAME, song.tracknr, 2, song.songname));
585 tr.top += GetCharacterHeight(FS_SMALL);
586 }
587 break;
588 }
589 }
590 }
591
592 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
593 {
594 switch (widget) {
595 case WID_MTS_LIST_LEFT: { // add to playlist
596 int y = this->GetRowFromWidget(pt.y, widget, WidgetDimensions::scaled.framerect.top, GetCharacterHeight(FS_SMALL));
597 _music.PlaylistAdd(y);
598 break;
599 }
600
601 case WID_MTS_LIST_RIGHT: { // remove from playlist
602 int y = this->GetRowFromWidget(pt.y, widget, WidgetDimensions::scaled.framerect.top, GetCharacterHeight(FS_SMALL));
603 _music.PlaylistRemove(y);
604 break;
605 }
606
607 case WID_MTS_MUSICSET: {
608 int selected = 0;
609 ShowDropDownList(this, BuildSetDropDownList<BaseMusic>(&selected), selected, widget);
610 break;
611 }
612
613 case WID_MTS_CLEAR: // clear
614 _music.PlaylistClear();
615 break;
616
617 case WID_MTS_ALL: case WID_MTS_OLD: case WID_MTS_NEW:
618 case WID_MTS_EZY: case WID_MTS_CUSTOM1: case WID_MTS_CUSTOM2: // set playlist
619 _music.ChangePlaylist((MusicSystem::PlaylistChoices)(widget - WID_MTS_ALL));
620 break;
621 }
622 }
623
624 void OnDropdownSelect(WidgetID widget, int index, int) override
625 {
626 switch (widget) {
627 case WID_MTS_MUSICSET:
628 ChangeMusicSet(index);
629 break;
630 default:
631 NOT_REACHED();
632 }
633 }
634};
635
636static constexpr std::initializer_list<NWidgetPart> _nested_music_track_selection_widgets = {
638 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
639 NWidget(WWT_CAPTION, COLOUR_GREY, WID_MTS_CAPTION),
640 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_MTS_MUSICSET), SetStringTip(STR_PLAYLIST_CHANGE_SET, STR_PLAYLIST_TOOLTIP_CHANGE_SET),
641 EndContainer(),
642 NWidget(WWT_PANEL, COLOUR_GREY),
643 NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
644 /* Left panel. */
646 NWidget(WWT_LABEL, INVALID_COLOUR), SetFill(1, 0), SetStringTip(STR_PLAYLIST_TRACK_INDEX),
647 NWidget(WWT_PANEL, COLOUR_GREY, WID_MTS_LIST_LEFT), SetFill(1, 1), SetMinimalSize(180, 194), SetToolTip(STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK), EndContainer(),
649 EndContainer(),
650 /* Middle buttons. */
652 NWidget(NWID_SPACER), SetMinimalSize(60, 30), // Space above the first button from the title bar.
653 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_ALL), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM),
654 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_OLD), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC),
655 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_NEW), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC),
656 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_EZY), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE),
657 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM1), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED),
658 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM2), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED),
659 NWidget(NWID_SPACER), SetMinimalSize(0, 16), // Space above 'clear' button
660 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_MTS_CLEAR), SetFill(1, 0), SetStringTip(STR_PLAYLIST_CLEAR, STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1),
662 EndContainer(),
663 /* Right panel. */
665 NWidget(WWT_LABEL, INVALID_COLOUR, WID_MTS_PLAYLIST), SetFill(1, 0),
666 NWidget(WWT_PANEL, COLOUR_GREY, WID_MTS_LIST_RIGHT), SetFill(1, 1), SetMinimalSize(180, 194), SetToolTip(STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK), EndContainer(),
668 EndContainer(),
669 EndContainer(),
670 EndContainer(),
671};
672
673static WindowDesc _music_track_selection_desc(
674 WDP_AUTO, {}, 0, 0,
676 {},
677 _nested_music_track_selection_widgets
678);
679
680static void ShowMusicTrackSelection()
681{
682 AllocateWindowDescFront<MusicTrackSelectionWindow>(_music_track_selection_desc, 0);
683}
684
685struct MusicWindow : public Window {
686 MusicWindow(WindowDesc &desc, WindowNumber number) : Window(desc)
687 {
688 this->InitNested(number);
689 this->LowerWidget(_settings_client.music.playlist + WID_M_ALL);
691
692 UpdateDisabledButtons();
693 }
694
695 void UpdateDisabledButtons()
696 {
697 /* Disable stop and play if there is no music. */
699 /* Disable most music control widgets if there is no music, or we are in the intro menu. */
701 BaseMusic::GetUsedSet()->num_available == 0 || _game_mode == GM_MENU,
704 );
705 /* Also disable programme button in the intro menu (not in game; it is desirable to allow change of music set.) */
706 this->SetWidgetsDisabledState(_game_mode == GM_MENU, WID_M_PROGRAMME);
707 }
708
709 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
710 {
711 switch (widget) {
712 /* Make sure that WID_M_SHUFFLE and WID_M_PROGRAMME have the same size.
713 * This can't be done by using NWidContainerFlag::EqualSize as the WID_M_INFO is
714 * between those widgets and of different size. */
715 case WID_M_SHUFFLE: case WID_M_PROGRAMME: {
716 Dimension d = maxdim(GetStringBoundingBox(STR_MUSIC_PROGRAM), GetStringBoundingBox(STR_MUSIC_SHUFFLE));
717 d.width += padding.width;
718 d.height += padding.height;
719 size = maxdim(size, d);
720 break;
721 }
722
723 case WID_M_TRACK_NR: {
724 Dimension d = GetStringBoundingBox(STR_MUSIC_TRACK_NONE);
725 d = maxdim(d, GetStringBoundingBox(GetString(STR_MUSIC_TRACK_DIGIT, GetParamMaxDigits(2, FS_SMALL), 2)));
726 d.width += padding.width;
727 d.height += padding.height + WidgetDimensions::scaled.fullbevel.bottom;
728 size = maxdim(size, d);
729 break;
730 }
731
732 case WID_M_TRACK_NAME: {
733 Dimension d = GetStringBoundingBox(STR_MUSIC_TITLE_NONE);
734 for (const auto &song : _music.music_set) {
735 d = maxdim(d, GetStringBoundingBox(GetString(STR_MUSIC_TITLE_NAME, song.songname)));
736 }
737 d.width += padding.width;
738 d.height += padding.height + WidgetDimensions::scaled.fullbevel.bottom;
739 size = maxdim(size, d);
740 break;
741 }
742
743 /* Hack-ish: set the proper widget data; only needs to be done once
744 * per (Re)Init as that's the only time the language changes. */
745 case WID_M_PREV: this->GetWidget<NWidgetCore>(WID_M_PREV)->SetSprite(_current_text_dir == TD_RTL ? SPR_IMG_SKIP_TO_NEXT : SPR_IMG_SKIP_TO_PREV); break;
746 case WID_M_NEXT: this->GetWidget<NWidgetCore>(WID_M_NEXT)->SetSprite(_current_text_dir == TD_RTL ? SPR_IMG_SKIP_TO_PREV : SPR_IMG_SKIP_TO_NEXT); break;
747 case WID_M_PLAY: this->GetWidget<NWidgetCore>(WID_M_PLAY)->SetSprite(_current_text_dir == TD_RTL ? SPR_IMG_PLAY_MUSIC_RTL : SPR_IMG_PLAY_MUSIC); break;
748 }
749 }
750
751 void DrawWidget(const Rect &r, WidgetID widget) const override
752 {
753 switch (widget) {
754 case WID_M_TRACK_NR: {
756 if (BaseMusic::GetUsedSet()->num_available == 0) {
757 break;
758 }
759 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
760 if (_music.IsPlaying()) {
761 DrawString(ir, GetString(STR_MUSIC_TRACK_DIGIT, _music.GetCurrentSong().tracknr, 2), TC_FROMSTRING, SA_HOR_CENTER);
762 } else {
763 DrawString(ir, STR_MUSIC_TRACK_NONE, TC_FROMSTRING, SA_HOR_CENTER);
764 }
765 break;
766 }
767
768 case WID_M_TRACK_NAME: {
770 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
771
772 MusicSystem::PlaylistEntry entry(_music.GetCurrentSong());
773 if (BaseMusic::GetUsedSet()->num_available == 0) {
774 DrawString(ir, STR_MUSIC_TITLE_NOMUSIC, TC_FROMSTRING, SA_HOR_CENTER);
775 } else if (_music.IsPlaying()) {
776 DrawString(ir, GetString(STR_MUSIC_TITLE_NAME, entry.songname), TC_FROMSTRING, SA_HOR_CENTER);
777 } else {
778 DrawString(ir, STR_MUSIC_TITLE_NONE, TC_FROMSTRING, SA_HOR_CENTER);
779 }
780
781 break;
782 }
783
784 case WID_M_MUSIC_VOL:
785 DrawSliderWidget(r, COLOUR_GREY, COLOUR_GREY, TC_BLACK, 0, INT8_MAX, 0, _settings_client.music.music_vol, nullptr);
786 break;
787
788 case WID_M_EFFECT_VOL:
789 DrawSliderWidget(r, COLOUR_GREY, COLOUR_GREY, TC_BLACK, 0, INT8_MAX, 0, _settings_client.music.effect_vol, nullptr);
790 break;
791 }
792 }
793
799 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
800 {
801 if (!gui_scope) return;
802 for (int i = 0; i < 6; i++) {
803 this->SetWidgetLoweredState(WID_M_ALL + i, i == _settings_client.music.playlist);
804 }
805
806 UpdateDisabledButtons();
807
808 if (data == 1) {
809 this->ReInit();
810 } else {
811 this->SetDirty();
812 }
813 }
814
815 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
816 {
817 switch (widget) {
818 case WID_M_PREV: // skip to prev
819 _music.Prev();
820 break;
821
822 case WID_M_NEXT: // skip to next
823 _music.Next();
824 break;
825
826 case WID_M_STOP: // stop playing
827 _music.Stop();
828 break;
829
830 case WID_M_PLAY: // start playing
831 _music.Play();
832 break;
833
834 case WID_M_MUSIC_VOL: case WID_M_EFFECT_VOL: { // volume sliders
835 uint8_t &vol = (widget == WID_M_MUSIC_VOL) ? _settings_client.music.music_vol : _settings_client.music.effect_vol;
836 if (ClickSliderWidget(this->GetWidget<NWidgetBase>(widget)->GetCurrentRect(), pt, 0, INT8_MAX, 0, vol)) {
837 if (widget == WID_M_MUSIC_VOL) {
839 } else {
840 SetEffectVolume(vol);
841 }
842 this->SetWidgetDirty(widget);
844 }
845
846 if (click_count > 0) this->mouse_capture_widget = widget;
847 break;
848 }
849
850 case WID_M_SHUFFLE: // toggle shuffle
851 if (_music.IsShuffle()) {
852 _music.Unshuffle();
853 } else {
854 _music.Shuffle();
855 }
856 this->SetWidgetLoweredState(WID_M_SHUFFLE, _music.IsShuffle());
858 break;
859
860 case WID_M_PROGRAMME: // show track selection
861 ShowMusicTrackSelection();
862 break;
863
864 case WID_M_ALL: case WID_M_OLD: case WID_M_NEW:
865 case WID_M_EZY: case WID_M_CUSTOM1: case WID_M_CUSTOM2: // playlist
866 _music.ChangePlaylist((MusicSystem::PlaylistChoices)(widget - WID_M_ALL));
867 break;
868 }
869 }
870};
871
872static constexpr std::initializer_list<NWidgetPart> _nested_music_window_widgets = {
874 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
875 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_MUSIC_JAZZ_JUKEBOX_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
876 NWidget(WWT_SHADEBOX, COLOUR_GREY),
877 NWidget(WWT_STICKYBOX, COLOUR_GREY),
878 EndContainer(),
879
882 NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(),
884 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_PREV), SetToolbarMinimalSize(1), SetSpriteTip(SPR_IMG_SKIP_TO_PREV, STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK),
885 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_NEXT), SetToolbarMinimalSize(1), SetSpriteTip(SPR_IMG_SKIP_TO_NEXT, STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION),
886 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_STOP), SetToolbarMinimalSize(1), SetSpriteTip(SPR_IMG_STOP_MUSIC, STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC),
887 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_PLAY), SetToolbarMinimalSize(1), SetSpriteTip(SPR_IMG_PLAY_MUSIC, STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC),
888 EndContainer(),
889 NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(),
890 EndContainer(),
891 NWidget(WWT_PANEL, COLOUR_GREY, WID_M_SLIDERS),
894 NWidget(WWT_LABEL, INVALID_COLOUR), SetFill(1, 0), SetStringTip(STR_MUSIC_MUSIC_VOLUME),
895 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_M_MUSIC_VOL), SetMinimalSize(67, 0), SetMinimalTextLines(1, 0), SetFill(1, 0), SetToolTip(STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC),
896 EndContainer(),
898 NWidget(WWT_LABEL, INVALID_COLOUR), SetFill(1, 0), SetStringTip(STR_MUSIC_EFFECTS_VOLUME),
899 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_M_EFFECT_VOL), SetMinimalSize(67, 0), SetMinimalTextLines(1, 0), SetFill(1, 0), SetToolTip(STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC),
900 EndContainer(),
901 EndContainer(),
902 EndContainer(),
903 EndContainer(),
904 NWidget(WWT_PANEL, COLOUR_GREY, WID_M_BACKGROUND),
907 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_SHUFFLE), SetMinimalSize(50, 0), SetStringTip(STR_MUSIC_SHUFFLE, STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE),
908 EndContainer(),
910 NWidget(WWT_LABEL, INVALID_COLOUR, WID_M_TRACK), SetFill(0, 0), SetStringTip(STR_MUSIC_TRACK),
911 NWidget(WWT_INSET, COLOUR_GREY, WID_M_TRACK_NR), SetFill(0, 0), EndContainer(),
912 EndContainer(),
914 NWidget(WWT_LABEL, INVALID_COLOUR, WID_M_TRACK_TITLE), SetFill(1, 0), SetStringTip(STR_MUSIC_XTITLE),
915 NWidget(WWT_INSET, COLOUR_GREY, WID_M_TRACK_NAME), SetFill(1, 0), EndContainer(),
916 EndContainer(),
918 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_M_PROGRAMME), SetMinimalSize(50, 0), SetStringTip(STR_MUSIC_PROGRAM, STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION),
919 EndContainer(),
920 EndContainer(),
921 EndContainer(),
923 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_ALL), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM),
924 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_OLD), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC),
925 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_NEW), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC),
926 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_EZY), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE),
927 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_CUSTOM1), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED),
928 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_CUSTOM2), SetFill(1, 0), SetStringTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED),
929 EndContainer(),
930};
931
932static WindowDesc _music_window_desc(
933 WDP_AUTO, "music", 0, 0,
935 {},
936 _nested_music_window_widgets
937);
938
939void ShowMusicWindow()
940{
941 AllocateWindowDescFront<MusicWindow>(_music_window_desc, 0);
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.
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:93
static IDirectMusic * _music
The direct music object manages buffers and ports.
Definition dmusic.cpp:140
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options)
Show a drop down list.
Definition dropdown.cpp:419
Functions related to the drop down widget.
Types related to the drop down widget.
Functions related to errors.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:900
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:669
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
Functions related to the gfx engine.
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:250
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:389
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 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 SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
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:967
#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.
void ChangeMusicSet(int index)
Change the configured music set and reset playback.
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.
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.
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.
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 SaveCustomPlaylist(PlaylistChoices pl)
Save a custom playlist to settings after modification.
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 ChangePlaylist(PlaylistChoices pl)
Switch to another playlist, or reload the current one.
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.
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.
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:61
void Prev()
Skip to previous track.
void PlaylistClear()
Remove all songs from the current custom playlist.
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:62
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:168
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:979
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:557
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:505
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:327
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:516
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:442
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1832
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:210
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:986
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:461
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1822
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
@ 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:3215
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:3307
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.
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
@ WN_GAME_OPTIONS_GAME_OPTIONS
Game options.
Definition window_type.h:31
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50
@ WC_MUSIC_TRACK_SELECTION
Music track selection; Window numbers:
@ WC_MUSIC_WINDOW
Music window; Window numbers:
@ WC_GAME_OPTIONS
Game options window; Window numbers:
Functions related to zooming.