<commit_before>/**
 * @file llpanellandaudio.cpp
 * @brief Allows configuration of "media" for a land parcel,
 *   for example movies, web pages, and audio.
 *
 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library 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.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llpanellandaudio.h"

// viewer includes
#include "llmimetypes.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "lluictrlfactory.h"

// library includes
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "llfloaterurlentry.h"
#include "llfocusmgr.h"
//#include "lllineeditor.h"	// <FS:CR> FIRE-593 - Unused since we use a combobox instead
#include "llparcel.h"
#include "lltextbox.h"
#include "llradiogroup.h"
#include "llspinctrl.h"
#include "llsdutil.h"
#include "lltexturectrl.h"
#include "roles_constants.h"
#include "llscrolllistctrl.h"

// Firestorm includes
#include "llviewercontrol.h"	// <FS:CR> FIRE-593 - Needed for gSavedSettings where we store our media list
#include "llclipboard.h"

// Values for the parcel voice settings radio group
enum
{
	kRadioVoiceChatEstate = 0,
	kRadioVoiceChatPrivate = 1,
	kRadioVoiceChatDisable = 2
};

//---------------------------------------------------------------------------
// LLPanelLandAudio
//---------------------------------------------------------------------------

LLPanelLandAudio::LLPanelLandAudio(LLParcelSelectionHandle& parcel)
:	LLPanel(/*std::string("land_media_panel")*/), mParcel(parcel)
{
}

// virtual
LLPanelLandAudio::~LLPanelLandAudio()
{
}

BOOL LLPanelLandAudio::postBuild()
{
	mCheckSoundLocal = getChild<LLCheckBoxCtrl>("check sound local");
	childSetCommitCallback("check sound local", onCommitAny, this);

	mCheckParcelEnableVoice = getChild<LLCheckBoxCtrl>("parcel_enable_voice_channel");
	childSetCommitCallback("parcel_enable_voice_channel", onCommitAny, this);

	// This one is always disabled so no need for a commit callback
	mCheckEstateDisabledVoice = getChild<LLCheckBoxCtrl>("parcel_enable_voice_channel_is_estate_disabled");

	mCheckParcelVoiceLocal = getChild<LLCheckBoxCtrl>("parcel_enable_voice_channel_local");
	childSetCommitCallback("parcel_enable_voice_channel_local", onCommitAny, this);

// <FS:CR> FIRE-593 - We use a combobox now, not a line editor, also set callbacks for new add/remove stream buttons
	//mMusicURLEdit = getChild<LLLineEditor>("music_url");
	mMusicURLEdit = getChild<LLComboBox>("music_url");
	childSetCommitCallback("music_url", onCommitAny, this);

	mBtnStreamAdd = getChild<LLButton>("stream_add_btn");
	childSetCommitCallback("stream_add_btn", onBtnStreamAdd, this);

	mBtnStreamDelete = getChild<LLButton>("stream_delete_btn");
	childSetCommitCallback("stream_delete_btn", onBtnStreamDelete, this);

	mBtnStreamCopyToClipboard = getChild<LLButton>("stream_copy_btn");
	childSetCommitCallback("stream_copy_btn", onBtnCopyToClipboard, this);
// </FS:CR>

	mCheckAVSoundAny = getChild<LLCheckBoxCtrl>("all av sound check");
	childSetCommitCallback("all av sound check", onCommitAny, this);

	mCheckAVSoundGroup = getChild<LLCheckBoxCtrl>("group av sound check");
	childSetCommitCallback("group av sound check", onCommitAny, this);

	return TRUE;
}

// public
void LLPanelLandAudio::refresh()
{
	LLParcel *parcel = mParcel->getParcel();

	if (!parcel)
	{
		clearCtrls();
	}
	else
	{
		// something selected, hooray!

		// Display options
		BOOL can_change_media = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA);

		mCheckSoundLocal->set( parcel->getSoundLocal() );
		mCheckSoundLocal->setEnabled( can_change_media );

		bool allow_voice = parcel->getParcelFlagAllowVoice();

		LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
		if (region && region->isVoiceEnabled())
		{
			mCheckEstateDisabledVoice->setVisible(false);

			mCheckParcelEnableVoice->setVisible(true);
			mCheckParcelEnableVoice->setEnabled( can_change_media );
			mCheckParcelEnableVoice->set(allow_voice);

			mCheckParcelVoiceLocal->setEnabled( can_change_media && allow_voice );
		}
		else
		{
			// Voice disabled at estate level, overrides parcel settings
			// Replace the parcel voice checkbox with a disabled one
			// labelled with an explanatory message
			mCheckEstateDisabledVoice->setVisible(true);

			mCheckParcelEnableVoice->setVisible(false);
			mCheckParcelEnableVoice->setEnabled(false);
			mCheckParcelVoiceLocal->setEnabled(false);
		}

		mCheckParcelEnableVoice->set(allow_voice);
		mCheckParcelVoiceLocal->set(!parcel->getParcelFlagUseEstateVoiceChannel());

// <FS:CR> FIRE-593 - Populate the audio combobox with our saved urls, then add the parcel's current url up top.
		//mMusicURLEdit->setText(parcel->getMusicURL());
		std::string current_url = parcel->getMusicURL();
		mMusicURLEdit->clearRows();
		LLSD streamlist = gSavedSettings.getLLSD("FSStreamList");
		LLSD streams = streamlist["audio"];

		for(LLSD::array_iterator s_itr = streams.beginArray(); s_itr != streams.endArray(); ++s_itr)
		{
			mMusicURLEdit->add(LLSD(*s_itr));
			LL_DEBUGS() << "adding: " << *s_itr << " to the audio stream combo." << LL_ENDL;
		}
		mMusicURLEdit->addSeparator(ADD_TOP);
		mMusicURLEdit->add(LLSD(current_url), ADD_TOP);
		mMusicURLEdit->selectByValue(current_url);

		mBtnStreamAdd->setEnabled( can_change_media );
		mBtnStreamDelete->setEnabled( can_change_media );
		mBtnStreamCopyToClipboard->setEnabled(TRUE);
// </FS:CR>
		mMusicURLEdit->setEnabled( can_change_media );

		BOOL can_change_av_sounds = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_OPTIONS) && parcel->getHaveNewParcelLimitData();
		mCheckAVSoundAny->set(parcel->getAllowAnyAVSounds());
		mCheckAVSoundAny->setEnabled(can_change_av_sounds);

		mCheckAVSoundGroup->set(parcel->getAllowGroupAVSounds() || parcel->getAllowAnyAVSounds());	// On if "Everyone" is on
		mCheckAVSoundGroup->setEnabled(can_change_av_sounds && !parcel->getAllowAnyAVSounds());		// Enabled if "Everyone" is off
	}
}
// static
void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata)
{
	LLPanelLandAudio *self = (LLPanelLandAudio *)userdata;

	LLParcel* parcel = self->mParcel->getParcel();
	if (!parcel)
	{
		return;
	}

	// Extract data from UI
	BOOL sound_local		= self->mCheckSoundLocal->get();
// <FS:CR> FIRE-593 - It's a combobox now
	//std::string music_url = self->mMusicURLEdit->getText();
	std::string music_url = self->mMusicURLEdit->getSimple();
// </FS:CR>

	BOOL voice_enabled = self->mCheckParcelEnableVoice->get();
	BOOL voice_estate_chan = !self->mCheckParcelVoiceLocal->get();

	BOOL any_av_sound		= self->mCheckAVSoundAny->get();
	BOOL group_av_sound		= TRUE;		// If set to "Everyone" then group is checked as well
	if (!any_av_sound)
	{	// If "Everyone" is off, use the value from the checkbox
		group_av_sound = self->mCheckAVSoundGroup->get();
	}

	// Remove leading/trailing whitespace (common when copying/pasting)
	LLStringUtil::trim(music_url);

	// Push data into current parcel
	parcel->setParcelFlag(PF_ALLOW_VOICE_CHAT, voice_enabled);
	parcel->setParcelFlag(PF_USE_ESTATE_VOICE_CHAN, voice_estate_chan);
	parcel->setParcelFlag(PF_SOUND_LOCAL, sound_local);
	parcel->setMusicURL(music_url);
	parcel->setAllowAnyAVSounds(any_av_sound);
	parcel->setAllowGroupAVSounds(group_av_sound);

	// Send current parcel data upstream to server
	LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel );

	// Might have changed properties, so let's redraw!
	self->refresh();
}

// <FS:CR> FIRE-593 - Add/remove streams from the list with these. They're fantastic!
// static
void LLPanelLandAudio::onBtnStreamAdd(LLUICtrl*, void *userdata)
{
	LLPanelLandAudio *self = (LLPanelLandAudio *)userdata;

	std::string music_url = self->mMusicURLEdit->getSimple();
	LLStringUtil::trim(music_url);

	if (!music_url.empty())
	{
		LLSD streamlist = gSavedSettings.getLLSD("FSStreamList");
		streamlist["version"] = 1;
		streamlist["audio"].append(music_url);
		gSavedSettings.setLLSD("FSStreamList", streamlist);
		self->refresh();
	}
}

// static
void LLPanelLandAudio::onBtnStreamDelete(LLUICtrl*, void *userdata)
{
	LLPanelLandAudio *self = (LLPanelLandAudio *)userdata;

	std::string music_url = self->mMusicURLEdit->getSimple();
	LLStringUtil::trim(music_url);

	LLSD streamlist = gSavedSettings.getLLSD("FSStreamList");
	LLSD streamlist_new;
	streamlist_new["version"] = 1;

	for (LLSD::array_const_iterator it = streamlist["audio"].beginArray(); it != streamlist["audio"].endArray(); ++it)
	{
		std::string current_url = (*it).asString();
		if (current_url != music_url)
		{
			streamlist_new["audio"].append(current_url);
		}
	}

	gSavedSettings.setLLSD("FSStreamList", streamlist_new);
	self->refresh();
}

//static
void LLPanelLandAudio::onBtnCopyToClipboard(LLUICtrl*, void *userdata)
{
	LLPanelLandAudio *self = (LLPanelLandAudio *)userdata;
	std::string music_url = self->mMusicURLEdit->getSimple();
	LLStringUtil::trim(music_url);

	if (!music_url.empty())
	{
		LLClipboard::instance().copyToClipboard(utf8str_to_wstring(music_url), 0, music_url.size() );
	}
}
// </FS:CR>
<commit_msg>FIRE-14644: Automatically add http:// to music url in parcel audio panel; patch by Samm Florian<commit_after>/**
 * @file llpanellandaudio.cpp
 * @brief Allows configuration of "media" for a land parcel,
 *   for example movies, web pages, and audio.
 *
 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library 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.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llpanellandaudio.h"

// viewer includes
#include "llmimetypes.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "lluictrlfactory.h"

