OpenTTD
music_gui.cpp
Go to the documentation of this file.
1 /* $Id: music_gui.cpp 27003 2014-10-12 18:41:53Z rubidium $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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 <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "stdafx.h"
13 #include "openttd.h"
14 #include "base_media_base.h"
15 #include "music/music_driver.hpp"
16 #include "window_gui.h"
17 #include "strings_func.h"
18 #include "window_func.h"
19 #include "sound_func.h"
20 #include "gfx_func.h"
21 #include "core/random_func.hpp"
22 #include "error.h"
23 #include "core/geometry_func.hpp"
24 #include "string_func.h"
25 #include "settings_type.h"
26 
27 #include "widgets/music_widget.h"
28 
29 #include "table/strings.h"
30 #include "table/sprites.h"
31 
32 #include "safeguards.h"
33 
39 static const char *GetSongName(int index)
40 {
41  return BaseMusic::GetUsedSet()->song_name[index];
42 }
43 
49 static int GetTrackNumber(int index)
50 {
51  return BaseMusic::GetUsedSet()->track_nr[index];
52 }
53 
55 static byte _music_wnd_cursong = 1;
57 static bool _song_is_active = false;
58 
61 
70 
73 
75 static byte * const _playlists[] = {
82 };
83 
89 void ValidatePlaylist(byte *playlist, byte *last)
90 {
91  while (*playlist != 0 && playlist <= last) {
92  /* Song indices are saved off-by-one so 0 is "nothing". */
93  if (*playlist <= NUM_SONGS_AVAILABLE && !StrEmpty(GetSongName(*playlist - 1))) {
94  playlist++;
95  continue;
96  }
97  for (byte *p = playlist; *p != 0 && p <= last; p++) {
98  p[0] = p[1];
99  }
100  }
101 
102  /* Make sure the list is null terminated. */
103  *last = 0;
104 }
105 
108 {
109  uint j = 0;
110  for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) {
111  if (StrEmpty(GetSongName(i))) continue;
112  _playlist_all[j++] = i + 1;
113  }
114  /* Terminate the list */
115  _playlist_all[j] = 0;
116 
117  /* Now make the 'styled' playlists */
118  for (uint k = 0; k < NUM_SONG_CLASSES; k++) {
119  j = 0;
120  for (uint i = 0; i < NUM_SONGS_CLASS; i++) {
121  int id = k * NUM_SONGS_CLASS + i + 1;
122  if (StrEmpty(GetSongName(id))) continue;
123  _playlists[k + 1][j++] = id + 1;
124  }
125  /* Terminate the list */
126  _playlists[k + 1][j] = 0;
127  }
128 
131 
132  if (BaseMusic::GetUsedSet()->num_available < _music_wnd_cursong) {
133  /* If there are less songs than the currently played song,
134  * just pause and reset to no song. */
135  _music_wnd_cursong = 0;
136  _song_is_active = false;
137  }
138 }
139 
140 static void SkipToPrevSong()
141 {
142  byte *b = _cur_playlist;
143  byte *p = b;
144  byte t;
145 
146  if (b[0] == 0) return; // empty playlist
147 
148  do p++; while (p[0] != 0); // find the end
149 
150  t = *--p; // and copy the bytes
151  while (p != b) {
152  p--;
153  p[1] = p[0];
154  }
155  *b = t;
156 
157  _song_is_active = false;
158 }
159 
160 static void SkipToNextSong()
161 {
162  byte *b = _cur_playlist;
163  byte t;
164 
165  t = b[0];
166  if (t != 0) {
167  while (b[1] != 0) {
168  b[0] = b[1];
169  b++;
170  }
171  b[0] = t;
172  }
173 
174  _song_is_active = false;
175 }
176 
177 static void MusicVolumeChanged(byte new_vol)
178 {
180 }
181 
182 static void DoPlaySong()
183 {
184  char filename[MAX_PATH];
185  if (FioFindFullPath(filename, lastof(filename), BASESET_DIR, BaseMusic::GetUsedSet()->files[_music_wnd_cursong - 1].filename) == NULL) {
186  FioFindFullPath(filename, lastof(filename), OLD_GM_DIR, BaseMusic::GetUsedSet()->files[_music_wnd_cursong - 1].filename);
187  }
188  MusicDriver::GetInstance()->PlaySong(filename);
190 }
191 
192 static void DoStopMusic()
193 {
196 }
197 
198 static void SelectSongToPlay()
199 {
200  uint i = 0;
201  uint j = 0;
202 
203  memset(_cur_playlist, 0, sizeof(_cur_playlist));
204  do {
205  /* File is the index into the file table of the music set. The play list uses 0 as 'no entry',
206  * so we need to subtract 1. In case of 'no entry' (file = -1), just skip adding it outright. */
207  int file = _playlists[_settings_client.music.playlist][i] - 1;
208  if (file >= 0) {
209  const char *filename = BaseMusic::GetUsedSet()->files[file].filename;
210  /* We are now checking for the existence of that file prior
211  * to add it to the list of available songs */
212  if (!StrEmpty(filename) && FioCheckFileExists(filename, BASESET_DIR)) {
213  _cur_playlist[j] = _playlists[_settings_client.music.playlist][i];
214  j++;
215  }
216  }
217  } while (_playlists[_settings_client.music.playlist][++i] != 0 && j < lengthof(_cur_playlist) - 1);
218 
219  /* Do not shuffle when on the intro-start window, as the song to play has to be the original TTD Theme*/
220  if (_settings_client.music.shuffle && _game_mode != GM_MENU) {
221  i = 500;
222  do {
223  uint32 r = InteractiveRandom();
224  byte *a = &_cur_playlist[GB(r, 0, 5)];
225  byte *b = &_cur_playlist[GB(r, 8, 5)];
226 
227  if (*a != 0 && *b != 0) {
228  byte t = *a;
229  *a = *b;
230  *b = t;
231  }
232  } while (--i);
233  }
234 }
235 
236 static void StopMusic()
237 {
238  _music_wnd_cursong = 0;
239  DoStopMusic();
240  _song_is_active = false;
242 }
243 
244 static void PlayPlaylistSong()
245 {
246  if (_cur_playlist[0] == 0) {
247  SelectSongToPlay();
248  /* if there is not songs in the playlist, it may indicate
249  * no file on the gm folder, or even no gm folder.
250  * Stop the playback, then */
251  if (_cur_playlist[0] == 0) {
252  _song_is_active = false;
253  _music_wnd_cursong = 0;
255  return;
256  }
257  }
259  DoPlaySong();
260  _song_is_active = true;
261 
263 }
264 
265 void ResetMusic()
266 {
267  _music_wnd_cursong = 1;
268  DoPlaySong();
269 }
270 
271 void MusicLoop()
272 {
274  StopMusic();
276  PlayPlaylistSong();
277  }
278 
279  if (!_song_is_active) return;
280 
281  if (!MusicDriver::GetInstance()->IsSongPlaying()) {
282  if (_game_mode != GM_MENU) {
283  StopMusic();
284  SkipToNextSong();
285  PlayPlaylistSong();
286  } else {
287  ResetMusic();
288  }
289  }
290 }
291 
292 static void SelectPlaylist(byte list)
293 {
297 }
298 
301  {
302  this->InitNested(number);
307  }
308 
309  virtual void SetStringParameters(int widget) const
310  {
311  switch (widget) {
312  case WID_MTS_PLAYLIST:
313  SetDParam(0, STR_MUSIC_PLAYLIST_ALL + _settings_client.music.playlist);
314  break;
315  }
316  }
317 
323  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
324  {
325  if (!gui_scope) return;
326  for (int i = 0; i < 6; i++) {
328  }
330  this->SetDirty();
331  }
332 
333  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
334  {
335  switch (widget) {
336  case WID_MTS_PLAYLIST: {
337  Dimension d = {0, 0};
338 
339  for (int i = 0; i < 6; i++) {
340  SetDParam(0, STR_MUSIC_PLAYLIST_ALL + i);
341  d = maxdim(d, GetStringBoundingBox(STR_PLAYLIST_PROGRAM));
342  }
343  d.width += padding.width;
344  d.height += padding.height;
345  *size = maxdim(*size, d);
346  break;
347  }
348 
350  Dimension d = {0, 0};
351 
352  for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) {
353  const char *song_name = GetSongName(i);
354  if (StrEmpty(song_name)) continue;
355 
356  SetDParam(0, GetTrackNumber(i));
357  SetDParam(1, 2);
358  SetDParamStr(2, GetSongName(i));
359  Dimension d2 = GetStringBoundingBox(STR_PLAYLIST_TRACK_NAME);
360  d.width = max(d.width, d2.width);
361  d.height += d2.height;
362  }
363  d.width += padding.width;
364  d.height += padding.height;
365  *size = maxdim(*size, d);
366  break;
367  }
368  }
369  }
370 
371  virtual void DrawWidget(const Rect &r, int widget) const
372  {
373  switch (widget) {
374  case WID_MTS_LIST_LEFT: {
375  GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK);
376 
377  int y = r.top + WD_FRAMERECT_TOP;
378  for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) {
379  const char *song_name = GetSongName(i);
380  if (StrEmpty(song_name)) continue;
381 
382  SetDParam(0, GetTrackNumber(i));
383  SetDParam(1, 2);
384  SetDParamStr(2, song_name);
385  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME);
386  y += FONT_HEIGHT_SMALL;
387  }
388  break;
389  }
390 
391  case WID_MTS_LIST_RIGHT: {
392  GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK);
393 
394  int y = r.top + WD_FRAMERECT_TOP;
395  for (const byte *p = _playlists[_settings_client.music.playlist]; *p != 0; p++) {
396  uint i = *p - 1;
397  SetDParam(0, GetTrackNumber(i));
398  SetDParam(1, 2);
399  SetDParamStr(2, GetSongName(i));
400  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME);
401  y += FONT_HEIGHT_SMALL;
402  }
403  break;
404  }
405  }
406  }
407 
408  virtual void OnClick(Point pt, int widget, int click_count)
409  {
410  switch (widget) {
411  case WID_MTS_LIST_LEFT: { // add to playlist
412  int y = this->GetRowFromWidget(pt.y, widget, 0, FONT_HEIGHT_SMALL);
413 
414  if (_settings_client.music.playlist < 4) return;
415  if (!IsInsideMM(y, 0, BaseMusic::GetUsedSet()->num_available)) return;
416 
417  byte *p = _playlists[_settings_client.music.playlist];
418  for (uint i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) {
419  if (p[i] == 0) {
420  /* Find the actual song number */
421  for (uint j = 0; j < NUM_SONGS_AVAILABLE; j++) {
422  if (GetTrackNumber(j) == y + 1) {
423  p[i] = j + 1;
424  break;
425  }
426  }
427  p[i + 1] = 0;
428  this->SetDirty();
429  SelectSongToPlay();
430  break;
431  }
432  }
433  break;
434  }
435 
436  case WID_MTS_LIST_RIGHT: { // remove from playlist
437  int y = this->GetRowFromWidget(pt.y, widget, 0, FONT_HEIGHT_SMALL);
438 
439  if (_settings_client.music.playlist < 4) return;
440  if (!IsInsideMM(y, 0, NUM_SONGS_PLAYLIST)) return;
441 
442  byte *p = _playlists[_settings_client.music.playlist];
443  for (uint i = y; i != NUM_SONGS_PLAYLIST - 1; i++) {
444  p[i] = p[i + 1];
445  }
446 
447  this->SetDirty();
448  SelectSongToPlay();
449  break;
450  }
451 
452  case WID_MTS_CLEAR: // clear
453  for (uint i = 0; _playlists[_settings_client.music.playlist][i] != 0; i++) _playlists[_settings_client.music.playlist][i] = 0;
454  this->SetDirty();
455  StopMusic();
456  SelectSongToPlay();
457  break;
458 
459  case WID_MTS_ALL: case WID_MTS_OLD: case WID_MTS_NEW:
460  case WID_MTS_EZY: case WID_MTS_CUSTOM1: case WID_MTS_CUSTOM2: // set playlist
461  SelectPlaylist(widget - WID_MTS_ALL);
462  StopMusic();
463  SelectSongToPlay();
464  break;
465  }
466  }
467 };
468 
469 static const NWidgetPart _nested_music_track_selection_widgets[] = {
471  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
472  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_PLAYLIST_MUSIC_PROGRAM_SELECTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
473  EndContainer(),
474  NWidget(WWT_PANEL, COLOUR_GREY),
475  NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
476  /* Left panel. */
478  NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_PLAYLIST_TRACK_INDEX, STR_NULL),
479  NWidget(WWT_PANEL, COLOUR_GREY, WID_MTS_LIST_LEFT), SetMinimalSize(180, 194), SetDataTip(0x0, STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK), EndContainer(),
481  EndContainer(),
482  /* Middle buttons. */
484  NWidget(NWID_SPACER), SetMinimalSize(60, 30), // Space above the first button from the title bar.
485  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_ALL), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM),
486  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_OLD), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC),
487  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_NEW), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC),
488  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_EZY), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE),
489  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM1), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED),
490  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM2), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED),
491  NWidget(NWID_SPACER), SetMinimalSize(0, 16), // Space above 'clear' button
492  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_MTS_CLEAR), SetFill(1, 0), SetDataTip(STR_PLAYLIST_CLEAR, STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1),
493  NWidget(NWID_SPACER), SetFill(0, 1),
494  EndContainer(),
495  /* Right panel. */
497  NWidget(WWT_LABEL, COLOUR_GREY, WID_MTS_PLAYLIST), SetDataTip(STR_PLAYLIST_PROGRAM, STR_NULL),
498  NWidget(WWT_PANEL, COLOUR_GREY, WID_MTS_LIST_RIGHT), SetMinimalSize(180, 194), SetDataTip(0x0, STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK), EndContainer(),
500  EndContainer(),
501  EndContainer(),
502  EndContainer(),
503 };
504 
505 static WindowDesc _music_track_selection_desc(
506  WDP_AUTO, "music_track", 0, 0,
508  0,
509  _nested_music_track_selection_widgets, lengthof(_nested_music_track_selection_widgets)
510 );
511 
512 static void ShowMusicTrackSelection()
513 {
514  AllocateWindowDescFront<MusicTrackSelectionWindow>(&_music_track_selection_desc, 0);
515 }
516 
517 struct MusicWindow : public Window {
518  static const int slider_width = 3;
519 
520  MusicWindow(WindowDesc *desc, WindowNumber number) : Window(desc)
521  {
522  this->InitNested(number);
525  }
526 
527  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
528  {
529  switch (widget) {
530  /* Make sure that WID_M_SHUFFLE and WID_M_PROGRAMME have the same size.
531  * This can't be done by using NC_EQUALSIZE as the WID_M_INFO is
532  * between those widgets and of different size. */
533  case WID_M_SHUFFLE: case WID_M_PROGRAMME: {
534  Dimension d = maxdim(GetStringBoundingBox(STR_MUSIC_PROGRAM), GetStringBoundingBox(STR_MUSIC_SHUFFLE));
535  d.width += padding.width;
536  d.height += padding.height;
537  *size = maxdim(*size, d);
538  break;
539  }
540 
541  case WID_M_TRACK_NR: {
542  Dimension d = GetStringBoundingBox(STR_MUSIC_TRACK_NONE);
545  *size = maxdim(*size, d);
546  break;
547  }
548 
549  case WID_M_TRACK_NAME: {
550  Dimension d = GetStringBoundingBox(STR_MUSIC_TITLE_NONE);
551  for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) {
552  SetDParamStr(0, GetSongName(i));
553  d = maxdim(d, GetStringBoundingBox(STR_MUSIC_TITLE_NAME));
554  }
557  *size = maxdim(*size, d);
558  break;
559  }
560 
561  /* Hack-ish: set the proper widget data; only needs to be done once
562  * per (Re)Init as that's the only time the language changes. */
563  case WID_M_PREV: this->GetWidget<NWidgetCore>(WID_M_PREV)->widget_data = _current_text_dir == TD_RTL ? SPR_IMG_SKIP_TO_NEXT : SPR_IMG_SKIP_TO_PREV; break;
564  case WID_M_NEXT: this->GetWidget<NWidgetCore>(WID_M_NEXT)->widget_data = _current_text_dir == TD_RTL ? SPR_IMG_SKIP_TO_PREV : SPR_IMG_SKIP_TO_NEXT; break;
565  case WID_M_PLAY: this->GetWidget<NWidgetCore>(WID_M_PLAY)->widget_data = _current_text_dir == TD_RTL ? SPR_IMG_PLAY_MUSIC_RTL : SPR_IMG_PLAY_MUSIC; break;
566  }
567  }
568 
569  virtual void DrawWidget(const Rect &r, int widget) const
570  {
571  switch (widget) {
572  case WID_M_TRACK_NR: {
573  GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK);
574  StringID str = STR_MUSIC_TRACK_NONE;
575  if (_song_is_active != 0 && _music_wnd_cursong != 0) {
577  SetDParam(1, 2);
578  str = STR_MUSIC_TRACK_DIGIT;
579  }
580  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str);
581  break;
582  }
583 
584  case WID_M_TRACK_NAME: {
585  GfxFillRect(r.left, r.top + 1, r.right - 1, r.bottom, PC_BLACK);
586  StringID str = STR_MUSIC_TITLE_NONE;
587  if (_song_is_active != 0 && _music_wnd_cursong != 0) {
588  str = STR_MUSIC_TITLE_NAME;
590  }
591  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_FROMSTRING, SA_HOR_CENTER);
592  break;
593  }
594 
595  case WID_M_MUSIC_VOL: case WID_M_EFFECT_VOL: {
596  DrawFrameRect(r.left, r.top + 2, r.right, r.bottom - 2, COLOUR_GREY, FR_LOWERED);
598  int x = (volume * (r.right - r.left) / 127);
599  if (_current_text_dir == TD_RTL) {
600  x = r.right - x;
601  } else {
602  x += r.left;
603  }
604  DrawFrameRect(x, r.top, x + slider_width, r.bottom, COLOUR_GREY, FR_NONE);
605  break;
606  }
607  }
608  }
609 
615  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
616  {
617  if (!gui_scope) return;
618  for (int i = 0; i < 6; i++) {
620  }
621  this->SetDirty();
622  }
623 
624  virtual void OnClick(Point pt, int widget, int click_count)
625  {
626  switch (widget) {
627  case WID_M_PREV: // skip to prev
628  if (!_song_is_active) return;
629  SkipToPrevSong();
630  this->SetDirty();
631  break;
632 
633  case WID_M_NEXT: // skip to next
634  if (!_song_is_active) return;
635  SkipToNextSong();
636  this->SetDirty();
637  break;
638 
639  case WID_M_STOP: // stop playing
641  break;
642 
643  case WID_M_PLAY: // start playing
645  break;
646 
647  case WID_M_MUSIC_VOL: case WID_M_EFFECT_VOL: { // volume sliders
648  int x = pt.x - this->GetWidget<NWidgetBase>(widget)->pos_x;
649 
651 
652  byte new_vol = x * 127 / this->GetWidget<NWidgetBase>(widget)->current_x;
653  if (_current_text_dir == TD_RTL) new_vol = 127 - new_vol;
654  if (new_vol != *vol) {
655  *vol = new_vol;
656  if (widget == WID_M_MUSIC_VOL) MusicVolumeChanged(new_vol);
657  this->SetDirty();
658  }
659 
660  _left_button_clicked = false;
661  break;
662  }
663 
664  case WID_M_SHUFFLE: // toggle shuffle
668  StopMusic();
669  SelectSongToPlay();
670  this->SetDirty();
671  break;
672 
673  case WID_M_PROGRAMME: // show track selection
674  ShowMusicTrackSelection();
675  break;
676 
677  case WID_M_ALL: case WID_M_OLD: case WID_M_NEW:
678  case WID_M_EZY: case WID_M_CUSTOM1: case WID_M_CUSTOM2: // playlist
679  SelectPlaylist(widget - WID_M_ALL);
680  StopMusic();
681  SelectSongToPlay();
682  this->SetDirty();
683  break;
684  }
685  }
686 };
687 
688 static const NWidgetPart _nested_music_window_widgets[] = {
690  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
691  NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MUSIC_JAZZ_JUKEBOX_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
692  NWidget(WWT_SHADEBOX, COLOUR_GREY),
693  NWidget(WWT_STICKYBOX, COLOUR_GREY),
694  EndContainer(),
695 
698  NWidget(WWT_PANEL, COLOUR_GREY, -1), SetFill(1, 1), EndContainer(),
700  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_PREV), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_SKIP_TO_PREV, STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK),
701  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_NEXT), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_SKIP_TO_NEXT, STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION),
702  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_STOP), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_STOP_MUSIC, STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC),
703  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_PLAY), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_PLAY_MUSIC, STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC),
704  EndContainer(),
705  NWidget(WWT_PANEL, COLOUR_GREY, -1), SetFill(1, 1), EndContainer(),
706  EndContainer(),
707  NWidget(WWT_PANEL, COLOUR_GREY, WID_M_SLIDERS),
708  NWidget(NWID_HORIZONTAL), SetPIP(20, 20, 20),
710  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetFill(1, 0), SetDataTip(STR_MUSIC_MUSIC_VOLUME, STR_NULL),
711  NWidget(WWT_EMPTY, COLOUR_GREY, WID_M_MUSIC_VOL), SetMinimalSize(67, 0), SetMinimalTextLines(1, 0), SetFill(1, 0), SetDataTip(0x0, STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC),
713  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MIN, STR_NULL),
714  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
715  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
716  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
717  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
718  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
719  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MAX, STR_NULL),
720  EndContainer(),
721  EndContainer(),
723  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetFill(1, 0), SetDataTip(STR_MUSIC_EFFECTS_VOLUME, STR_NULL),
724  NWidget(WWT_EMPTY, COLOUR_GREY, WID_M_EFFECT_VOL), SetMinimalSize(67, 0), SetMinimalTextLines(1, 0), SetFill(1, 0), SetDataTip(0x0, STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC),
726  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MIN, STR_NULL),
727  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
728  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
729  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
730  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
731  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0),
732  NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MAX, STR_NULL),
733  EndContainer(),
734  EndContainer(),
735  EndContainer(),
736  EndContainer(),
737  EndContainer(),
738  NWidget(WWT_PANEL, COLOUR_GREY, WID_M_BACKGROUND),
739  NWidget(NWID_HORIZONTAL), SetPIP(6, 0, 6),
741  NWidget(NWID_SPACER), SetFill(0, 1),
742  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_SHUFFLE), SetMinimalSize(50, 8), SetDataTip(STR_MUSIC_SHUFFLE, STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE),
743  NWidget(NWID_SPACER), SetFill(0, 1),
744  EndContainer(),
745  NWidget(NWID_VERTICAL), SetPadding(0, 0, 3, 3),
746  NWidget(WWT_LABEL, COLOUR_GREY, WID_M_TRACK), SetFill(0, 0), SetDataTip(STR_MUSIC_TRACK, STR_NULL),
747  NWidget(WWT_PANEL, COLOUR_GREY, WID_M_TRACK_NR), EndContainer(),
748  EndContainer(),
749  NWidget(NWID_VERTICAL), SetPadding(0, 3, 3, 0),
750  NWidget(WWT_LABEL, COLOUR_GREY, WID_M_TRACK_TITLE), SetFill(1, 0), SetDataTip(STR_MUSIC_XTITLE, STR_NULL),
751  NWidget(WWT_PANEL, COLOUR_GREY, WID_M_TRACK_NAME), SetFill(1, 0), EndContainer(),
752  EndContainer(),
754  NWidget(NWID_SPACER), SetFill(0, 1),
755  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_M_PROGRAMME), SetMinimalSize(50, 8), SetDataTip(STR_MUSIC_PROGRAM, STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION),
756  NWidget(NWID_SPACER), SetFill(0, 1),
757  EndContainer(),
758  EndContainer(),
759  EndContainer(),
761  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_ALL), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM),
762  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_OLD), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC),
763  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_NEW), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC),
764  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_EZY), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE),
765  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_CUSTOM1), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED),
766  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_CUSTOM2), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED),
767  EndContainer(),
768 };
769 
770 static WindowDesc _music_window_desc(
771  WDP_AUTO, "music", 0, 0,
773  0,
774  _nested_music_window_widgets, lengthof(_nested_music_window_widgets)
775 );
776 
777 void ShowMusicWindow()
778 {
779  if (BaseMusic::GetUsedSet()->num_available == 0) ShowErrorMessage(STR_ERROR_NO_SONGS, INVALID_STRING_ID, WL_WARNING);
780  AllocateWindowDescFront<MusicWindow>(&_music_window_desc, 0);
781 }
Functions related to OTTD&#39;s strings.
Empty widget, place holder to reserve space in widget array.
Definition: widget_type.h:48
Normal push-button (no toggle button) with image caption.
Definition: widget_type.h:105
static byte _playlist_old_style[NUM_SONGS_CLASS+1]
Indices of all old style songs.
Definition: music_gui.cpp:65
Old subdirectory for the music.
Definition: fileio_type.h:116
Types related to the music widgets.
Music window; Window numbers:
Definition: window_type.h:592
Horizontally center the text.
Definition: gfx_func.h:99
ResizeInfo resize
Resize information.
Definition: window_gui.h:317
Window(WindowDesc *desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1843
Right button.
Definition: music_widget.h:19
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen...
Definition: gfx.cpp:112
void SetWidgetDisabledState(byte widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:387
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3120
static byte _music_wnd_cursong
The currently played song.
Definition: music_gui.cpp:55
void SetWidgetLoweredState(byte widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition: window_gui.h:448
static const uint NUM_SONGS_PLAYLIST
Maximum number of songs in the (custom) playlist.
Previous button.
Definition: music_widget.h:31
High level window description.
Definition: window_gui.h:168
static int GetTrackNumber(int index)
Get the track number of the song.
Definition: music_gui.cpp:49
static bool IsInsideMM(const T x, const uint min, const uint max)
Checks if a value is in an interval.
Definition: math_func.hpp:266
Stop button.
Definition: music_widget.h:33
Centered label.
Definition: widget_type.h:57
void SetWidgetDirty(byte widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:577
Offset at top to draw the frame rectangular area.
Definition: window_gui.h:64
Horizontal container.
Definition: widget_type.h:75
static byte _playlist_ezy_street[NUM_SONGS_CLASS+1]
Indices of all ezy street songs.
Definition: music_gui.cpp:69
static byte _playlist_new_style[NUM_SONGS_CLASS+1]
Indices of all new style songs.
Definition: music_gui.cpp:67
virtual void OnClick(Point pt, int widget, int click_count)
A click with the left mouse button has been made on the window.
Definition: music_gui.cpp:624
Generic functions for replacing base data (graphics, sounds).
Music track selection; Window numbers:
Definition: window_type.h:598
static const uint NUM_SONGS_AVAILABLE
Maximum number of songs in the full playlist; theme song + the classes.
MusicSettings music
settings related to music/sound
Playlist.
Definition: music_widget.h:18
Old button.
Definition: music_widget.h:46
Close box (at top-left of a window)
Definition: widget_type.h:69
static NWidgetPart SetMinimalTextLines(uint8 lines, uint8 spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
Definition: widget_type.h:965
#define lastof(x)
Get the last element of an fixed size array.
Definition: depend.cpp:50
byte playlist
The playlist (number) to play.
bool playing
Whether music is playing.
MD5File files[NUM_FILES]
All files part of this set.
Subdirectory for all base data (base sets, intro game)
Definition: fileio_type.h:118
static T max(const T a, const T b)
Returns the maximum of two values.
Definition: math_func.hpp:26
virtual void SetStringParameters(int widget) const
Initialize string parameters for a widget.
Definition: music_gui.cpp:309
Functions, definitions and such used only by the GUI.
static byte *const _playlists[]
The different playlists that can be played.
Definition: music_gui.cpp:75
Old button.
Definition: music_widget.h:21
Sliders.
Definition: music_widget.h:35
bool _left_button_clicked
Is left mouse button clicked?
Definition: gfx.cpp:40
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:177
Ezy button.
Definition: music_widget.h:23
New button.
Definition: music_widget.h:47
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:910
Pseudo random number generator.
Data structure for an opened window.
Definition: window_gui.h:271
static NWidgetPart SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left)
Widget part function for setting additional space around a widget.
Definition: widget_type.h:1046
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1833
void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x=0, int y=0, const GRFFile *textref_stack_grffile=NULL, uint textref_stack_size=0, const uint32 *textref_stack=NULL)
Display an error message in a window.
Definition: error_gui.cpp:378
void SetDParamStr(uint n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:279
Functions related to low-level strings.
Shuffle button.
Definition: music_widget.h:43
Custom2 button.
Definition: music_widget.h:50
Invisible widget that takes some space.
Definition: widget_type.h:79
Other information.
Definition: error.h:24
All button.
Definition: music_widget.h:20
Functions related to errors.
#define FONT_HEIGHT_SMALL
Height of characters in the small (FS_SMALL) font.
Definition: gfx_func.h:177
virtual void SetVolume(byte vol)=0
Set the volume, if possible.
virtual void OnClick(Point pt, int widget, int click_count)
A click with the left mouse button has been made on the window.
Definition: music_gui.cpp:408
Effect volume.
Definition: music_widget.h:37
Track playing.
Definition: music_widget.h:39
const char * filename
filename
bool shuffle
Whether to shuffle the music.
void InitializeMusic()
Initialize the playlists.
Definition: music_gui.cpp:107
Clear button.
Definition: music_widget.h:26
char * FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename)
Find a path to the filename in one of the search directories.
Definition: fileio.cpp:364
static const uint NUM_SONGS_CLASS
Maximum number of songs in the &#39;class&#39; playlists.
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1014
Functions related to the gfx engine.
Track name.
Definition: music_widget.h:42
virtual void OnInvalidateData(int data=0, bool gui_scope=true)
Some data on this window has become invalid.
Definition: music_gui.cpp:615
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:76
Types related to global configuration settings.
static NWidgetPart SetMinimalSize(int16 x, int16 y)
Widget part function for setting the minimal size.
Definition: widget_type.h:947
Base for all music playback.
Definition of base types and functions in a cross-platform compatible way.
Program button.
Definition: music_widget.h:44
virtual void DrawWidget(const Rect &r, int widget) const
Draw the contents of a nested widget.
Definition: music_gui.cpp:569
A number of safeguards to prevent using unsafe methods.
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:104
Geometry functions.
byte custom_1[33]
The order of the first custom playlist.
Simple depressed panel.
Definition: widget_type.h:50
void LowerWidget(byte widget_index)
Marks a widget as lowered.
Definition: window_gui.h:469
int GetRowFromWidget(int clickpos, int widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
Definition: window.cpp:199
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
Update size and resize step of a widget in the window.
Definition: music_gui.cpp:333
static NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx=-1)
Widget part function for starting a new &#39;real&#39; widget.
Definition: widget_type.h:1114
Offset at bottom to draw the frame rectangular area.
Definition: window_gui.h:65
Baseclass for nested widgets.
Definition: widget_type.h:126
int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:499
Some generic types.
static MusicDriver * GetInstance()
Get the currently active instance of the music driver.
#define lengthof(x)
Return the length of an fixed size array.
Definition: depend.cpp:42
Track number.
Definition: music_widget.h:40
void ValidatePlaylist(byte *playlist, byte *last)
Validate a playlist.
Definition: music_gui.cpp:89
bool FioCheckFileExists(const char *filename, Subdirectory subdir)
Check whether the given file exists.
Definition: fileio.cpp:312
Functions related to sound.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:18
static const uint8 PC_BLACK
Black palette colour.
Definition: gfx_func.h:207
Custom2 button.
Definition: music_widget.h:25
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:959
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:699
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:40
static const uint NUM_SONG_CLASSES
Number of classes for songs.
Track title.
Definition: music_widget.h:41
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
Update size and resize step of a widget in the window.
Definition: music_gui.cpp:527
byte music_vol
The requested music volume.
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition: window.cpp:3134
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
If set the frame is lowered and the background colour brighter (ie. buttons when pressed) ...
Definition: window_gui.h:31
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
Definition: string_func.h:59
virtual void OnInvalidateData(int data=0, bool gui_scope=true)
Some data on this window has become invalid.
Definition: music_gui.cpp:323
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:52
Custom1 button.
Definition: music_widget.h:24
New button.
Definition: music_widget.h:22
static byte _playlist_all[NUM_SONGS_AVAILABLE+1]
Indices of all songs.
Definition: music_gui.cpp:63
Vertical container.
Definition: widget_type.h:77
static NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL).
Definition: widget_type.h:999
static uint GB(const T x, const uint8 s, const uint8 n)
Fetch n bits from x, started at bit s.
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:174
char song_name[NUM_SONGS_AVAILABLE][32]
The name of the different songs.
Music volume.
Definition: music_widget.h:36
virtual void DrawWidget(const Rect &r, int widget) const
Draw the contents of a nested widget.
Definition: music_gui.cpp:371
Coordinates of a point in 2D.
byte custom_2[33]
The order of the second custom playlist.
static bool _song_is_active
Whether a song is currently played.
Definition: music_gui.cpp:57
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:19
virtual void StopSong()=0
Stop playing the current song.
Background of the window.
Definition: music_widget.h:38
Offset at right to draw the frame rectangular area.
Definition: window_gui.h:63
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
static NWidgetPart SetFill(uint fill_x, uint fill_y)
Widget part function for setting filling.
Definition: widget_type.h:983
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:695
Specification of a rectangle with absolute coordinates of all edges.
Text is written right-to-left by default.
Definition: strings_type.h:26
Window functions not directly related to making/drawing windows.
virtual void PlaySong(const char *filename)=0
Play a particular song.
Find a place automatically.
Definition: window_gui.h:156
Play button.
Definition: music_widget.h:34
Ezy button.
Definition: music_widget.h:48
Next button.
Definition: music_widget.h:32
All button.
Definition: music_widget.h:45
static const char * GetSongName(int index)
Get the name of the song.
Definition: music_gui.cpp:39
Dimensions (a width and height) of a rectangle in 2D.
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:429
Offset at left to draw the frame rectangular area.
Definition: window_gui.h:62
This file contains all sprite-related enums and defines.
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:64
byte effect_vol
The requested effects volume.
static const MusicSet * GetUsedSet()
Return the used set.
static byte _cur_playlist[NUM_SONGS_PLAYLIST+1]
Indices of the songs in the current playlist.
Definition: music_gui.cpp:60
static NWidgetPart SetPIP(uint8 pre, uint8 inter, uint8 post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1076
Left button.
Definition: music_widget.h:17
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:3220
(Toggle) Button with text
Definition: widget_type.h:55
Custom1 button.
Definition: music_widget.h:49
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:201