llfloaternearbymedia.cpp 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  1. /**
  2. * @file llfloaternearbymedia.cpp
  3. * @brief Management interface for muting and controlling nearby media
  4. *
  5. * $LicenseInfo:firstyear=2010&license=viewergpl$
  6. *
  7. * Copyright (c) 2010, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llfloaternearbymedia.h"
  34. #include "llbutton.h"
  35. #include "llcheckboxctrl.h"
  36. #include "llcombobox.h"
  37. #include "lllineeditor.h"
  38. #include "llparcel.h"
  39. #include "llscrolllistctrl.h"
  40. #include "llsliderctrl.h"
  41. #include "lltextbox.h"
  42. #include "lluictrlfactory.h"
  43. #include "llappviewer.h" // For gFrameTimeSeconds
  44. #include "llfloaterpreference.h"
  45. #include "llviewermedia.h"
  46. #include "llviewermediafocus.h"
  47. #include "llviewerparcelmedia.h"
  48. #include "llviewerparcelmgr.h"
  49. static const LLUUID PARCEL_MEDIA_LIST_ITEM_UUID = LLUUID("CAB5920F-E484-4233-8621-384CF373A321");
  50. static const LLUUID PARCEL_AUDIO_LIST_ITEM_UUID = LLUUID("DF4B020D-8A24-4B95-AB5D-CA970D694822");
  51. LLFloaterNearByMedia::LLFloaterNearByMedia(const LLSD&)
  52. : mParcelMediaItem(NULL),
  53. mParcelAudioItem(NULL),
  54. mStreamingMusic(LLCachedControl<bool>(gSavedSettings,
  55. "EnableStreamingMusic")),
  56. mSteamingMedia(LLCachedControl<bool>(gSavedSettings,
  57. "EnableStreamingMedia")),
  58. mSharedMedia(LLCachedControl<bool>(gSavedSettings,
  59. "PrimMediaMasterEnabled"))
  60. {
  61. LLUICtrlFactory::getInstance()->buildFloater(this,
  62. "floater_nearby_media.xml");
  63. }
  64. //virtual
  65. LLFloaterNearByMedia::~LLFloaterNearByMedia()
  66. {
  67. gSavedSettings.setBool("ShowNearbyMedia", false);
  68. }
  69. //virtual
  70. bool LLFloaterNearByMedia::postBuild()
  71. {
  72. mMediaTypeCombo = getChild<LLComboBox>("show_combo");
  73. mMediaTypeCombo->setCommitCallback(onCommitMediaType);
  74. mMediaTypeCombo->setCallbackUserData(this);
  75. mMediaList = getChild<LLScrollListCtrl>("media_list");
  76. mMediaList->setCommitOnSelectionChange(true);
  77. mMediaList->setCommitCallback(onSelectNewMedia);
  78. mMediaList->setCallbackUserData(this);
  79. mMediaList->setDoubleClickCallback(onClickSelectedMediaZoom);
  80. mMediaList->sortByColumnIndex(PROXIMITY_COLUMN, true);
  81. mMediaList->sortByColumnIndex(VISIBILITY_COLUMN, false);
  82. mMediaURLText = getChild<LLTextBox>("url_text");
  83. mMediaURLEditor = getChild<LLLineEditor>("media_url");
  84. mMediaURLEditor->setCommitCallback(onCommitMediaURL);
  85. mMediaURLEditor->setCallbackUserData(this);
  86. mPlayButton = getChild<LLButton>("play_btn");
  87. mPlayButton->setClickedCallback(onClickSelectedMediaPlay, this);
  88. mPauseButton = getChild<LLButton>("pause_btn");
  89. mPauseButton->setClickedCallback(onClickSelectedMediaPause, this);
  90. mStopButton = getChild<LLButton>("stop_btn");
  91. mStopButton->setClickedCallback(onClickSelectedMediaStop, this);
  92. mVolumeSlider = getChild<LLSliderCtrl>("volume_slider");
  93. mVolumeSlider->setCommitCallback(onCommitSelectedMediaVolume);
  94. mVolumeSlider->setCallbackUserData(this);
  95. mMuteButton = getChild<LLButton>("mute_btn");
  96. mMuteButton->setClickedCallback(onClickSelectedMediaMute, this);
  97. mUnmuteButton = getChild<LLButton>("unmute_btn");
  98. mUnmuteButton->setClickedCallback(onClickSelectedMediaUnmute, this);
  99. mZoomButton = getChild<LLButton>("zoom_btn");
  100. mZoomButton->setClickedCallback(onClickSelectedMediaZoom, this);
  101. mUnzoomButton = getChild<LLButton>("unzoom_btn");
  102. mUnzoomButton->setClickedCallback(onClickSelectedMediaUnzoom, this);
  103. mEnableAllButton = getChild<LLButton>("enable_all_btn");
  104. mEnableAllButton->setClickedCallback(onClickEnableAll, this);
  105. mDisableAllButton = getChild<LLButton>("disable_all_btn");
  106. mDisableAllButton->setClickedCallback(onClickDisableAll, this);
  107. mOpenPrefsButton = getChild<LLButton>("open_prefs_btn");
  108. mOpenPrefsButton->setClickedCallback(onOpenPrefs, this);
  109. mEmptyNameString = getString("empty_item_text");
  110. mParcelMediaName = getString("parcel_media_name");
  111. mParcelAudioName = getString("parcel_audio_name");
  112. mPlayingString = getString("playing_suffix");
  113. gSavedSettings.setBool("ShowNearbyMedia", true);
  114. refreshList(true);
  115. return true;
  116. }
  117. void LLFloaterNearByMedia::draw()
  118. {
  119. static F32 last_update = 0.f;
  120. // Do not update every frame: that would be insane !
  121. if (gFrameTimeSeconds > last_update + 0.33f)
  122. {
  123. last_update = gFrameTimeSeconds;
  124. refreshList();
  125. updateControls();
  126. }
  127. LLFloater::draw();
  128. }
  129. void LLFloaterNearByMedia::updateControls()
  130. {
  131. LLUUID selected_media_id = mMediaList->getValue().asUUID();
  132. if (selected_media_id == PARCEL_AUDIO_LIST_ITEM_UUID)
  133. {
  134. if (!mStreamingMusic || !LLViewerParcelMedia::hasParcelAudio())
  135. {
  136. showDisabledControls();
  137. }
  138. else
  139. {
  140. static LLCachedControl<bool> muted_music(gSavedSettings,
  141. "MuteMusic");
  142. static LLCachedControl<F32> music_volume(gSavedSettings,
  143. "AudioLevelMusic");
  144. showTimeBasedControls(LLViewerParcelMedia::parcelMusicPlaying(),
  145. LLViewerParcelMedia::parcelMusicPaused(),
  146. false, false, // no zoom on audio...
  147. muted_music, music_volume);
  148. }
  149. }
  150. else if (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID)
  151. {
  152. if (!mSteamingMedia || !LLViewerParcelMedia::hasParcelMedia())
  153. {
  154. showDisabledControls();
  155. }
  156. else
  157. {
  158. // *TODO: find a way to allow zooming on parcel media...
  159. LLViewerMediaImpl* impl = LLViewerParcelMedia::getParcelMedia();
  160. if (!impl)
  161. {
  162. // It has not started yet
  163. showBasicControls(false, false, false, false, 1.f);
  164. }
  165. else
  166. {
  167. F32 volume = impl->getVolume();
  168. if (impl->isMediaTimeBased())
  169. {
  170. showTimeBasedControls(impl->isMediaPlaying(),
  171. impl->isMediaPaused(),
  172. false, false,
  173. volume <= 0.f, volume);
  174. }
  175. else
  176. {
  177. showBasicControls(LLViewerParcelMedia::isParcelMediaPlaying(),
  178. false, false, volume <= 0.f, volume);
  179. }
  180. }
  181. }
  182. }
  183. else if (!mSteamingMedia || !mSharedMedia)
  184. {
  185. showDisabledControls();
  186. }
  187. else
  188. {
  189. // *TODO: find a way to allow zooming on parcel media...
  190. LLViewerMediaImpl* impl =
  191. LLViewerMedia::getMediaImplFromTextureID(selected_media_id);
  192. if (!impl)
  193. {
  194. showDisabledControls();
  195. }
  196. else
  197. {
  198. F32 volume = impl->getVolume();
  199. // *TODO: find a way to allow zooming on parcel media...
  200. const LLUUID& media_id = impl->getMediaTextureID();
  201. bool zoomed =
  202. LLViewerMediaFocus::getInstance()->isZoomedOnMedia(media_id);
  203. if (impl->isMediaTimeBased())
  204. {
  205. showTimeBasedControls(impl->isMediaPlaying(),
  206. impl->isMediaPaused(),
  207. !impl->isParcelMedia(), zoomed,
  208. volume <= 0.f, volume);
  209. }
  210. else
  211. {
  212. showBasicControls(!impl->isMediaDisabled(),
  213. !impl->isParcelMedia(), zoomed,
  214. volume <= 0.f, volume);
  215. }
  216. }
  217. }
  218. }
  219. void LLFloaterNearByMedia::showBasicControls(bool playing, bool include_zoom,
  220. bool is_zoomed, bool muted,
  221. F32 volume)
  222. {
  223. mPlayButton->setVisible(true);
  224. mPlayButton->setEnabled(!playing);
  225. mPauseButton->setVisible(false);
  226. mStopButton->setEnabled(playing);
  227. mVolumeSlider->setVisible(true);
  228. mMuteButton->setEnabled(true);
  229. mMuteButton->setVisible(!muted);
  230. mUnmuteButton->setVisible(muted);
  231. mVolumeSlider->setEnabled(true);
  232. mVolumeSlider->setValue(volume);
  233. mZoomButton->setVisible(include_zoom && !is_zoomed);
  234. mUnzoomButton->setVisible(include_zoom && is_zoomed);
  235. }
  236. void LLFloaterNearByMedia::showTimeBasedControls(bool playing, bool paused,
  237. bool include_zoom,
  238. bool is_zoomed, bool muted,
  239. F32 volume)
  240. {
  241. mPlayButton->setVisible(!playing || paused);
  242. mPlayButton->setEnabled(true);
  243. mStopButton->setEnabled(playing || paused);
  244. mPauseButton->setVisible(playing && !paused);
  245. mMuteButton->setEnabled(true);
  246. mMuteButton->setVisible(!muted);
  247. mUnmuteButton->setVisible(muted);
  248. mVolumeSlider->setEnabled(true);
  249. mVolumeSlider->setValue(volume);
  250. mZoomButton->setVisible(include_zoom && !is_zoomed);
  251. mUnzoomButton->setVisible(include_zoom && is_zoomed);
  252. }
  253. void LLFloaterNearByMedia::showDisabledControls()
  254. {
  255. mPlayButton->setVisible(true);
  256. mPlayButton->setEnabled(false);
  257. mPauseButton->setVisible(false);
  258. mStopButton->setEnabled(false);
  259. mMuteButton->setVisible(true);
  260. mMuteButton->setEnabled(false);
  261. mUnmuteButton->setVisible(false);
  262. mVolumeSlider->setEnabled(false);
  263. mZoomButton->setVisible(false);
  264. mUnzoomButton->setVisible(false);
  265. }
  266. LLScrollListItem* LLFloaterNearByMedia::addListItem(const LLUUID& id)
  267. {
  268. // Just set up the columns -- the values will be filled in by
  269. // updateListItem().
  270. LLSD row;
  271. row["id"] = id;
  272. LLSD& columns = row["columns"];
  273. columns[CHECKBOX_COLUMN]["column"] = "media_checkbox_ctrl";
  274. columns[CHECKBOX_COLUMN]["type"] = "checkbox";
  275. columns[PROXIMITY_COLUMN]["column"] = "media_proximity";
  276. columns[PROXIMITY_COLUMN]["value"] = "";
  277. columns[VISIBILITY_COLUMN]["column"] = "media_visibility";
  278. columns[VISIBILITY_COLUMN]["value"] = "";
  279. columns[CLASS_COLUMN]["column"] = "media_class";
  280. columns[CLASS_COLUMN]["value"] = "";
  281. columns[NAME_COLUMN]["column"] = "media_name";
  282. columns[NAME_COLUMN]["value"] = "";
  283. LLScrollListItem* new_item = mMediaList->addElement(row);
  284. if (new_item)
  285. {
  286. LLScrollListCheck* scroll_list_check =
  287. dynamic_cast<LLScrollListCheck*>(new_item->getColumn(CHECKBOX_COLUMN));
  288. if (scroll_list_check)
  289. {
  290. LLCheckBoxCtrl* check = scroll_list_check->getCheckBox();
  291. check->setCommitCallback(onCheckItem);
  292. check->setCallbackUserData(this);
  293. }
  294. }
  295. return new_item;
  296. }
  297. void LLFloaterNearByMedia::updateListItem(LLScrollListItem* item,
  298. LLViewerMediaImpl* impl)
  299. {
  300. if (!item || !impl) return; // Paranoia
  301. std::string item_name;
  302. std::string item_tooltip;
  303. LLFloaterNearByMedia::MediaClass media_class = MEDIA_CLASS_ALL;
  304. getNameAndUrlHelper(impl, item_name, item_tooltip, mEmptyNameString);
  305. if (impl->getUsedOnHUD())
  306. {
  307. // Used on a HUD object. Test this case first, else the media will be
  308. // listed as either MEDIA_CLASS_WITHIN_PARCEL (if the parcel includes
  309. // the (0, 0) sim position) or MEDIA_CLASS_OUTSIDE_PARCEL.
  310. media_class = MEDIA_CLASS_ON_HUD_OBJECT;
  311. }
  312. else if (impl->isAttachedToAnotherAvatar())
  313. {
  314. // Attached to another avatar
  315. media_class = MEDIA_CLASS_ON_OTHERS;
  316. }
  317. else if (impl->isInAgentParcel())
  318. {
  319. // inside parcel
  320. media_class = MEDIA_CLASS_WITHIN_PARCEL;
  321. }
  322. else
  323. {
  324. // Outside agent parcel
  325. media_class = MEDIA_CLASS_OUTSIDE_PARCEL;
  326. }
  327. updateListItem(item, item_name, item_tooltip, impl->getProximity(),
  328. impl->isMediaDisabled(), impl->hasMedia(),
  329. impl->isMediaTimeBased() && impl->isMediaPlaying(),
  330. media_class, impl->hasFocus());
  331. }
  332. void LLFloaterNearByMedia::updateListItem(LLScrollListItem* item,
  333. const std::string& item_name,
  334. const std::string& item_tooltip,
  335. S32 proximity,
  336. bool is_disabled,
  337. bool has_media,
  338. bool is_time_based_and_playing,
  339. LLFloaterNearByMedia::MediaClass media_class,
  340. bool focused)
  341. {
  342. LLScrollListCell* cell = item->getColumn(PROXIMITY_COLUMN);
  343. if (cell)
  344. {
  345. // Since we are forced to sort by text, encode sort order as string
  346. std::string proximity_string = llformat("%d", proximity);
  347. std::string old_proximity_string = cell->getValue().asString();
  348. if (proximity_string != old_proximity_string)
  349. {
  350. cell->setValue(proximity_string);
  351. mMediaList->setSorted(false);
  352. }
  353. }
  354. cell = item->getColumn(CHECKBOX_COLUMN);
  355. if (cell)
  356. {
  357. cell->setValue(!is_disabled);
  358. }
  359. cell = item->getColumn(VISIBILITY_COLUMN);
  360. if (cell)
  361. {
  362. S32 old_visibility = cell->getValue();
  363. // *HACK: force parcel audio to appear first, parcel media second, then
  364. // other media.
  365. LLUUID media_id = item->getUUID();
  366. S32 new_visibility = -1;
  367. if (media_id == PARCEL_AUDIO_LIST_ITEM_UUID)
  368. {
  369. new_visibility = 3;
  370. }
  371. else if (media_id == PARCEL_MEDIA_LIST_ITEM_UUID)
  372. {
  373. new_visibility = 2;
  374. }
  375. else if (has_media)
  376. {
  377. new_visibility = 1;
  378. }
  379. else if (is_disabled)
  380. {
  381. new_visibility = 0;
  382. }
  383. cell->setValue(llformat("%d", new_visibility));
  384. if (new_visibility != old_visibility)
  385. {
  386. mMediaList->setSorted(false);
  387. }
  388. }
  389. cell = item->getColumn(NAME_COLUMN);
  390. if (cell)
  391. {
  392. std::string name = item_name;
  393. std::string old_name = cell->getValue().asString();
  394. if (has_media)
  395. {
  396. name += " " + mPlayingString;
  397. }
  398. if (name != old_name)
  399. {
  400. cell->setValue(name);
  401. }
  402. item->setToolTip(item_tooltip);
  403. // *TODO: Make these font styles/colors configurable via XUI
  404. U8 font_style = LLFontGL::NORMAL;
  405. if (!has_media)
  406. {
  407. font_style |= LLFontGL::ITALIC;
  408. }
  409. else if (focused)
  410. {
  411. font_style |= LLFontGL::BOLD;
  412. }
  413. LLColor4 font_color = LLColor4::black;
  414. if (media_class == MEDIA_CLASS_ON_HUD_OBJECT)
  415. {
  416. font_color = LLColor4::blue;
  417. }
  418. else if (media_class == MEDIA_CLASS_ON_OTHERS)
  419. {
  420. font_color = LLColor4::red2;
  421. }
  422. else if (media_class == MEDIA_CLASS_OUTSIDE_PARCEL)
  423. {
  424. font_color = LLColor4::orange;
  425. }
  426. else if (is_time_based_and_playing)
  427. {
  428. font_color = LLColor4::green3;
  429. }
  430. LLScrollListText* text_cell = dynamic_cast<LLScrollListText*>(cell);
  431. if (text_cell)
  432. {
  433. text_cell->setFontStyle(font_style);
  434. text_cell->setColor(font_color);
  435. }
  436. }
  437. cell = item->getColumn(CLASS_COLUMN);
  438. if (cell)
  439. {
  440. // TODO: clean this up!
  441. cell->setValue(llformat("%d", media_class));
  442. }
  443. }
  444. void LLFloaterNearByMedia::removeListItem(const LLUUID& id)
  445. {
  446. mMediaList->deleteSingleItem(mMediaList->getItemIndex(id));
  447. mMediaList->updateLayout();
  448. }
  449. void LLFloaterNearByMedia::refreshParcelItems()
  450. {
  451. // Get the filter choice.
  452. const LLSD& choice_llsd = mMediaTypeCombo->getSelectedValue();
  453. MediaClass choice = (MediaClass)choice_llsd.asInteger();
  454. // Only show "special parcel items" if "All" or "Within" filter
  455. // (and if media is "enabled")
  456. bool should_include = choice == MEDIA_CLASS_ALL ||
  457. choice == MEDIA_CLASS_WITHIN_PARCEL;
  458. // Parcel Audio: add or remove it as necessary (don't show if disabled)
  459. if (mStreamingMusic && should_include &&
  460. LLViewerParcelMedia::hasParcelAudio())
  461. {
  462. // Yes, there is parcel audio.
  463. if (!mParcelAudioItem)
  464. {
  465. mParcelAudioItem = addListItem(PARCEL_AUDIO_LIST_ITEM_UUID);
  466. mMediaList->setSorted(false);
  467. }
  468. }
  469. else if (mParcelAudioItem)
  470. {
  471. removeListItem(PARCEL_AUDIO_LIST_ITEM_UUID);
  472. mParcelAudioItem = NULL;
  473. mMediaList->setSorted(false);
  474. }
  475. // ... then update it
  476. if (mParcelAudioItem)
  477. {
  478. bool is_playing = LLViewerParcelMedia::isParcelAudioPlaying();
  479. std::string url = LLViewerParcelMedia::getParcelAudioURL();
  480. updateListItem(mParcelAudioItem, mParcelAudioName, url,
  481. -2, // Proximity before Parcel Media and anything else
  482. !is_playing, is_playing, is_playing,
  483. MEDIA_CLASS_ALL, false);
  484. }
  485. // Then Parcel Media: add or remove it as necessary
  486. if (mSteamingMedia && should_include &&
  487. LLViewerParcelMedia::hasParcelMedia())
  488. {
  489. // Yes, there is parcel media.
  490. if (!mParcelMediaItem)
  491. {
  492. mParcelMediaItem = addListItem(PARCEL_MEDIA_LIST_ITEM_UUID);
  493. mMediaList->setSorted(false);
  494. }
  495. }
  496. else if (mParcelMediaItem)
  497. {
  498. removeListItem(PARCEL_MEDIA_LIST_ITEM_UUID);
  499. mParcelMediaItem = NULL;
  500. mMediaList->setSorted(false);
  501. }
  502. // ... then update it
  503. if (mParcelMediaItem)
  504. {
  505. std::string name, url, tooltip;
  506. getNameAndUrlHelper(LLViewerParcelMedia::getParcelMedia(), name, url,
  507. "");
  508. if (name.empty() || name == url)
  509. {
  510. tooltip = url;
  511. }
  512. else
  513. {
  514. tooltip = name + " : " + url;
  515. }
  516. LLViewerMediaImpl* impl = LLViewerParcelMedia::getParcelMedia();
  517. updateListItem(mParcelMediaItem, mParcelMediaName, tooltip,
  518. -1, // Proximity closer than anything but Parcel Audio
  519. !impl || impl->isMediaDisabled(),
  520. impl && !LLViewerParcelMedia::getURL().empty(),
  521. impl && impl->isMediaTimeBased() && impl->isMediaPlaying(),
  522. MEDIA_CLASS_ALL, impl && impl->hasFocus());
  523. }
  524. }
  525. void LLFloaterNearByMedia::refreshMediaURL()
  526. {
  527. LLUUID selected_media_id = mMediaList->getValue().asUUID();
  528. if (selected_media_id.notNull() &&
  529. // Do not allow to change parcel audio and media URL
  530. // *TODO: allow to do it for the parcel owner/managers ?
  531. selected_media_id != PARCEL_AUDIO_LIST_ITEM_UUID &&
  532. selected_media_id != PARCEL_MEDIA_LIST_ITEM_UUID)
  533. {
  534. LLViewerMediaImpl* impl;
  535. impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id);
  536. if (impl && !impl->isParcelMedia() && impl->hasMedia() &&
  537. !impl->isMediaDisabled())
  538. {
  539. std::string url = impl->getCurrentMediaURL();
  540. if (url != mPreviousURL)
  541. {
  542. mPreviousURL = url;
  543. mMediaURLEditor->setText(url);
  544. }
  545. mMediaURLText->setEnabled(true);
  546. mMediaURLEditor->setEnabled(true);
  547. return;
  548. }
  549. }
  550. // Not editable or NULL impl
  551. mMediaURLText->setEnabled(false);
  552. mMediaURLEditor->clear();
  553. mMediaURLEditor->setEnabled(false);
  554. mPreviousURL.clear();
  555. }
  556. void LLFloaterNearByMedia::refreshList(bool fresh)
  557. {
  558. refreshParcelItems();
  559. LLViewerMediaImpl* impl;
  560. // Iterate over the implements list, creating rows as necessary.
  561. for (LLViewerMedia::impl_list::iterator
  562. iter = LLViewerMedia::getPriorityList().begin(),
  563. end = LLViewerMedia::getPriorityList().end();
  564. iter != end; ++iter)
  565. {
  566. impl = *iter;
  567. if (impl && fresh)
  568. {
  569. impl->setInNearbyMediaList(false);
  570. }
  571. if (impl && !impl->isParcelMedia())
  572. {
  573. const LLUUID& media_id = impl->getMediaTextureID();
  574. S32 proximity = impl->getProximity();
  575. if (proximity < 0 || !shouldShow(impl))
  576. {
  577. if (impl->getInNearbyMediaList())
  578. {
  579. // There's a row for this impl, remove it.
  580. removeListItem(media_id);
  581. impl->setInNearbyMediaList(false);
  582. }
  583. }
  584. else if (!impl->getInNearbyMediaList())
  585. {
  586. // We don't have a row for this impl, add one.
  587. addListItem(media_id);
  588. impl->setInNearbyMediaList(true);
  589. }
  590. }
  591. }
  592. mEnableAllButton->setEnabled((mStreamingMusic || mSteamingMedia) &&
  593. (LLViewerMedia::isAnyMediaDisabled() ||
  594. (LLViewerParcelMedia::hasParcelMedia() &&
  595. !LLViewerParcelMedia::isParcelMediaPlaying()) ||
  596. (LLViewerParcelMedia::hasParcelAudio() &&
  597. !LLViewerParcelMedia::isParcelAudioPlaying())));
  598. mDisableAllButton->setEnabled((mStreamingMusic || mSteamingMedia) &&
  599. (LLViewerMedia::isAnyMediaEnabled() ||
  600. LLViewerMedia::isAnyMediaShowing() ||
  601. LLViewerParcelMedia::isParcelMediaPlaying() ||
  602. LLViewerParcelMedia::isParcelAudioPlaying()));
  603. // Iterate over the rows in the control, updating ones whose impl exists,
  604. // and deleting ones whose impl has gone away.
  605. std::vector<LLScrollListItem*> items = mMediaList->getAllData();
  606. for (std::vector<LLScrollListItem*>::iterator iter = items.begin(),
  607. end = items.end();
  608. iter != end; ++iter)
  609. {
  610. LLScrollListItem* item = *iter;
  611. if (!item) continue; // Paranoia
  612. LLUUID row_id = item->getUUID();
  613. if (row_id != PARCEL_MEDIA_LIST_ITEM_UUID &&
  614. row_id != PARCEL_AUDIO_LIST_ITEM_UUID)
  615. {
  616. impl = LLViewerMedia::getMediaImplFromTextureID(row_id);
  617. if (impl)
  618. {
  619. updateListItem(item, impl);
  620. }
  621. else
  622. {
  623. // This item's impl has been deleted remove the row. Removing
  624. // it won't throw off our iteration, since we have a local copy
  625. // of the array. We just need to make sure we don't access this
  626. // item after the delete.
  627. removeListItem(row_id);
  628. }
  629. }
  630. }
  631. refreshMediaURL();
  632. }
  633. bool LLFloaterNearByMedia::shouldShow(LLViewerMediaImpl* impl)
  634. {
  635. if (!impl) return false;
  636. const LLSD& choice_llsd = mMediaTypeCombo->getSelectedValue();
  637. MediaClass choice = (MediaClass)choice_llsd.asInteger();
  638. switch (choice)
  639. {
  640. case MEDIA_CLASS_ALL:
  641. return true;
  642. case MEDIA_CLASS_WITHIN_PARCEL:
  643. return impl->isInAgentParcel() && !impl->getUsedOnHUD();
  644. case MEDIA_CLASS_OUTSIDE_PARCEL:
  645. return !impl->isInAgentParcel() && !impl->getUsedOnHUD();
  646. case MEDIA_CLASS_ON_OTHERS:
  647. return impl->isAttachedToAnotherAvatar();
  648. case MEDIA_CLASS_ON_HUD_OBJECT:
  649. return impl->getUsedOnHUD();
  650. default:
  651. break;
  652. }
  653. return true;
  654. }
  655. void LLFloaterNearByMedia::mediaEnable(const LLUUID& row_id, bool enable)
  656. {
  657. if (row_id == PARCEL_AUDIO_LIST_ITEM_UUID)
  658. {
  659. if (enable)
  660. {
  661. LLViewerParcelMedia::playMusic();
  662. }
  663. else
  664. {
  665. LLViewerParcelMedia::stopMusic();
  666. }
  667. }
  668. else if (row_id == PARCEL_MEDIA_LIST_ITEM_UUID)
  669. {
  670. if (enable)
  671. {
  672. LLViewerParcelMedia::play();
  673. }
  674. else
  675. {
  676. LLViewerParcelMedia::stop();
  677. }
  678. }
  679. else
  680. {
  681. LLViewerMediaImpl* impl;
  682. impl = LLViewerMedia::getMediaImplFromTextureID(row_id);
  683. if (impl)
  684. {
  685. impl->setDisabled(!enable, true);
  686. }
  687. }
  688. }
  689. // static
  690. void LLFloaterNearByMedia::onSelectNewMedia(LLUICtrl* ctrl, void* data)
  691. {
  692. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)data;
  693. if (self)
  694. {
  695. self->refreshMediaURL();
  696. }
  697. }
  698. //static
  699. void LLFloaterNearByMedia::onCheckItem(LLUICtrl* ctrl, void* user_data)
  700. {
  701. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  702. LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)ctrl;
  703. if (self && check)
  704. {
  705. LLUUID selected_media_id = self->mMediaList->getValue().asUUID();
  706. if (check)
  707. {
  708. self->mediaEnable(selected_media_id, check->getValue());
  709. }
  710. }
  711. }
  712. //static
  713. void LLFloaterNearByMedia::onCommitMediaType(LLUICtrl*, void* user_data)
  714. {
  715. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  716. if (self)
  717. {
  718. self->refreshList();
  719. }
  720. }
  721. //static
  722. void LLFloaterNearByMedia::onCommitMediaURL(LLUICtrl* ctrl, void* user_data)
  723. {
  724. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  725. if (self && ctrl)
  726. {
  727. // Get the new URL:
  728. std::string url = ctrl->getValue().asString();
  729. // Force a refresh of the input line:
  730. ctrl->clear();
  731. self->mPreviousURL.clear();
  732. LLUUID selected_media_id = self->mMediaList->getValue().asUUID();
  733. if (selected_media_id != PARCEL_AUDIO_LIST_ITEM_UUID &&
  734. selected_media_id != PARCEL_MEDIA_LIST_ITEM_UUID &&
  735. !url.empty())
  736. {
  737. LLViewerMediaImpl* impl;
  738. impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id);
  739. if (impl)
  740. {
  741. impl->navigateTo(url, "", true); // force mime type rediscovery
  742. }
  743. }
  744. }
  745. }
  746. //static
  747. void LLFloaterNearByMedia::onClickSelectedMediaPlay(void* user_data)
  748. {
  749. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  750. if (self)
  751. {
  752. LLUUID selected_media_id = self->mMediaList->getValue().asUUID();
  753. // First enable it
  754. self->mediaEnable(selected_media_id);
  755. // Special code to make play "unpause" if time-based and playing
  756. if (selected_media_id != PARCEL_AUDIO_LIST_ITEM_UUID)
  757. {
  758. LLViewerMediaImpl* impl;
  759. if (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID)
  760. {
  761. impl = (LLViewerMediaImpl*)LLViewerParcelMedia::getParcelMedia();
  762. }
  763. else
  764. {
  765. impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id);
  766. }
  767. if (impl)
  768. {
  769. if (impl->isMediaTimeBased() && impl->isMediaPaused())
  770. {
  771. // Aha !... It's really a time-based media that was paused,
  772. // so un-pause it.
  773. impl->play();
  774. }
  775. else if (impl->isParcelMedia())
  776. {
  777. LLParcel* parcel = gViewerParcelMgr.getAgentParcel();
  778. if (parcel)
  779. {
  780. LLViewerParcelMedia::playMedia(parcel);
  781. }
  782. }
  783. }
  784. }
  785. }
  786. }
  787. //static
  788. void LLFloaterNearByMedia::onClickSelectedMediaPause(void* user_data)
  789. {
  790. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  791. if (self)
  792. {
  793. LLUUID selected_media_id = self->mMediaList->getValue().asUUID();
  794. if (selected_media_id == PARCEL_AUDIO_LIST_ITEM_UUID)
  795. {
  796. LLViewerParcelMedia::pauseMusic();
  797. }
  798. else if (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID)
  799. {
  800. LLViewerParcelMedia::pause();
  801. }
  802. else
  803. {
  804. LLViewerMediaImpl* impl;
  805. impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id);
  806. if (impl && impl->isMediaTimeBased() && impl->isMediaPlaying())
  807. {
  808. impl->pause();
  809. }
  810. }
  811. }
  812. }
  813. //static
  814. void LLFloaterNearByMedia::onClickSelectedMediaStop(void* user_data)
  815. {
  816. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  817. if (self)
  818. {
  819. self->mediaEnable(self->mMediaList->getValue().asUUID(), false);
  820. }
  821. }
  822. //static
  823. void LLFloaterNearByMedia::onCommitSelectedMediaVolume(LLUICtrl*,
  824. void* user_data)
  825. {
  826. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  827. if (self)
  828. {
  829. F32 volume = self->mVolumeSlider->getValueF32();
  830. LLUUID selected_media_id = self->mMediaList->getValue().asUUID();
  831. if (selected_media_id == PARCEL_AUDIO_LIST_ITEM_UUID)
  832. {
  833. gSavedSettings.setF32("AudioLevelMusic", volume);
  834. }
  835. else
  836. {
  837. LLViewerMediaImpl* impl;
  838. if (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID)
  839. {
  840. impl = (LLViewerMediaImpl*)LLViewerParcelMedia::getParcelMedia();
  841. }
  842. else
  843. {
  844. impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id);
  845. }
  846. if (impl)
  847. {
  848. impl->setVolume(volume);
  849. }
  850. }
  851. }
  852. }
  853. //static
  854. void LLFloaterNearByMedia::onClickSelectedMediaMute(void* user_data)
  855. {
  856. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  857. if (!self) return;
  858. LLUUID selected_media_id = self->mMediaList->getValue().asUUID();
  859. if (selected_media_id == PARCEL_AUDIO_LIST_ITEM_UUID)
  860. {
  861. gSavedSettings.setBool("MuteMusic", true);
  862. }
  863. else
  864. {
  865. LLViewerMediaImpl* impl;
  866. if (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID)
  867. {
  868. impl = (LLViewerMediaImpl*)LLViewerParcelMedia::getParcelMedia();
  869. }
  870. else
  871. {
  872. impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id);
  873. }
  874. if (impl)
  875. {
  876. impl->setMute();
  877. }
  878. }
  879. }
  880. //static
  881. void LLFloaterNearByMedia::onClickSelectedMediaUnmute(void* user_data)
  882. {
  883. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  884. if (!self) return;
  885. LLUUID selected_media_id = self->mMediaList->getValue().asUUID();
  886. if (selected_media_id == PARCEL_AUDIO_LIST_ITEM_UUID)
  887. {
  888. gSavedSettings.setBool("MuteMusic", false);
  889. }
  890. else
  891. {
  892. LLViewerMediaImpl* impl;
  893. if (selected_media_id == PARCEL_MEDIA_LIST_ITEM_UUID)
  894. {
  895. impl = (LLViewerMediaImpl*)LLViewerParcelMedia::getParcelMedia();
  896. }
  897. else
  898. {
  899. impl = LLViewerMedia::getMediaImplFromTextureID(selected_media_id);
  900. }
  901. if (impl)
  902. {
  903. F32 slider_volume = self->mVolumeSlider->getValueF32();
  904. if (slider_volume == 0.f)
  905. {
  906. impl->setMute(false);
  907. self->mVolumeSlider->setValue(impl->getVolume());
  908. }
  909. else
  910. {
  911. impl->setVolume(slider_volume);
  912. }
  913. }
  914. }
  915. }
  916. //static
  917. void LLFloaterNearByMedia::onClickSelectedMediaZoom(void* user_data)
  918. {
  919. LLFloaterNearByMedia* self = (LLFloaterNearByMedia*)user_data;
  920. if (self)
  921. {
  922. LLUUID media_id = self->mMediaList->getValue().asUUID();
  923. if (media_id.notNull() && media_id != PARCEL_AUDIO_LIST_ITEM_UUID &&
  924. media_id != PARCEL_MEDIA_LIST_ITEM_UUID)
  925. {
  926. LLViewerMediaFocus::getInstance()->focusZoomOnMedia(media_id);
  927. }
  928. }
  929. }
  930. //static
  931. void LLFloaterNearByMedia::onClickSelectedMediaUnzoom(void*)
  932. {
  933. LLViewerMediaFocus::getInstance()->unZoom();
  934. }
  935. //static
  936. void LLFloaterNearByMedia::onClickEnableAll(void*)
  937. {
  938. LLViewerMedia::setAllMediaEnabled(true);
  939. }
  940. //static
  941. void LLFloaterNearByMedia::onClickDisableAll(void*)
  942. {
  943. LLViewerMedia::setAllMediaEnabled(false);
  944. }
  945. //static
  946. void LLFloaterNearByMedia::onOpenPrefs(void*)
  947. {
  948. // To select the Media sub-tab:
  949. gSavedSettings.setS32("LastMediaPrefTab", 1);
  950. // Open the Preferences with the Audio & Media tab selected
  951. LLFloaterPreference::openInTab(LLFloaterPreference::AUDIO_AND_MEDIA_TAB);
  952. }
  953. // static
  954. void LLFloaterNearByMedia::getNameAndUrlHelper(LLViewerMediaImpl* impl,
  955. std::string& name,
  956. std::string& url,
  957. const std::string& default_name)
  958. {
  959. if (NULL == impl) return;
  960. name = impl->getName();
  961. url = impl->getCurrentMediaURL(); // This is the URL the media impl actually has loaded
  962. if (url.empty())
  963. {
  964. url = impl->getMediaEntryURL(); // This is the current URL from the media data
  965. }
  966. if (url.empty())
  967. {
  968. url = impl->getHomeURL(); // This is the home URL from the media data
  969. }
  970. if (name.empty())
  971. {
  972. name = url;
  973. }
  974. if (name.empty())
  975. {
  976. name = default_name;
  977. }
  978. }