// library includes
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "llfloaterurlentry.h"
#include "llfocusmgr.h"
//#include "lllineeditor.h"	// <FS:CR> FIRE-593 - Unused since we use a combobox instead
#include "llparcel.h"
#include "lltextbox.h"
#include "llradiogroup.h"
#include "llspinctrl.h"
#include "llsdutil.h"
#include "lltexturectrl.h"
#include "roles_constants.h"
#include "llscrolllistctrl.h"

// Firestorm includes
#include "llviewercontrol.h"	// <FS:CR> FIRE-593 - Needed for gSavedSettings where we store our media list
#include "llclipboard.h"

// Values for the parcel voice settings radio group
enum
{
	kRadioVoiceChatEstate = 0,
	kRadioVoiceChatPrivate = 1,
	kRadioVoiceChatDisable = 2
};

//---------------------------------------------------------------------------
// LLPanelLandAudio
//---------------------------------------------------------------------------

LLPanelLandAudio::LLPanelLandAudio(LLParcelSelectionHandle& parcel)
:	LLPanel(/*std::string("land_media_panel")*/), mParcel(parcel)
{
}

// virtual
LLPanelLandAudio::~LLPanelLandAudio()
{
}

BOOL LLPanelLandAudio::postBuild()
{
	mCheckSoundLocal = getChild<LLCheckBoxCtrl>("check sound local");
	childSetCommitCallback("check sound local", onCommitAny, this);

	mCheckParcelEnableVoice = getChild<LLCheckBoxCtrl>("parcel_enable_voice_channel");
	childSetCommitCallback("parcel_enable_voice_channel", onCommitAny, this);

	// This one is always disabled so no need for a commit callback
	mCheckEstateDisabledVoice = getChild<LLCheckBoxCtrl>("parcel_enable_voice_channel_is_estate_disabled");

	mCheckParcelVoiceLocal = getChild<LLCheckBoxCtrl>("parcel_enable_voice_channel_local");
	childSetCommitCallback("parcel_enable_voice_channel_local", onCommitAny, this);

// <FS:CR> FIRE-593 - We use a combobox now, not a line editor, also set callbacks for new add/remove stream buttons
	//mMusicURLEdit = getChild<LLLineEditor>("music_url");
	mMusicURLEdit = getChild<LLComboBox>("music_url");
	childSetCommitCallback("music_url", onCommitAny, this);

	mBtnStreamAdd = getChild<LLButton>("stream_add_btn");
	childSetCommitCallback("stream_add_btn", onBtnStreamAdd, this);

	mBtnStreamDelete = getChild<LLButton>("stream_delete_btn");
	childSetCommitCallback("stream_delete_btn", onBtnStreamDelete, this);

	mBtnStreamCopyToClipboard = getChild<LLButton>("stream_copy_btn");
	childSetCommitCallback("stream_copy_btn", onBtnCopyToClipboard, this);
// </FS:CR>

	mCheckAVSoundAny = getChild<LLCheckBoxCtrl>("all av sound check");
	childSetCommitCallback("all av sound check", onCommitAny, this);

	mCheckAVSoundGroup = getChild<LLCheckBoxCtrl>("group av sound check");
	childSetCommitCallback("group av sound check", onCommitAny, this);

	return TRUE;
}

// public
void LLPanelLandAudio::refresh()
{
	LLParcel *parcel = mParcel->getParcel();

	if (!parcel)
	{
		clearCtrls();
	}
	else
	{
		// something selected, hooray!

		// Display options
		BOOL can_change_media = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA);

		mCheckSoundLocal->set( parcel->getSoundLocal() );
		mCheckSoundLocal->setEnabled( can_change_media );

		bool allow_voice = parcel->getParcelFlagAllowVoice();

		LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
		if (region && region->isVoiceEnabled())
		{
			mCheckEstateDisabledVoice->setVisible(false);

			mCheckParcelEnableVoice->setVisible(true);
			mCheckParcelEnableVoice->setEnabled( can_change_media );
			mCheckParcelEnableVoice->set(allow_voice);

			mCheckParcelVoiceLocal->setEnabled( can_change_media && allow_voice );
		}
		else
		{
			// Voice disabled at estate level, overrides parcel settings
			// Replace the parcel voice checkbox with a disabled one
			// labelled with an explanatory message
			mCheckEstateDisabledVoice->setVisible(true);

			mCheckParcelEnableVoice->setVisible(false);
			mCheckParcelEnableVoice->setEnabled(false);
			mCheckParcelVoiceLocal->setEnabled(false);
		}

		mCheckParcelEnableVoice->set(allow_voice);
		mCheckParcelVoiceLocal->set(!parcel->getParcelFlagUseEstateVoiceChannel());

// <FS:CR> FIRE-593 - Populate the audio combobox with our saved urls, then add the parcel's current url up top.
		//mMusicURLEdit->setText(parcel->getMusicURL());
		std::string current_url = parcel->getMusicURL();
		mMusicURLEdit->clearRows();
		LLSD streamlist = gSavedSettings.getLLSD("FSStreamList");
		LLSD streams = streamlist["audio"];

		for(LLSD::array_iterator s_itr = streams.beginArray(); s_itr != streams.endArray(); ++s_itr)
		{
			mMusicURLEdit->add(LLSD(*s_itr));
			LL_DEBUGS() << "adding: " << *s_itr << " to the audio stream combo." << LL_ENDL;
		}
		mMusicURLEdit->addSeparator(ADD_TOP);
		mMusicURLEdit->add(LLSD(current_url), ADD_TOP);
		mMusicURLEdit->selectByValue(current_url);

		mBtnStreamAdd->setEnabled( can_change_media );
		mBtnStreamDelete->setEnabled( can_change_media );
		mBtnStreamCopyToClipboard->setEnabled(TRUE);
// </FS:CR>
		mMusicURLEdit->setEnabled( can_change_media );

		BOOL can_change_av_sounds = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_OPTIONS) && parcel->getHaveNewParcelLimitData();
		mCheckAVSoundAny->set(parcel->getAllowAnyAVSounds());
		mCheckAVSoundAny->setEnabled(can_change_av_sounds);

		mCheckAVSoundGroup->set(parcel->getAllowGroupAVSounds() || parcel->getAllowAnyAVSounds());	// On if "Everyone" is on
		mCheckAVSoundGroup->setEnabled(can_change_av_sounds && !parcel->getAllowAnyAVSounds());		// Enabled if "Everyone" is off
	}
}
// static
void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata)
{
	LLPanelLandAudio *self = (LLPanelLandAudio *)userdata;

	LLParcel* parcel = self->mParcel->getParcel();
	if (!parcel)
	{
		return;
	}

	// Extract data from UI
	BOOL sound_local		= self->mCheckSoundLocal->get();
// <FS:CR> FIRE-593 - It's a combobox now
	//std::string music_url = self->mMusicURLEdit->getText();
	std::string music_url = self->mMusicURLEdit->getSimple();
// </FS:CR>

	BOOL voice_enabled = self->mCheckParcelEnableVoice->get();
	BOOL voice_estate_chan = !self->mCheckParcelVoiceLocal->get();

	BOOL any_av_sound		= self->mCheckAVSoundAny->get();
	BOOL group_av_sound		= TRUE;		// If set to "Everyone" then group is checked as well
	if (!any_av_sound)
	{	// If "Everyone" is off, use the value from the checkbox
		group_av_sound = self->mCheckAVSoundGroup->get();
	}

	// Remove leading/trailing whitespace (common when copying/pasting)
	LLStringUtil::trim(music_url);

	// <FS> Add leading http:// if not already present
	if (!music_url.empty() && music_url.find("://") == std::string::npos)
	{
		music_url.insert(0, "http://");
	}
	// </FS>

	// Push data into current parcel
	parcel->setParcelFlag(PF_ALLOW_VOICE_CHAT, voice_enabled);
	parcel->setParcelFlag(PF_USE_ESTATE_VOICE_CHAN, voice_estate_chan);
	parcel->setParcelFlag(PF_SOUND_LOCAL, sound_local);
	parcel->setMusicURL(music_url);
	parcel->setAllowAnyAVSounds(any_av_sound);
	parcel->setAllowGroupAVSounds(group_av_sound);

	// Send current parcel data upstream to server
	LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel );

	// Might have changed properties, so let's redraw!
	self->refresh();
}

// <FS:CR> FIRE-593 - Add/remove streams from the list with these. They're fantastic!
// static
void LLPanelLandAudio::onBtnStreamAdd(LLUICtrl*, void *userdata)
{
	LLPanelLandAudio *self = (LLPanelLandAudio *)userdata;

	std::string music_url = self->mMusicURLEdit->getSimple();
	LLStringUtil::trim(music_url);

	if (!music_url.empty())
	{
		LLSD streamlist = gSavedSettings.getLLSD("FSStreamList");
		streamlist["version"] = 1;
		streamlist["audio"].append(music_url);
		gSavedSettings.setLLSD("FSStreamList", streamlist);
		self->refresh();
	}
}

// static
void LLPanelLandAudio::onBtnStreamDelete(LLUICtrl*, void *userdata)
{
	LLPanelLandAudio *self = (LLPanelLandAudio *)userdata;

	std::string music_url = self->mMusicURLEdit->getSimple();
	LLStringUtil::trim(music_url);

	LLSD streamlist = gSavedSettings.getLLSD("FSStreamList");
	LLSD streamlist_new;
	streamlist_new["version"] = 1;

	for (LLSD::array_const_iterator it = streamlist["audio"].beginArray(); it != streamlist["audio"].endArray(); ++it)
	{
		std::string current_url = (*it).asString();
		if (current_url != music_url)
		{
			streamlist_new["audio"].append(current_url);
		}
	}

	gSavedSettings.setLLSD("FSStreamList", streamlist_new);
	self->refresh();
}

//static
void LLPanelLandAudio::onBtnCopyToClipboard(LLUICtrl*, void *userdata)
{
	LLPanelLandAudio *self = (LLPanelLandAudio *)userdata;
	std::string music_url = self->mMusicURLEdit->getSimple();
	LLStringUtil::trim(music_url);

	if (!music_url.empty())
	{
		LLClipboard::instance().copyToClipboard(utf8str_to_wstring(music_url), 0, music_url.size() );
	}
}
// </FS:CR>
<|endoftext|>


<commit_before>/// \file ROOT/TCanvas.hxx
/// \ingroup Gpad ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2015-07-08
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_TCanvas
#define ROOT7_TCanvas

#include "ROOT/TPad.hxx"
#include "ROOT/TVirtualCanvasPainter.hxx"

#include <memory>
#include <string>
#include <vector>

namespace ROOT {
namespace Experimental {

class TDrawingOptsBaseNoDefault;
template <class PRIMITIVE>
class TDrawingAttrRef;

/** \class ROOT::Experimental::TCanvas
  A window's topmost `TPad`.
  */

class TCanvas: public TPadBase {
private:
   /// Title of the canvas.
   std::string fTitle;

   /// Size of the canvas in pixels,
   std::array<TPadCoord::Pixel, 2> fSize;

   /// Modify counter, incremented every time canvas is changed
   uint64_t fModified; ///<!

   /// The painter of this canvas, bootstrapping the graphics connection.
   /// Unmapped canvases (those that never had `Draw()` invoked) might not have
   /// a painter.
   std::unique_ptr<Internal::TVirtualCanvasPainter> fPainter; ///<!

   /// Disable copy construction for now.
   TCanvas(const TCanvas &) = delete;

   /// Disable assignment for now.
   TCanvas &operator=(const TCanvas &) = delete;

public:
   static std::shared_ptr<TCanvas> Create(const std::string &title);

   /// Create a temporary TCanvas; for long-lived ones please use Create().
   TCanvas() = default;

   ~TCanvas() = default;

   const TCanvas &GetCanvas() const override { return *this; }

   /// Access to the top-most canvas, if any (non-const version).
   TCanvas &GetCanvas() override { return *this; }

   /// Return canvas pixel size as array with two elements - width and height
   const std::array<TPadCoord::Pixel, 2> &GetSize() const { return fSize; }

   /// Set canvas pixel size as array with two elements - width and height
   void SetSize(const std::array<TPadCoord::Pixel, 2> &sz) { fSize = sz; }

   /// Set canvas pixel size - width and height
   void SetSize(const TPadCoord::Pixel &width, const TPadCoord::Pixel &height)
   {
      fSize[0] = width;
      fSize[1] = height;
   }

   /// Display the canvas.
   void Show(const std::string &where = "");

   /// Close all canvas displays
   void Hide();

   /// Insert panel into the canvas, canvas should be shown at this moment
   template <class PANEL>
   bool AddPanel(std::shared_ptr<PANEL> &panel) {
      if (!fPainter) return false;
      return fPainter->AddPanel(panel->GetWindow());
   }

   // Indicates that primitives list was changed or any primitive was modified
   void Modified() { fModified++; }

   // Return if canvas was modified and not yet updated
   bool IsModified() const;

   /// update drawing
   void Update(bool async = false, CanvasCallback_t callback = nullptr);

   /// Save canvas in image file
   void SaveAs(const std::string &filename, bool async = false, CanvasCallback_t callback = nullptr);

   /// Get the canvas's title.
   const std::string &GetTitle() const { return fTitle; }

   /// Set the canvas's title.
   void SetTitle(const std::string &title) { fTitle = title; }

   /// Convert a `Pixel` position to Canvas-normalized positions.
   std::array<TPadCoord::Normal, 2> PixelsToNormal(const std::array<TPadCoord::Pixel, 2> &pos) const final
   {
      return {{pos[0] / fSize[0], pos[1] / fSize[1]}};
   }

   static const std::vector<std::shared_ptr<TCanvas>> &GetCanvases();
};

} // namespace Experimental
} // namespace ROOT

#endif
<commit_msg>Adapt to change in return type in base.<commit_after>/// \file ROOT/TCanvas.hxx
/// \ingroup Gpad ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2015-07-08
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_TCanvas
#define ROOT7_TCanvas

#include "ROOT/TPad.hxx"
#include "ROOT/TVirtualCanvasPainter.hxx"

#include <memory>
#include <string>
#include <vector>

namespace ROOT {
namespace Experimental {

class TDrawingOptsBaseNoDefault;
template <class PRIMITIVE>
class TDrawingAttrRef;

/** \class ROOT::Experimental::TCanvas
  A window's topmost `TPad`.
  */

class TCanvas: public TPadBase {
private:
   /// Title of the canvas.
   std::string fTitle;

   /// Size of the canvas in pixels,
   std::array<TPadCoord::Pixel, 2> fSize;

   /// Modify counter, incremented every time canvas is changed
   uint64_t fModified; ///<!

   /// The painter of this canvas, bootstrapping the graphics connection.
   /// Unmapped canvases (those that never had `Draw()` invoked) might not have
   /// a painter.
   std::unique_ptr<Internal::TVirtualCanvasPainter> fPainter; ///<!

   /// Disable copy construction for now.
   TCanvas(const TCanvas &) = delete;

   /// Disable assignment for now.
   TCanvas &operator=(const TCanvas &) = delete;

public:
   static std::shared_ptr<TCanvas> Create(const std::string &title);

   /// Create a temporary TCanvas; for long-lived ones please use Create().
   TCanvas() = default;

   ~TCanvas() = default;

   const TCanvas *GetCanvas() const override { return this; }

   /// Access to the top-most canvas, if any (non-const version).
   TCanvas *GetCanvas() override { return this; }

   /// Return canvas pixel size as array with two elements - width and height
   const std::array<TPadCoord::Pixel, 2> &GetSize() const { return fSize; }

   /// Set canvas pixel size as array with two elements - width and height
   void SetSize(const std::array<TPadCoord::Pixel, 2> &sz) { fSize = sz; }

   /// Set canvas pixel size - width and height
   void SetSize(const TPadCoord::Pixel &width, const TPadCoord::Pixel &height)
   {
      fSize[0] = width;
      fSize[1] = height;
   }

   /// Display the canvas.
   void Show(const std::string &where = "");

   /// Close all canvas displays
   void Hide();

   /// Insert panel into the canvas, canvas should be shown at this moment
   template <class PANEL>
   bool AddPanel(std::shared_ptr<PANEL> &panel) {
      if (!fPainter) return false;
      return fPainter->AddPanel(panel->GetWindow());
   }

   // Indicates that primitives list was changed or any primitive was modified
   void Modified() { fModified++; }

   // Return if canvas was modified and not yet updated
   bool IsModified() const;

   /// update drawing
   void Update(bool async = false, CanvasCallback_t callback = nullptr);

   /// Save canvas in image file
   void SaveAs(const std::string &filename, bool async = false, CanvasCallback_t callback = nullptr);

   /// Get the canvas's title.
   const std::string &GetTitle() const { return fTitle; }

   /// Set the canvas's title.
   void SetTitle(const std::string &title) { fTitle = title; }

   /// Convert a `Pixel` position to Canvas-normalized positions.
   std::array<TPadCoord::Normal, 2> PixelsToNormal(const std::array<TPadCoord::Pixel, 2> &pos) const final
   {
      return {{pos[0] / fSize[0], pos[1] / fSize[1]}};
   }

   static const std::vector<std::shared_ptr<TCanvas>> &GetCanvases();
};

} // namespace Experimental
} // namespace ROOT

#endif
<|endoftext|>


<commit_before>/*
 *  ARC++
 *
 *  Copyright (c) 2007-2008 Steven Noonan.
 *
 *  Licensed under the New BSD License.
 *
 */

#include "universal_include.h"

#include "App/app.h"
#include "App/preferences.h"
#include "App/resource.h"
#include "App/string_utils.h"
#include "App/text_stream_readers.h"

Preferences *g_prefsManager = NULL;

PrefsItem::PrefsItem()
:   m_key(NULL),
    m_str(NULL),
    m_int(0)
{
}

PrefsItem::PrefsItem(char *_line)
:    m_str(NULL)
{
    // Get key
    char *key = _line;
    while (!isalnum(*key) && *key != '\0')        // Skip leading whitespace
    {
        key++;
    }
    char *c = key;
    while (isalnum(*c))                            // Find the end of the key word
    {
        c++;
    }
    *c = '\0';
    m_key = newStr(key);

    // Get value
    char *value = c + 1;
    while (isspace(*value) || *value == '=')
    {
        if (value == '\0') break;
        value++;
    }

    // Is value a number?
    if (value[0] == '-' || isdigit(value[0]))
    {
        // Guess that number is an int
        m_type = TypeInt;

        // Verify that guess
        c = value;
        int numDots = 0;
        while (*c != '\0')
        {
            if (*c == '.')
            {
                ++numDots;
            }
            ++c;
        }
        if( numDots == 1 ) m_type = TypeFloat;
        else if(  numDots > 1 ) m_type = TypeString;

        // Convert string into a real number
        if      (m_type == TypeFloat)        m_float = (float)atof(value);
        else if (m_type == TypeString)      m_str = newStr(value);
        else                                m_int = atoi(value);
    }
    else
    {
        m_type = TypeString;
        m_str = newStr(value);
    }
}

PrefsItem::PrefsItem(char const *_key, char const *_str)
:   m_type(TypeString)
{
    m_key = newStr(_key);
    m_str = newStr(_str);
}

PrefsItem::PrefsItem(char const *_key, float _float)
:   m_type(TypeFloat),
    m_str(NULL),
    m_float(_float)
{
    m_key = newStr(_key);
}

PrefsItem::PrefsItem(char const *_key, int _int)
:    m_type(TypeInt),
    m_str(NULL),
    m_int(_int)
{
    m_key = newStr(_key);
}

PrefsItem::~PrefsItem()
{
    delete [] m_key; m_key = NULL;
    delete [] m_str; m_str = NULL;
}

Preferences::Preferences(char const *_filename)
{
    m_filename = newStr(_filename);

    Load();

}

Preferences::Preferences(std::string const &_filename)
{
    m_filename = newStr(_filename.c_str());

    Load();
}

Preferences::~Preferences()
{
    delete [] m_filename; m_filename = NULL;
    Clear();
}

bool Preferences::IsLineEmpty(char const *_line)
{
    while (_line[0] != '\0')
    {
        if (_line[0] == '#') return true;
        if (isalnum(_line[0])) return false;
        ++_line;
    }

    return true;
}

void Preferences::CreateDefaultValues()
{

    // We default to the best possible preferences for performance and
    // so forth on the latest-and-greatest machines.

	AddLine( "# PrimaryRenderer\n" );
	AddLine( "#   direct3d: Experimental Direct3D 9 renderer (Windows only)\n" );
	AddLine( "#   opengl: OpenGL renderer (recommended)\n" );
	AddLine( "#   sdl: SDL renderer\n" );
    AddLine( "PrimaryRenderer = opengl" );
	AddLine( "\n" );
	AddLine( "# SecondaryRenderer\n" );
	AddLine( "#  The SDL rendering engine uses this as the backend renderer.\n" );
	AddLine( "#   windib: DIB rendering (Windows only)\n" );
	AddLine( "#   directx: DirectDraw rendering (Windows only)\n" );
	AddLine( "#   dga: Direct X11 framebuffer access\n" );
#ifdef TARGET_OS_WINDOWS
    AddLine( "SecondaryRenderer = windib" );
#elif defined ( TARGET_OS_LINUX )
    AddLine( "SecondaryRenderer = dga" );
#endif
	AddLine( "\n" );
    AddLine( "TextureCompression = 0" );
    AddLine( "TextureRectangles = 0" );
	// AddLine ( "RenderMode = 0" );

    AddLine( "\n" );

	AddLine ( "IgnoreDataFiles = 0" );
	AddLine ( "DumpOpenGLInfo = 0" );

	AddLine ( "\n" );

#ifdef INTERNAL_BUILD
    AddLine( "ScreenWindowed = 1" );
#else
    AddLine( "ScreenWindowed = 0" );
#endif
    AddLine( "ScreenWidth = 800" );
    AddLine( "ScreenHeight = 600" );
    AddLine( "ScreenColourDepth = 32" );
    AddLine( "WaitVerticalRetrace = 1" );

	AddLine( "\n" );

	// AddLine( "SurfaceSplitFactor = 32" );

    // AddLine( "\n" );

    AddLine( "SoundChannels = 32" );
    AddLine( "SoundMixFreq = 22050" );
    AddLine( "SoundBufferSize = 512" );

    AddLine( "\n" );

    // Override the defaults above with stuff from a default preferences file
    if ( g_app && g_app->m_resource )
    {
        TextReader *reader = g_app->m_resource->GetTextReader( "default_preferences.txt" );
        if ( reader && reader->IsOpen() )
        {
            while ( reader->ReadLine() )
            {
                AddLine( reader->GetRestOfLine(), true );
            }
        }
        delete reader;
    }

}

void Preferences::Load(char const *_filename)
{
    if (!_filename) _filename = m_filename;

    Data::DArray<PrefsItem *> *items = m_items.ConvertToDArray();
    for ( size_t i = 0; i < items->size(); i++ )
        if ( items->valid(i) )
            delete items->get(i);
    delete items;
    m_items.empty();

    // Try to read preferences if they exist
    FILE *in = fopen(_filename, "r");

    if( !in )
    {
        // Probably first time running the game
        CreateDefaultValues();
    }
    else
    {
        char line[256];
        while (fgets(line, 256, in) != NULL)
        {
            AddLine( line );
        }
        fclose(in);
    }

    if ( m_items.size() < 1 ) CreateDefaultValues();

#ifdef DEMOBUILD
    AddLine( OTHER_DIFFICULTY " = 1", true );
#endif
}

void Preferences::SaveItem(FILE *out, PrefsItem *_item)
{
    switch (_item->m_type)
    {
        case PrefsItem::TypeFloat:
            fprintf(out, "%s = %.2f\n", _item->m_key, _item->m_float);
            break;
        case PrefsItem::TypeInt:
            fprintf(out, "%s = %d\n", _item->m_key, _item->m_int);
            break;
        case PrefsItem::TypeString:
            fprintf(out, "%s = %s\n", _item->m_key, _item->m_str);
            break;
    }
    _item->m_hasBeenWritten = true;
}

void Preferences::Save()
{
    // We've got a copy of the plain text from the prefs file that we initially
    // loaded in the variable m_fileText. We use that file as a template with
    // which to create the new save file. Updated prefs items values are looked up
    // as it their turn to be output comes around. When we've finished we then
    // write out all the new prefs items because they didn't exist in m_fileText.

	size_t i;

    // First clear the "has been written" flags on all the items
    Data::DArray<PrefsItem *> *items = m_items.ConvertToDArray();
    for ( i = 0; i < items->size(); ++i )
    {
        if ( items->valid ( i ) )
        {
            items->get(i)->m_hasBeenWritten = false;
        }
    }
    delete items;

    // Now use m_fileText as a template to write most of the items
    FILE *out = fopen(m_filename, "w");

    // If we couldn't open the prefs file for writing then just silently fail -
    // it's better than crashing.
    if (!out)
    {
        return;
    }

    for ( i = 0; i < m_fileText.size(); ++i )
    {
        if ( !m_fileText.valid ( i ) ) continue;
        char const *line = m_fileText[i];
        if (IsLineEmpty(line))
        {
            fprintf(out, line);
        }
        else
        {
            char const *c = line;
            char const *keyStart = NULL;
            char const *keyEnd = NULL;
            while (*c != '=')
            {
                if (keyStart)
                {
                    if (!isalnum(c[0]))
                    {
                        keyEnd = c;
                    }
                }
                else
                {
                    if (isalnum(c[0]))
                    {
                        keyStart = c;
                    }
                }
                ++c;
            }
            char key[128];
            int keyLen = keyEnd - keyStart;
            strncpy(key, keyStart, keyLen);
            key[keyLen] = '\0';
            PrefsItem *item;
			bool exists = m_items.find(key, item);
			ARCReleaseAssert ( exists );
            SaveItem(out, item);
        }
    }

    // Finally output any items that haven't already been written
    items = m_items.ConvertToDArray();
    for ( i = 0; i < items->size(); ++i )
    {
        if ( items->valid ( i ) )
        {
            PrefsItem *item = items->get ( i );
            if ( !item->m_hasBeenWritten )
            {
                SaveItem(out, item);
            }
        }
    }
    delete items;

    fclose(out);
}

void Preferences::Clear()
{
    Data::DArray<PrefsItem *> *items = m_items.ConvertToDArray();
	size_t i;
    for ( i = 0; i < items->size(); i++ )
        if ( items->valid(i) )
            delete items->get(i);
    delete items;
    m_items.empty();
    for ( i = 0; i < m_fileText.size(); i++ )
        if ( m_fileText.valid ( i ) )
            delete m_fileText.get ( i );
}

float Preferences::GetFloat(char const *_key, float _default) const
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists ) return _default;
    if (item->m_type != PrefsItem::TypeFloat) return _default;
    return item->m_float;
}

int Preferences::GetInt(char const *_key, int _default) const
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists ) return _default;
    if (item->m_type != PrefsItem::TypeInt) return _default;
    return item->m_int;
}

const char *Preferences::GetString(char const *_key, const char *_default) const
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists ) return _default;
    if (item->m_type != PrefsItem::TypeString) return _default;
    return item->m_str;
}

void Preferences::SetString(char const *_key, char const *_string)
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists )
    {
        item = new PrefsItem(_key, _string);
        m_items.insert ( item->m_key, item );
    }
    else
    {
        ARCDebugAssert ( item->m_type == PrefsItem::TypeString );
        char *newString = newStr(_string);
        delete [] item->m_str; item->m_str = NULL;
        // Note by Chris:
        // The incoming value of _string might also be item->m_str
        // So it is essential to copy _string before freeing item->m_str
        item->m_str = newString;
    }
}

void Preferences::SetFloat(char const *_key, float _float)
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists )
    {
        item = new PrefsItem ( _key, _float );
        m_items.insert ( item->m_key, item );
    }
    else
    {
        ARCDebugAssert ( item->m_type == PrefsItem::TypeFloat );
        item->m_float = _float;
    }
}

void Preferences::SetInt(char const *_key, int _int)
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists )
    {
        item = new PrefsItem(_key, _int);
        m_items.insert ( item->m_key, item );
    }
    else
    {
        ARCDebugAssert ( item->m_type == PrefsItem::TypeInt );
        item->m_int = _int;
    }
}

void Preferences::AddLine(char const*_line, bool _overwrite)
{
    if ( !_line )
        return;

    bool saveLine = true;

    if (!IsLineEmpty(_line))                // Skip comment lines and blank lines
    {
        char *localCopy = newStr( _line );
        char *c = strchr(localCopy, '\n');
        if (c)
            *c = '\0';

        PrefsItem *item = new PrefsItem(localCopy);

        PrefsItem *idx;
		bool exists = m_items.find ( item->m_key, idx );
        if ( _overwrite && exists ) {
            delete idx;
            m_items.erase ( item->m_key );
            saveLine = false;
        }

        m_items.insert ( item->m_key, item );
        delete [] localCopy; localCopy = NULL;
    }

    if ( saveLine ) {
        char *lineCopy = newStr(_line);
        m_fileText.insert ( lineCopy );
    }
}

bool Preferences::DoesKeyExist(char const *_key)
{
    return m_items.exists ( _key );
}
<commit_msg>preferences: make Direct3D the default renderer<commit_after>/*
 *  ARC++
 *
 *  Copyright (c) 2007-2008 Steven Noonan.
 *
 *  Licensed under the New BSD License.
 *
 */

#include "universal_include.h"

#include "App/app.h"
#include "App/preferences.h"
#include "App/resource.h"
#include "App/string_utils.h"
#include "App/text_stream_readers.h"

Preferences *g_prefsManager = NULL;

PrefsItem::PrefsItem()
:   m_key(NULL),
    m_str(NULL),
    m_int(0)
{
}

PrefsItem::PrefsItem(char *_line)
:    m_str(NULL)
{
    // Get key
    char *key = _line;
    while (!isalnum(*key) && *key != '\0')        // Skip leading whitespace
    {
        key++;
    }
    char *c = key;
    while (isalnum(*c))                            // Find the end of the key word
    {
        c++;
    }
    *c = '\0';
    m_key = newStr(key);

    // Get value
    char *value = c + 1;
    while (isspace(*value) || *value == '=')
    {
        if (value == '\0') break;
        value++;
    }

    // Is value a number?
    if (value[0] == '-' || isdigit(value[0]))
    {
        // Guess that number is an int
        m_type = TypeInt;

        // Verify that guess
        c = value;
        int numDots = 0;
        while (*c != '\0')
        {
            if (*c == '.')
            {
                ++numDots;
            }
            ++c;
        }
        if( numDots == 1 ) m_type = TypeFloat;
        else if(  numDots > 1 ) m_type = TypeString;

        // Convert string into a real number
        if      (m_type == TypeFloat)        m_float = (float)atof(value);
        else if (m_type == TypeString)      m_str = newStr(value);
        else                                m_int = atoi(value);
    }
    else
    {
        m_type = TypeString;
        m_str = newStr(value);
    }
}

PrefsItem::PrefsItem(char const *_key, char const *_str)
:   m_type(TypeString)
{
    m_key = newStr(_key);
    m_str = newStr(_str);
}

PrefsItem::PrefsItem(char const *_key, float _float)
:   m_type(TypeFloat),
    m_str(NULL),
    m_float(_float)
{
    m_key = newStr(_key);
}

PrefsItem::PrefsItem(char const *_key, int _int)
:    m_type(TypeInt),
    m_str(NULL),
    m_int(_int)
{
    m_key = newStr(_key);
}

PrefsItem::~PrefsItem()
{
    delete [] m_key; m_key = NULL;
    delete [] m_str; m_str = NULL;
}

Preferences::Preferences(char const *_filename)
{
    m_filename = newStr(_filename);

    Load();

}

Preferences::Preferences(std::string const &_filename)
{
    m_filename = newStr(_filename.c_str());

    Load();
}

Preferences::~Preferences()
{
    delete [] m_filename; m_filename = NULL;
    Clear();
}

bool Preferences::IsLineEmpty(char const *_line)
{
    while (_line[0] != '\0')
    {
        if (_line[0] == '#') return true;
        if (isalnum(_line[0])) return false;
        ++_line;
    }

    return true;
}

void Preferences::CreateDefaultValues()
{

    // We default to the best possible preferences for performance and
    // so forth on the latest-and-greatest machines.

	AddLine( "# PrimaryRenderer\n" );
	AddLine( "#   direct3d: Experimental Direct3D 9 renderer (Windows only)\n" );
	AddLine( "#   opengl: OpenGL renderer (recommended)\n" );
	AddLine( "#   sdl: SDL renderer\n" );
    AddLine( "PrimaryRenderer = direct3d" );
	AddLine( "\n" );
	AddLine( "# SecondaryRenderer\n" );
	AddLine( "#  The SDL rendering engine uses this as the backend renderer.\n" );
	AddLine( "#   windib: DIB rendering (Windows only)\n" );
	AddLine( "#   directx: DirectDraw rendering (Windows only)\n" );
	AddLine( "#   dga: Direct X11 framebuffer access\n" );
#ifdef TARGET_OS_WINDOWS
    AddLine( "SecondaryRenderer = windib" );
#elif defined ( TARGET_OS_LINUX )
    AddLine( "SecondaryRenderer = dga" );
#endif
	AddLine( "\n" );
    AddLine( "TextureCompression = 0" );
    AddLine( "TextureRectangles = 0" );
	// AddLine ( "RenderMode = 0" );

    AddLine( "\n" );

	AddLine ( "IgnoreDataFiles = 0" );
	AddLine ( "DumpOpenGLInfo = 0" );

	AddLine ( "\n" );

#ifdef INTERNAL_BUILD
    AddLine( "ScreenWindowed = 1" );
#else
    AddLine( "ScreenWindowed = 0" );
#endif
    AddLine( "ScreenWidth = 800" );
    AddLine( "ScreenHeight = 600" );
    AddLine( "ScreenColourDepth = 32" );
    AddLine( "WaitVerticalRetrace = 1" );

	AddLine( "\n" );

	// AddLine( "SurfaceSplitFactor = 32" );

    // AddLine( "\n" );

    AddLine( "SoundChannels = 32" );
    AddLine( "SoundMixFreq = 22050" );
    AddLine( "SoundBufferSize = 512" );

    AddLine( "\n" );

    // Override the defaults above with stuff from a default preferences file
    if ( g_app && g_app->m_resource )
    {
        TextReader *reader = g_app->m_resource->GetTextReader( "default_preferences.txt" );
        if ( reader && reader->IsOpen() )
        {
            while ( reader->ReadLine() )
            {
                AddLine( reader->GetRestOfLine(), true );
            }
        }
        delete reader;
    }

}

void Preferences::Load(char const *_filename)
{
    if (!_filename) _filename = m_filename;

    Data::DArray<PrefsItem *> *items = m_items.ConvertToDArray();
    for ( size_t i = 0; i < items->size(); i++ )
        if ( items->valid(i) )
            delete items->get(i);
    delete items;
    m_items.empty();

    // Try to read preferences if they exist
    FILE *in = fopen(_filename, "r");

    if( !in )
    {
        // Probably first time running the game
        CreateDefaultValues();
    }
    else
    {
        char line[256];
        while (fgets(line, 256, in) != NULL)
        {
            AddLine( line );
        }
        fclose(in);
    }

    if ( m_items.size() < 1 ) CreateDefaultValues();

#ifdef DEMOBUILD
    AddLine( OTHER_DIFFICULTY " = 1", true );
#endif
}

void Preferences::SaveItem(FILE *out, PrefsItem *_item)
{
    switch (_item->m_type)
    {
        case PrefsItem::TypeFloat:
            fprintf(out, "%s = %.2f\n", _item->m_key, _item->m_float);
            break;
        case PrefsItem::TypeInt:
            fprintf(out, "%s = %d\n", _item->m_key, _item->m_int);
            break;
        case PrefsItem::TypeString:
            fprintf(out, "%s = %s\n", _item->m_key, _item->m_str);
            break;
    }
    _item->m_hasBeenWritten = true;
}

void Preferences::Save()
{
    // We've got a copy of the plain text from the prefs file that we initially
    // loaded in the variable m_fileText. We use that file as a template with
    // which to create the new save file. Updated prefs items values are looked up
    // as it their turn to be output comes around. When we've finished we then
    // write out all the new prefs items because they didn't exist in m_fileText.

	size_t i;

    // First clear the "has been written" flags on all the items
    Data::DArray<PrefsItem *> *items = m_items.ConvertToDArray();
    for ( i = 0; i < items->size(); ++i )
    {
        if ( items->valid ( i ) )
        {
            items->get(i)->m_hasBeenWritten = false;
        }
    }
    delete items;

    // Now use m_fileText as a template to write most of the items
    FILE *out = fopen(m_filename, "w");

    // If we couldn't open the prefs file for writing then just silently fail -
    // it's better than crashing.
    if (!out)
    {
        return;
    }

    for ( i = 0; i < m_fileText.size(); ++i )
    {
        if ( !m_fileText.valid ( i ) ) continue;
        char const *line = m_fileText[i];
        if (IsLineEmpty(line))
        {
            fprintf(out, line);
        }
        else
        {
            char const *c = line;
            char const *keyStart = NULL;
            char const *keyEnd = NULL;
            while (*c != '=')
            {
                if (keyStart)
                {
                    if (!isalnum(c[0]))
                    {
                        keyEnd = c;
                    }
                }
                else
                {
                    if (isalnum(c[0]))
                    {
                        keyStart = c;
                    }
                }
                ++c;
            }
            char key[128];
            int keyLen = keyEnd - keyStart;
            strncpy(key, keyStart, keyLen);
            key[keyLen] = '\0';
            PrefsItem *item;
			bool exists = m_items.find(key, item);
			ARCReleaseAssert ( exists );
            SaveItem(out, item);
        }
    }

    // Finally output any items that haven't already been written
    items = m_items.ConvertToDArray();
    for ( i = 0; i < items->size(); ++i )
    {
        if ( items->valid ( i ) )
        {
            PrefsItem *item = items->get ( i );
            if ( !item->m_hasBeenWritten )
            {
                SaveItem(out, item);
            }
        }
    }
    delete items;

    fclose(out);
}

void Preferences::Clear()
{
    Data::DArray<PrefsItem *> *items = m_items.ConvertToDArray();
	size_t i;
    for ( i = 0; i < items->size(); i++ )
        if ( items->valid(i) )
            delete items->get(i);
    delete items;
    m_items.empty();
    for ( i = 0; i < m_fileText.size(); i++ )
        if ( m_fileText.valid ( i ) )
            delete m_fileText.get ( i );
}

float Preferences::GetFloat(char const *_key, float _default) const
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists ) return _default;
    if (item->m_type != PrefsItem::TypeFloat) return _default;
    return item->m_float;
}

int Preferences::GetInt(char const *_key, int _default) const
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists ) return _default;
    if (item->m_type != PrefsItem::TypeInt) return _default;
    return item->m_int;
}

const char *Preferences::GetString(char const *_key, const char *_default) const
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists ) return _default;
    if (item->m_type != PrefsItem::TypeString) return _default;
    return item->m_str;
}

void Preferences::SetString(char const *_key, char const *_string)
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists )
    {
        item = new PrefsItem(_key, _string);
        m_items.insert ( item->m_key, item );
    }
    else
    {
        ARCDebugAssert ( item->m_type == PrefsItem::TypeString );
        char *newString = newStr(_string);
        delete [] item->m_str; item->m_str = NULL;
        // Note by Chris:
        // The incoming value of _string might also be item->m_str
        // So it is essential to copy _string before freeing item->m_str
        item->m_str = newString;
    }
}

void Preferences::SetFloat(char const *_key, float _float)
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists )
    {
        item = new PrefsItem ( _key, _float );
        m_items.insert ( item->m_key, item );
    }
    else
    {
        ARCDebugAssert ( item->m_type == PrefsItem::TypeFloat );
        item->m_float = _float;
    }
}

void Preferences::SetInt(char const *_key, int _int)
{
	PrefsItem *item;
	bool exists = m_items.find ( _key, item );
    if ( !exists )
    {
        item = new PrefsItem(_key, _int);
        m_items.insert ( item->m_key, item );
    }
    else
    {
        ARCDebugAssert ( item->m_type == PrefsItem::TypeInt );
        item->m_int = _int;
    }
}

void Preferences::AddLine(char const*_line, bool _overwrite)
{
    if ( !_line )
        return;

    bool saveLine = true;

    if (!IsLineEmpty(_line))                // Skip comment lines and blank lines
    {
        char *localCopy = newStr( _line );
        char *c = strchr(localCopy, '\n');
        if (c)
            *c = '\0';

        PrefsItem *item = new PrefsItem(localCopy);

        PrefsItem *idx;
		bool exists = m_items.find ( item->m_key, idx );
        if ( _overwrite && exists ) {
            delete idx;
            m_items.erase ( item->m_key );
            saveLine = false;
        }

        m_items.insert ( item->m_key, item );
        delete [] localCopy; localCopy = NULL;
    }

    if ( saveLine ) {
        char *lineCopy = newStr(_line);
        m_fileText.insert ( lineCopy );
    }
}

bool Preferences::DoesKeyExist(char const *_key)
{
    return m_items.exists ( _key );
}
<|endoftext|>


<commit_before>/*=========================================================================

  Library:   CTK

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// QT includes
#include <QChildEvent>
#include <QDebug>
#include <QDialogButtonBox>
#include <QEvent>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QListView>
#include <QPushButton>

// CTK includes
#include "ctkFileDialog.h"

//------------------------------------------------------------------------------
class ctkFileDialogPrivate
{
  Q_DECLARE_PUBLIC(ctkFileDialog);
protected:
  ctkFileDialog* const q_ptr;
public:
  ctkFileDialogPrivate(ctkFileDialog& object);
  void init();
  void observeAcceptButton();

  QPushButton* acceptButton()const;
  QListView* listView()const;

  bool AcceptButtonEnable;
  bool AcceptButtonState;
  bool IgnoreEvent;
};

//------------------------------------------------------------------------------
ctkFileDialogPrivate::ctkFileDialogPrivate(ctkFileDialog& object)
  :q_ptr(&object)
{
  this->IgnoreEvent = false;
  this->AcceptButtonEnable = true;
  this->AcceptButtonState = true;
}

//------------------------------------------------------------------------------
void ctkFileDialogPrivate::init()
{
  Q_Q(ctkFileDialog);

  this->observeAcceptButton();

  QObject::connect(this->listView()->selectionModel(),
                   SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
                   q, SLOT(onSelectionChanged()));
}

//------------------------------------------------------------------------------
QPushButton* ctkFileDialogPrivate::acceptButton()const
{
  Q_Q(const ctkFileDialog);
  QDialogButtonBox* buttonBox = q->findChild<QDialogButtonBox*>();
  Q_ASSERT(buttonBox);
  QDialogButtonBox::StandardButton button =
    (q->acceptMode() == QFileDialog::AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
  return buttonBox->button(button);
}

//------------------------------------------------------------------------------
QListView* ctkFileDialogPrivate::listView()const
{
  Q_Q(const ctkFileDialog);
  QListView* listView= q->findChild<QListView*>("listView");
  Q_ASSERT(listView);
  return listView;
}

//------------------------------------------------------------------------------
void ctkFileDialogPrivate::observeAcceptButton()
{
  Q_Q(ctkFileDialog);
  QPushButton* button = this->acceptButton();
  Q_ASSERT(button);
  this->AcceptButtonState =
    button->isEnabledTo(qobject_cast<QWidget*>(button->parent()));
  // TODO: catching the event of the enable state is not enough, if the user
  // double click on the file, the dialog will be accepted, that event should
  // be intercepted as well
  button->installEventFilter(q);
}

//------------------------------------------------------------------------------
ctkFileDialog::ctkFileDialog(QWidget *parentWidget,
              const QString &caption,
              const QString &directory,
              const QString &filter)
  :QFileDialog(parentWidget, caption, directory, filter)
  , d_ptr(new ctkFileDialogPrivate(*this))
{
  Q_D(ctkFileDialog);
  d->init();
}

//------------------------------------------------------------------------------
ctkFileDialog::~ctkFileDialog()
{
}

//------------------------------------------------------------------------------
void ctkFileDialog::setBottomWidget(QWidget* widget, const QString& label)
{
  QGridLayout* gridLayout = qobject_cast<QGridLayout*>(this->layout());
  QWidget* oldBottomWidget = this->bottomWidget();
  // remove the old widget from the layout if any
  if (oldBottomWidget)
    {
    if (oldBottomWidget == widget)
      {
      return;
      }
    gridLayout->removeWidget(oldBottomWidget);
    delete oldBottomWidget;
    }
  if (widget == 0)
    {
    return;
    }
  if (!label.isEmpty())
    {
    gridLayout->addWidget(new QLabel(label), 4, 0);
    gridLayout->addWidget(widget,4, 1,1, 1);
    }
  else
    {
    gridLayout->addWidget(widget,4, 0,1, 2);
    }
  // The dialog button box is no longer spanned on 2 rows but on 3 rows if
  // there is a "bottom widget"
  QDialogButtonBox* buttonBox = this->findChild<QDialogButtonBox*>();
  Q_ASSERT(buttonBox);
  gridLayout->removeWidget(buttonBox);
  gridLayout->addWidget(buttonBox, 2, 2, widget ? 3 : 2, 1);
}

//------------------------------------------------------------------------------
QWidget* ctkFileDialog::bottomWidget()const
{
  QGridLayout* gridLayout = qobject_cast<QGridLayout*>(this->layout());
  QLayoutItem* item = gridLayout->itemAtPosition(4,1);
  return item ? item->widget() : 0;
}

//------------------------------------------------------------------------------
void ctkFileDialog::setAcceptButtonEnable(bool enable)
{
  Q_D(ctkFileDialog);
  d->AcceptButtonEnable = enable;
  d->IgnoreEvent = true;
  d->acceptButton()->setEnabled(d->AcceptButtonEnable && d->AcceptButtonState);
  d->IgnoreEvent = false;
}

//------------------------------------------------------------------------------
bool ctkFileDialog::eventFilter(QObject *obj, QEvent *event)
{
  Q_D(ctkFileDialog);
  QPushButton* button = d->acceptButton();
  QDialogButtonBox* dialogButtonBox = qobject_cast<QDialogButtonBox*>(obj);
  if (obj == button && event->type() == QEvent::EnabledChange &&
      !d->IgnoreEvent)
    {
    d->IgnoreEvent = true;
    d->AcceptButtonState = button->isEnabledTo(qobject_cast<QWidget*>(button->parent()));
    button->setEnabled(d->AcceptButtonEnable && d->AcceptButtonState);
    d->IgnoreEvent = false;
    }
  else if (obj == button && event->type() == QEvent::Destroy)
    {
    // The accept button is deleted probably because setAcceptMode() is being called.
    // observe the parent to check when the accept button is added back
    obj->parent()->installEventFilter(this);
    }
  else if (dialogButtonBox && event->type() == QEvent::ChildAdded)
    {
    dynamic_cast<QChildEvent*>(event)->child()->installEventFilter(this);
    }
  return QFileDialog::eventFilter(obj, event);
}

//------------------------------------------------------------------------------
void ctkFileDialog::onSelectionChanged()
{
  emit this->fileSelectionChanged(this->selectedFiles());
}

//------------------------------------------------------------------------------
void ctkFileDialog::accept()
{
  QLineEdit* fileNameEdit = qobject_cast<QLineEdit*>(this->sender());
  if (fileNameEdit)
    {
    QFileInfo info(fileNameEdit->text());
    if (info.isDir())
      {
      setDirectory(info.absoluteFilePath());
      return;
      }
    }
  // Don't accept read-only directories if we are in AcceptSave mode.
  if ((this->fileMode() == Directory || this->fileMode() == DirectoryOnly) &&
      this->acceptMode() == AcceptSave)
    {
    QStringList files = this->selectedFiles();
    QString fn = files.first();
    QFileInfo info(fn);
    if (info.isDir() && !info.isWritable())
      {
      this->setDirectory(info.absoluteFilePath());
      return;
      }
    }
  this->Superclass::accept();
}
<commit_msg>fixed crashing line in ctkFileDialog for Qt5.<commit_after>/*=========================================================================

  Library:   CTK

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=========================================================================*/

// QT includes
#include <QChildEvent>
#include <QDebug>
#include <QDialogButtonBox>
#include <QEvent>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QListView>
#include <QPushButton>

// CTK includes
#include "ctkFileDialog.h"

//------------------------------------------------------------------------------
class ctkFileDialogPrivate
{
  Q_DECLARE_PUBLIC(ctkFileDialog);
protected:
  ctkFileDialog* const q_ptr;
public:
  ctkFileDialogPrivate(ctkFileDialog& object);
  void init();
  void observeAcceptButton();

  QPushButton* acceptButton()const;
  QListView* listView()const;

  bool AcceptButtonEnable;
  bool AcceptButtonState;
  bool IgnoreEvent;
};

//------------------------------------------------------------------------------
ctkFileDialogPrivate::ctkFileDialogPrivate(ctkFileDialog& object)
  :q_ptr(&object)
{
  this->IgnoreEvent = false;
  this->AcceptButtonEnable = true;
  this->AcceptButtonState = true;
}

//------------------------------------------------------------------------------
void ctkFileDialogPrivate::init()
{
  Q_Q(ctkFileDialog);

  this->observeAcceptButton();

  QObject::connect(this->listView()->selectionModel(),
                   SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
                   q, SLOT(onSelectionChanged()));
}

//------------------------------------------------------------------------------
QPushButton* ctkFileDialogPrivate::acceptButton()const
{
  Q_Q(const ctkFileDialog);
  QDialogButtonBox* buttonBox = q->findChild<QDialogButtonBox*>();
  Q_ASSERT(buttonBox);
  QDialogButtonBox::StandardButton button =
    (q->acceptMode() == QFileDialog::AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
  return buttonBox->button(button);
}

//------------------------------------------------------------------------------
QListView* ctkFileDialogPrivate::listView()const
{
  Q_Q(const ctkFileDialog);
  QListView* listView= q->findChild<QListView*>("listView");
  Q_ASSERT(listView);
  return listView;
}

//------------------------------------------------------------------------------
void ctkFileDialogPrivate::observeAcceptButton()
{
  Q_Q(ctkFileDialog);
  QPushButton* button = this->acceptButton();
  Q_ASSERT(button);
  this->AcceptButtonState =
    button->isEnabledTo(qobject_cast<QWidget*>(button->parent()));
  // TODO: catching the event of the enable state is not enough, if the user
  // double click on the file, the dialog will be accepted, that event should
  // be intercepted as well
  button->installEventFilter(q);
}

//------------------------------------------------------------------------------
ctkFileDialog::ctkFileDialog(QWidget *parentWidget,
              const QString &caption,
              const QString &directory,
              const QString &filter)
  :QFileDialog(parentWidget, caption, directory, filter)
  , d_ptr(new ctkFileDialogPrivate(*this))
{
  Q_D(ctkFileDialog);

#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
  this->setOptions(DontUseNativeDialog);
#endif

  d->init();
}

//------------------------------------------------------------------------------
ctkFileDialog::~ctkFileDialog()
{
}

//------------------------------------------------------------------------------
void ctkFileDialog::setBottomWidget(QWidget* widget, const QString& label)
{
  QGridLayout* gridLayout = qobject_cast<QGridLayout*>(this->layout());
  QWidget* oldBottomWidget = this->bottomWidget();
  // remove the old widget from the layout if any
  if (oldBottomWidget)
    {
    if (oldBottomWidget == widget)
      {
      return;
      }
    gridLayout->removeWidget(oldBottomWidget);
    delete oldBottomWidget;
    }
  if (widget == 0)
    {
    return;
    }
  if (!label.isEmpty())
    {
    gridLayout->addWidget(new QLabel(label), 4, 0);
    gridLayout->addWidget(widget,4, 1,1, 1);
    }
  else
    {
    gridLayout->addWidget(widget,4, 0,1, 2);
    }
  // The dialog button box is no longer spanned on 2 rows but on 3 rows if
  // there is a "bottom widget"
  QDialogButtonBox* buttonBox = this->findChild<QDialogButtonBox*>();
  Q_ASSERT(buttonBox);
  gridLayout->removeWidget(buttonBox);
  gridLayout->addWidget(buttonBox, 2, 2, widget ? 3 : 2, 1);
}

//------------------------------------------------------------------------------
QWidget* ctkFileDialog::bottomWidget()const
{
  QGridLayout* gridLayout = qobject_cast<QGridLayout*>(this->layout());
  QLayoutItem* item = gridLayout->itemAtPosition(4,1);
  return item ? item->widget() : 0;
}

//------------------------------------------------------------------------------
void ctkFileDialog::setAcceptButtonEnable(bool enable)
{
  Q_D(ctkFileDialog);
  d->AcceptButtonEnable = enable;
  d->IgnoreEvent = true;
  d->acceptButton()->setEnabled(d->AcceptButtonEnable && d->AcceptButtonState);
  d->IgnoreEvent = false;
}

//------------------------------------------------------------------------------
bool ctkFileDialog::eventFilter(QObject *obj, QEvent *event)
{
  Q_D(ctkFileDialog);
  QPushButton* button = d->acceptButton();
  QDialogButtonBox* dialogButtonBox = qobject_cast<QDialogButtonBox*>(obj);
  if (obj == button && event->type() == QEvent::EnabledChange &&
      !d->IgnoreEvent)
    {
    d->IgnoreEvent = true;
    d->AcceptButtonState = button->isEnabledTo(qobject_cast<QWidget*>(button->parent()));
    button->setEnabled(d->AcceptButtonEnable && d->AcceptButtonState);
    d->IgnoreEvent = false;
    }
  else if (obj == button && event->type() == QEvent::Destroy)
    {
    // The accept button is deleted probably because setAcceptMode() is being called.
    // observe the parent to check when the accept button is added back
    obj->parent()->installEventFilter(this);
    }
  else if (dialogButtonBox && event->type() == QEvent::ChildAdded)
    {
    dynamic_cast<QChildEvent*>(event)->child()->installEventFilter(this);
    }
  return QFileDialog::eventFilter(obj, event);
}

//------------------------------------------------------------------------------
void ctkFileDialog::onSelectionChanged()
{
  emit this->fileSelectionChanged(this->selectedFiles());
}

//------------------------------------------------------------------------------
void ctkFileDialog::accept()
{
  QLineEdit* fileNameEdit = qobject_cast<QLineEdit*>(this->sender());
  if (fileNameEdit)
    {
    QFileInfo info(fileNameEdit->text());
    if (info.isDir())
      {
      setDirectory(info.absoluteFilePath());
      return;
      }
    }
  // Don't accept read-only directories if we are in AcceptSave mode.
  if ((this->fileMode() == Directory || this->fileMode() == DirectoryOnly) &&
      this->acceptMode() == AcceptSave)
    {
    QStringList files = this->selectedFiles();
    QString fn = files.first();
    QFileInfo info(fn);
    if (info.isDir() && !info.isWritable())
      {
      this->setDirectory(info.absoluteFilePath());
      return;
      }
    }
  this->Superclass::accept();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2021 The CFU-Playground Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "models/magic_wand/magic_wand.h"

#include <stdio.h>

#include "menu.h"
#include "models/magic_wand/model_magic_wand.h"
#include "tensorflow/lite/micro/examples/magic_wand/ring_micro_features_data.h"
#include "tensorflow/lite/micro/examples/magic_wand/slope_micro_features_data.h"
#include "tflite.h"

// The magic_wand model classifies based on the greatest of 4 scores.
typedef struct {
  uint32_t wing_score;  // Stored as uint32_t because we can't print floats.
  uint32_t ring_score;
  uint32_t slope_score;
  uint32_t negative_score;
} MagicWandResult;

// Initialize everything once
// deallocate tensors when done
static void magic_wand_init(void) {
  tflite_load_model(model_magic_wand, model_magic_wand_len);
}

// Run classification, after input has been loaded
MagicWandResult magic_wand_classify() {
  printf("Running magic_wand\n");
  tflite_classify();

  // Process the inference results.
  float* output = tflite_get_output_float();

  // Kindly ask for the raw bits of the floats.
  return (MagicWandResult){
      *(uint32_t*)&output[0],
      *(uint32_t*)&output[1],
      *(uint32_t*)&output[2],
      *(uint32_t*)&output[3],
  };
}

static int interpret_score(uint32_t& score) {
  return 1000000 * static_cast<int>(*reinterpret_cast<float*>(&score));
}

static void print_magic_wand_result(const char* prefix, MagicWandResult res) {
  printf("%s-- wing: 0x%lx, ring: 0x%lx, slope: 0x%lx, negative: 0x%lx\n",
         prefix, res.wing_score, res.ring_score, res.slope_score,
         res.negative_score);
  printf(
      "%s approx-- wing: 0.%06d ring: 0.%06d, slope: 0.%06d, negative: "
      "0.%06d\n",
      prefix, interpret_score(res.wing_score) * 1000000,
      interpret_score(res.ring_score) * 1000000,
      interpret_score(res.slope_score) * 1000000,
      interpret_score(res.negative_score) * 1000000);
}

static void do_classify_zeros() {
  puts("Classify all zeros input");
  tflite_set_input_zeros_float();
  print_magic_wand_result("  results", magic_wand_classify());
}

static void do_classify_ring() {
  puts("Classify ring");
  tflite_set_input_float(g_ring_micro_f9643d42_nohash_4_data);
  print_magic_wand_result("  results", magic_wand_classify());
}

static void do_classify_slope() {
  puts("Classify slope");
  tflite_set_input_float(g_slope_micro_f2e59fea_nohash_1_data);
  print_magic_wand_result("  results", magic_wand_classify());
}

#define NUM_GOLDEN 3

static void do_golden_tests() {
  // Dequantization leads to simpler floats.
  static MagicWandResult magic_wand_golden_results[NUM_GOLDEN] = {
      {0x3d200000, 0x3ee00000, 0x3db00000, 0x3ee00000},
      {0x0, 0x3f7f0000, 0x0, 0x0},
      {0x0, 0x0, 0x3f7f0000, 0x0},
  };

  MagicWandResult actual[NUM_GOLDEN];
  tflite_set_input_zeros_float();
  actual[0] = magic_wand_classify();
  tflite_set_input_float(g_ring_micro_f9643d42_nohash_4_data);
  actual[1] = magic_wand_classify();
  tflite_set_input_float(g_slope_micro_f2e59fea_nohash_1_data);
  actual[2] = magic_wand_classify();

  bool failed = false;
  for (size_t i = 0; i < NUM_GOLDEN; i++) {
    MagicWandResult res = actual[i];
    MagicWandResult exp = magic_wand_golden_results[i];
    if (res.wing_score != exp.wing_score || res.ring_score != exp.ring_score ||
        res.slope_score != exp.slope_score ||
        res.negative_score != exp.negative_score) {
      failed = true;
      printf("*** Golden test %d failed: \n", i);
      print_magic_wand_result("actual", res);
      print_magic_wand_result("expected", exp);
    }
  }

  if (failed) {
    puts("FAIL Golden tests failed");
  } else {
    puts("OK   Golden tests passed");
  }
}

static struct Menu MENU = {
    "Tests for magic_wand model",
    "magic_wand",
    {
        MENU_ITEM('1', "Run with zeros input", do_classify_zeros),
        MENU_ITEM('2', "Run with ring input", do_classify_ring),
        MENU_ITEM('3', "Run with slope input", do_classify_slope),
        MENU_ITEM('g', "Run golden tests (check for expected outputs)",
                  do_golden_tests),
        MENU_END,
    },
};

// For integration into menu system
void magic_wand_menu() {
  magic_wand_init();
  menu_run(&MENU);
}
<commit_msg>Multiply before casting to int<commit_after>/*
 * Copyright 2021 The CFU-Playground Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "models/magic_wand/magic_wand.h"

#include <stdio.h>

#include "menu.h"
#include "models/magic_wand/model_magic_wand.h"
#include "tensorflow/lite/micro/examples/magic_wand/ring_micro_features_data.h"
#include "tensorflow/lite/micro/examples/magic_wand/slope_micro_features_data.h"
#include "tflite.h"

// The magic_wand model classifies based on the greatest of 4 scores.
typedef struct {
  uint32_t wing_score;  // Stored as uint32_t because we can't print floats.
  uint32_t ring_score;
  uint32_t slope_score;
  uint32_t negative_score;
} MagicWandResult;

// Initialize everything once
// deallocate tensors when done
static void magic_wand_init(void) {
  tflite_load_model(model_magic_wand, model_magic_wand_len);
}

// Run classification, after input has been loaded
MagicWandResult magic_wand_classify() {
  printf("Running magic_wand\n");
  tflite_classify();

  // Process the inference results.
  float* output = tflite_get_output_float();

  // Kindly ask for the raw bits of the floats.
  return (MagicWandResult){
      *(uint32_t*)&output[0],
      *(uint32_t*)&output[1],
      *(uint32_t*)&output[2],
      *(uint32_t*)&output[3],
  };
}

static int interpret_score(uint32_t& score) {
  return static_cast<int>(*reinterpret_cast<float*>(&score) * 1000000);
}

static void print_magic_wand_result(const char* prefix, MagicWandResult res) {
  printf("%s-- wing: 0x%lx, ring: 0x%lx, slope: 0x%lx, negative: 0x%lx\n",
         prefix, res.wing_score, res.ring_score, res.slope_score,
         res.negative_score);
  printf(
      "%s approx-- wing: 0.%06d ring: 0.%06d, slope: 0.%06d, negative: "
      "0.%06d\n",
      prefix, interpret_score(res.wing_score) * 1000000,
      interpret_score(res.ring_score) * 1000000,
      interpret_score(res.slope_score) * 1000000,
      interpret_score(res.negative_score) * 1000000);
}

static void do_classify_zeros() {
  puts("Classify all zeros input");
  tflite_set_input_zeros_float();
  print_magic_wand_result("  results", magic_wand_classify());
}

static void do_classify_ring() {
  puts("Classify ring");
  tflite_set_input_float(g_ring_micro_f9643d42_nohash_4_data);
  print_magic_wand_result("  results", magic_wand_classify());
}

static void do_classify_slope() {
  puts("Classify slope");
  tflite_set_input_float(g_slope_micro_f2e59fea_nohash_1_data);
  print_magic_wand_result("  results", magic_wand_classify());
}

#define NUM_GOLDEN 3

static void do_golden_tests() {
  // Dequantization leads to simpler floats.
  static MagicWandResult magic_wand_golden_results[NUM_GOLDEN] = {
      {0x3d200000, 0x3ee00000, 0x3db00000, 0x3ee00000},
      {0x0, 0x3f7f0000, 0x0, 0x0},
      {0x0, 0x0, 0x3f7f0000, 0x0},
  };

  MagicWandResult actual[NUM_GOLDEN];
  tflite_set_input_zeros_float();
  actual[0] = magic_wand_classify();
  tflite_set_input_float(g_ring_micro_f9643d42_nohash_4_data);
  actual[1] = magic_wand_classify();
  tflite_set_input_float(g_slope_micro_f2e59fea_nohash_1_data);
  actual[2] = magic_wand_classify();

  bool failed = false;
  for (size_t i = 0; i < NUM_GOLDEN; i++) {
    MagicWandResult res = actual[i];
    MagicWandResult exp = magic_wand_golden_results[i];
    if (res.wing_score != exp.wing_score || res.ring_score != exp.ring_score ||
        res.slope_score != exp.slope_score ||
        res.negative_score != exp.negative_score) {
      failed = true;
      printf("*** Golden test %d failed: \n", i);
      print_magic_wand_result("actual", res);
      print_magic_wand_result("expected", exp);
    }
  }

  if (failed) {
    puts("FAIL Golden tests failed");
  } else {
    puts("OK   Golden tests passed");
  }
}

static struct Menu MENU = {
    "Tests for magic_wand model",
    "magic_wand",
    {
        MENU_ITEM('1', "Run with zeros input", do_classify_zeros),
        MENU_ITEM('2', "Run with ring input", do_classify_ring),
        MENU_ITEM('3', "Run with slope input", do_classify_slope),
        MENU_ITEM('g', "Run golden tests (check for expected outputs)",
                  do_golden_tests),
        MENU_END,
    },
};

// For integration into menu system
void magic_wand_menu() {
  magic_wand_init();
  menu_run(&MENU);
}
<|endoftext|>


<commit_before>#include "gum/Sprite2.h"
#include "gum/DTex.h"
#include "gum/RenderTargetMgr.h"
#include "gum/RenderTarget.h"
#include "gum/Audio.h"
#include "gum/ThreadPool.h"

#include <sprite2/RenderTargetMgr.h>
#include <sprite2/RenderTarget.h>
#include <sprite2/Sprite.h>
#include <sprite2/Symbol.h>
#include <sprite2/RenderParams.h>
#include <sprite2/DrawNode.h>
#include <sprite2/AudioContext.h>
#include <sprite2/Callback.h>
#include <sprite2/Blackboard.h>
#include <dtex2/DebugDraw.h>
#include <shaderlab/Statistics.h>

#include <stdint.h>

namespace gum
{

CU_SINGLETON_DEFINITION(Sprite2);

Sprite2::Sprite2()
	: m_curr_dc(std::numeric_limits<int>::max())
	, m_dc_count(0)
{
}

void Sprite2::DebugDraw() const
{
	s2::RenderTargetMgr* RT = s2::RenderTargetMgr::Instance();
	for (int i = 0; i < 4; ++i) {
		int texid = RT->GetTexID(i);
		if (texid < 0) {
			continue;
		}
		dtex::DebugDraw::Draw(texid, i + 1);
	}
}

static void prepare_render_params(const s2::RenderParams& parent,
								  const s2::Sprite* spr,
								  s2::RenderParams& child)
{
	if (parent.IsDisableDTexC2() || spr->IsDTexDisable()) {
		child.SetDisableDTexC2(true);
	}
}

static void
dtex_sym_insert(UID uid, const sm::rect& bounding, int tex_id, int tex_w, int tex_h)
{
	DTex* dtex = DTex::Instance();
	dtex->LoadSymStart();

	sm::i16_rect r_dst;
	r_dst.xmin = static_cast<uint16_t>(bounding.xmin + tex_w * 0.5f);
	r_dst.ymin = static_cast<uint16_t>(bounding.ymin + tex_h * 0.5f);
	r_dst.xmax = static_cast<uint16_t>(bounding.xmax + tex_w * 0.5f);
	r_dst.ymax = static_cast<uint16_t>(bounding.ymax + tex_h * 0.5f);

	dtex->LoadSymbol(uid, tex_id, tex_w, tex_h, r_dst, 1, 0, 0);

	dtex->LoadSymFinish();
}

static const float*
dtex_sym_query(UID uid, int& tex_id, int& block_id)
{
	return DTex::Instance()->QuerySymbol(uid, tex_id, block_id);
}

static uint64_t
get_sym_uid(const s2::Symbol& sym)
{
	return ResourceUID::BinNode(sym.GetID());
}

static uint64_t
get_spr_uid(const s2::Sprite* spr)
{
	return ResourceUID::Sprite(spr->GetID());
}

static uint64_t
get_actor_uid(const s2::Actor* actor)
{
	return ResourceUID::Actor(actor);
}

static s2::RenderTarget*
fetch_screen()
{
	return RenderTargetMgr::Instance()->Fetch();
}

static void
return_screen(s2::RenderTarget* rt)
{
	RenderTargetMgr::Instance()->Return(static_cast<gum::RenderTarget*>(rt));
}

static bool
is_audio_enable()
{
	return Audio::Instance()->IsEnable();
}

static void
submit_task(mt::Task* task)
{
	ThreadPool::Instance()->Run(task);
}

static int
query_thread_idx(std::thread::id id)
{
	return ThreadPool::Instance()->QueryThreadIdx(id);
}

void Sprite2::Init()
{
	s2::DrawNode::InitDTexCB(prepare_render_params, dtex_sym_insert, dtex_sym_query);
	s2::DrawNode::InitUIDCB(get_sym_uid, get_spr_uid, get_actor_uid);

	s2::RenderTargetMgr::Instance()->InitScreenCB(fetch_screen, return_screen);

#ifdef S2_MULTITHREAD
	s2::RenderParamsPool::Instance()->Init(ThreadPool::Instance()->GetThreadCount());
#endif // S2_MULTITHREAD

	{
		s2::AudioContext::Callback cb;
		cb.is_enable = is_audio_enable;
		s2::AudioContext::InitCallback(cb);
	}
	{
		s2::Callback::Funs funs;
		funs.submit_task      = submit_task;
		funs.query_thread_idx = query_thread_idx;
		s2::Callback::RegisterCallback(funs);
	}
}

void Sprite2::Flush()
{
	//int dc = sl::Statistics::Instance()->GetLastDrawCall();
	//if (dc < 4) {
	//	return;
	//}

	//if (dc < m_curr_dc) {
	//	m_curr_dc = dc;
	//	m_dc_count = 0;
	//} else if (dc == m_curr_dc) {
	//	++m_dc_count;
	//	if (m_dc_count == MAX_DC_COUNT) {
	//		s2::Blackboard::Instance()->SetDlistEnable(true);
	//	}
	//}
}

}<commit_msg>up s2<commit_after>#include "gum/Sprite2.h"
#include "gum/DTex.h"
#include "gum/RenderTargetMgr.h"
#include "gum/RenderTarget.h"
#include "gum/Audio.h"
#include "gum/ThreadPool.h"

#include <sprite2/RenderTargetMgr.h>
#include <sprite2/RenderTarget.h>
#include <sprite2/Sprite.h>
#include <sprite2/Symbol.h>
#include <sprite2/RenderParams.h>
#include <sprite2/DrawNode.h>
#include <sprite2/AudioContext.h>
#include <sprite2/Callback.h>
#include <sprite2/Blackboard.h>
#include <dtex2/DebugDraw.h>
#include <shaderlab/Statistics.h>

#include <stdint.h>

namespace gum
{

CU_SINGLETON_DEFINITION(Sprite2);

Sprite2::Sprite2()
	: m_curr_dc(std::numeric_limits<int>::max())
	, m_dc_count(0)
{
}

void Sprite2::DebugDraw() const
{
	s2::RenderTargetMgr* RT = s2::RenderTargetMgr::Instance();
	for (int i = 0; i < 4; ++i) {
		int texid = RT->GetTexID(i);
		if (texid < 0) {
			continue;
		}
		dtex::DebugDraw::Draw(texid, i + 1);
	}
}

static void prepare_render_params(const s2::RenderParams& parent,
								  const s2::Sprite* spr,
								  s2::RenderParams& child)
{
	if (parent.IsDisableDTexC2() || spr->IsDTexDisable()) {
		child.SetDisableDTexC2(true);
	}
}

static void
dtex_sym_insert(UID uid, const sm::rect& bounding, int tex_id, int tex_w, int tex_h)
{
	DTex* dtex = DTex::Instance();
	dtex->LoadSymStart();

	sm::i16_rect r_dst;
	r_dst.xmin = static_cast<uint16_t>(bounding.xmin + tex_w * 0.5f);
	r_dst.ymin = static_cast<uint16_t>(bounding.ymin + tex_h * 0.5f);
	r_dst.xmax = static_cast<uint16_t>(bounding.xmax + tex_w * 0.5f);
	r_dst.ymax = static_cast<uint16_t>(bounding.ymax + tex_h * 0.5f);

	dtex->LoadSymbol(uid, tex_id, tex_w, tex_h, r_dst, 1, 0, 0);

	dtex->LoadSymFinish();
}

static const float*
dtex_sym_query(UID uid, int& tex_id, int& block_id)
{
	return DTex::Instance()->QuerySymbol(uid, tex_id, block_id);
}

static uint64_t
get_sym_uid(const s2::Symbol& sym)
{
	return ResourceUID::BinNode(sym.GetID());
}

static uint64_t
get_spr_uid(const s2::Sprite* spr)
{
	return ResourceUID::Sprite(spr->GetID());
}

static uint64_t
get_actor_uid(const s2::Actor* actor)
{
	return ResourceUID::Actor(actor);
}

static s2::RenderTarget*
fetch_screen()
{
	return RenderTargetMgr::Instance()->Fetch();
}

static void
return_screen(s2::RenderTarget* rt)
{
	RenderTargetMgr::Instance()->Return(static_cast<gum::RenderTarget*>(rt));
}

static bool
is_audio_enable()
{
	return Audio::Instance()->IsEnable();
}

static void
submit_task(mt::Task* task)
{
	ThreadPool::Instance()->Run(task);
}

static int
query_thread_idx(std::thread::id id)
{
	return ThreadPool::Instance()->QueryThreadIdx(id);
}

void Sprite2::Init()
{
	s2::DrawNode::InitDTexCB(prepare_render_params, dtex_sym_insert, dtex_sym_query);
	s2::DrawNode::InitUIDCB(get_sym_uid, get_spr_uid, get_actor_uid);

	s2::RenderTargetMgr::Instance()->InitScreenCB(fetch_screen, return_screen);

	{
		s2::AudioContext::Callback cb;
		cb.is_enable = is_audio_enable;
		s2::AudioContext::InitCallback(cb);
	}
	{
		s2::Callback::Funs funs;
		funs.submit_task      = submit_task;
		funs.query_thread_idx = query_thread_idx;
		s2::Callback::RegisterCallback(funs);
	}
}

void Sprite2::Flush()
{
	//int dc = sl::Statistics::Instance()->GetLastDrawCall();
	//if (dc < 4) {
	//	return;
	//}

	//if (dc < m_curr_dc) {
	//	m_curr_dc = dc;
	//	m_dc_count = 0;
	//} else if (dc == m_curr_dc) {
	//	++m_dc_count;
	//	if (m_dc_count == MAX_DC_COUNT) {
	//		s2::Blackboard::Instance()->SetDlistEnable(true);
	//	}
	//}
}

}<|endoftext|>