extern "C" const GUID IID_AudioOleCtrl;
class RichEditAudioOle :public RichEditOleBase
{
DECLARE_REOBJ(RichEditAudioOle, L"audio")
public:
enum ReAudioState
{
REAUDIO_STATE_NOPLAY, // 未播放状态
REAUDIO_STATE_PLAYING, // 正在播放状态
REAUDIO_STATE_PLAYFINISH, // 播放完成状态
};
RichEditAudioOle();
~RichEditAudioOle();
BOOL InitOleWindow(IRichEditObjHost* pHost);
int GetAudioState(){return _state;}
SStringW GetAudioPath(){return _audio_path;}
SStringW GetAudioDuration(){return _audio_duration;}
SStringW GetAudioId(){return GetId();}
void AudioPlayFinish();
protected:
void UpdatePosition();
bool OnAudioPlayClick(SOUI::EventArgs* pEvt);
bool OnAudioPlayingClick(SOUI::EventArgs* pEvt);
protected:
SOUI_ATTRS_BEGIN()
ATTR_STRINGW(L"audio_duration", _audio_duration, FALSE)
ATTR_STRINGW(L"audio_path", _audio_path, FALSE)
SOUI_ATTRS_END()
private:
int _state;
SIZE _maxSize;
SStringW _audio_duration;
SStringW _audio_path;
};
//
//
//{9DB5554F-7BB7-4d2f-B4D7-3BD9F6E8901A}
static const GUID IID_AudioOleCtrl =
{ 0x9db5554f, 0x7bb7, 0x4d2f, { 0xb4, 0xd7, 0x3b, 0xd9, 0xf6, 0xe8, 0x90, 0x1a } };
RichEditAudioOle::RichEditAudioOle()
{
_oleGuid = IID_AudioOleCtrl;
_maxSize.cx = _maxSize.cy = 180;
_state = REAUDIO_STATE_NOPLAY;
_canBeSelect = FALSE;
_xmlLayout = L"LAYOUT:AudioOleLayout";
}
RichEditAudioOle::~RichEditAudioOle()
{
//
// 把图片skin的内存由_oleView管理,当_oleView释放时,会调用skin的release
//
}
void RichEditAudioOle::AudioPlayFinish()
{
_state = REAUDIO_STATE_PLAYFINISH;
SImageView* pImgPlay = _oleView.FindChildByName2<SImageView>(L"play");
if (pImgPlay)
{
pImgPlay->SetVisible(TRUE, TRUE);
}
SImageView* pImgPlaying = _oleView.FindChildByName2<SImageView>(L"playing");
if (pImgPlaying)
{
pImgPlaying->SetVisible(FALSE, TRUE);
}
SImageView* pImageReddot= _oleView.FindChildByName2<SImageView>(L"isplayed");
if (pImageReddot)
pImageReddot->SetVisible(FALSE, TRUE);
std::wstring wstrDuration;
wstrDuration.append(_audio_duration);
wstrDuration.append(L"\"");
SWindow* pAudioDuration = _oleView.FindChildByName2<SWindow>(L"audio_duration");
if (pAudioDuration)
{
pAudioDuration->SetWindowText(wstrDuration.c_str());
pAudioDuration->SetVisible(TRUE, TRUE);
}
}
bool RichEditAudioOle::OnAudioPlayClick(SOUI::EventArgs* pEvt)
{
_state = REAUDIO_STATE_PLAYING;
SImageView* pImgPlay = _oleView.FindChildByName2<SImageView>(L"play");
if (pImgPlay)
{
pImgPlay->SetVisible(FALSE, TRUE);
}
SImageView* pImgPlaying = _oleView.FindChildByName2<SImageView>(L"playing");
if (pImgPlaying)
{
pImgPlaying->SetVisible(TRUE, TRUE);
pImgPlaying->Resume();
}
SImageView* pImageReddot= _oleView.FindChildByName2<SImageView>(L"isplayed");
if (pImageReddot)
pImageReddot->SetVisible(FALSE, TRUE);
std::wstring wstrDuration;
wstrDuration.append(_audio_duration);
wstrDuration.append(L"\"");
SWindow* pAudioDuration = _oleView.FindChildByName2<SWindow>(L"audio_duration");
if (pAudioDuration)
{
pAudioDuration->SetWindowText(wstrDuration.c_str());
pAudioDuration->SetVisible(TRUE, TRUE);
}
_pObjHost->NotifyRichObjEvent(this, CLICK_15AUDIO_PLAY, 0, 0);
return true;
}
bool RichEditAudioOle::OnAudioPlayingClick(SOUI::EventArgs* pEvt)
{
_state = REAUDIO_STATE_PLAYFINISH;
SImageView* pImgPlay = _oleView.FindChildByName2<SImageView>(L"play");
if (pImgPlay)
{
pImgPlay->SetVisible(TRUE, TRUE);
}
SImageView* pImgPlaying = _oleView.FindChildByName2<SImageView>(L"playing");
if (pImgPlaying)
{
pImgPlaying->SetVisible(FALSE, TRUE);
}
SImageView* pImageReddot= _oleView.FindChildByName2<SImageView>(L"isplayed");
if (pImageReddot)
pImageReddot->SetVisible(FALSE, TRUE);
std::wstring wstrDuration;
wstrDuration.append(_audio_duration);
wstrDuration.append(L"\"");
SWindow* pAudioDuration = _oleView.FindChildByName2<SWindow>(L"audio_duration");
if (pAudioDuration)
{
pAudioDuration->SetWindowText(wstrDuration.c_str());
pAudioDuration->SetVisible(TRUE, TRUE);
}
_pObjHost->NotifyRichObjEvent(this, CLICK_15AUDIO_PLAYING, 0, 0);
return true;
}
BOOL RichEditAudioOle::InitOleWindow(IRichEditObjHost * pHost)
{
BOOL ret = RichEditOleBase::InitOleWindow(pHost);
ISkinObj* pSkinPlay = GETSKIN(L"skin.richaudio_15play", 100);
SImageView* pImgPlay = _oleView.FindChildByName2<SImageView>(L"play");
if (pImgPlay && pSkinPlay)
{
pImgPlay->SetSkin(pSkinPlay);
pImgPlay->SetVisible(TRUE, TRUE);
pImgPlay->Resume();
SUBSCRIBE(pImgPlay, EVT_CMD, RichEditAudioOle::OnAudioPlayClick);
}
ISkinObj* pSkinPlaying = GETSKIN(L"skin.richaudio_15playing", 100);
SImageView* pImgPlaying = _oleView.FindChildByName2<SImageView>(L"playing");
if (pImgPlaying && pSkinPlaying)
{
pImgPlaying->SetSkin(pSkinPlaying);
pImgPlaying->SetVisible(FALSE, TRUE);
}
ISkinObj* pSkinReddot = GETSKIN(L"skin.richaudio_reddot", 100);
SImageView* pImageReddot= _oleView.FindChildByName2<SImageView>(L"isplayed");
if (pImageReddot && pSkinReddot)
{
pImageReddot->SetSkin(pSkinReddot);
pImageReddot->SetVisible(TRUE, TRUE);
pImageReddot->Resume();
SUBSCRIBE(pImgPlaying, EVT_CMD, RichEditAudioOle::OnAudioPlayingClick);
}
std::wstring wstrDuration;
wstrDuration.append(_audio_duration);
wstrDuration.append(L"\"");
SWindow* pAudioDuration = _oleView.FindChildByName2<SWindow>(L"audio_duration");
if (pAudioDuration)
{
pAudioDuration->SetWindowText(wstrDuration.c_str());
pAudioDuration->SetVisible(TRUE, TRUE);
}
return ret;
}
void RichEditAudioOle::UpdatePosition()
{
if (_spAdviseSink)
{
double fRatio = GetZoomRatio(_sizeNatural, _maxSize);
_sizeNatural.cx = 130;
_sizeNatural.cy = 40;
_oleView.SetOleWindowRect(CRect(0, 0, 0, 0)); // 已经失效
_oleView.Move(0, 0, _sizeNatural.cx, _sizeNatural.cy);
CalculateExtentSize(_sizeNatural);
_spAdviseSink->OnViewChange(DVASPECT_CONTENT, -1);
}
}
以上为控件实现代码;
IID_AudioOleCtrl为控件GUID,可以自己生成。
接口说明:
InitOleWindow:初始化Ole窗口
GetAudioState:获取Audio状态
GetAudioPath:获取Audio文件路径
GetAudioDuration:获取Audio文件播放时长
GetAudioId:获取元素ID
AudioPlayFinish:Audio播放完成时调用
OnAudioPlayClick:静态状态点击事件
OnAudioPlayingClick:播放状态点击事件
以下是控件布局相关XML:
<root>
<window pos="0,0,-0,-0" skin="skin.empty">
<image name="play" cursor="hand" pos="0,0"/>
<image name="playing" cursor="hand" pos="0,0" />
<text name="audio_duration" pos="[5,22" align="center" colorText="#000000" dotted="1" font="size:12"/>
<image name="isplayed" pos="110,15" skin="skin.richaudio_reddot" show="1" />
</window>
</root>
控件需要在uires.idx文件中添加相关映射关系
注意:
在使用时还需要在以下文件的接口中添加相关代码:
RichEditObjFactory.cpp文件的RichEditObjFactory接口中添加_creaters[RichEditAudioOle::GetClassName()] = RichEditAudioOle::CreateObject;
如下所示:
RichEditObjFactory::RichEditObjFactory()
{
_creaters[RichEditText::GetClassName()] = RichEditText::CreateObject;
_creaters[RichEditBkElement::GetClassName()] = RichEditBkElement::CreateObject;
_creaters[RichEditPara::GetClassName()] = RichEditPara::CreateObject;
_creaters[RichEditContent::GetClassName()] = RichEditContent::CreateObject;
_creaters[RichEditFetchMoreOle::GetClassName()] = RichEditFetchMoreOle::CreateObject;
_creaters[RichEditImageOle::GetClassName()] = RichEditImageOle::CreateObject;
_creaters[RichEditFileOle::GetClassName()] = RichEditFileOle::CreateObject;
_creaters[RichEditSeparatorBar::GetClassName()] = RichEditSeparatorBar::CreateObject;
_creaters[RichEditMetaFileOle::GetClassName()] = RichEditMetaFileOle::CreateObject;
_creaters[RichEditReminderOle::GetClassName()] = RichEditReminderOle::CreateObject;
_creaters[RichEditAudioOle::GetClassName()] = RichEditAudioOle::CreateObject;
}
RichEditOleCallback.cpp文件的QueryInsertObject接口中添加相关代码,如下所示:
HRESULT RichEditOleCallback::QueryInsertObject(
LPCLSID lpclsid,
LPSTORAGE lpstg,
LONG cp)
{
if (lpclsid == NULL)
{
return E_INVALIDARG;
}
if (*lpclsid == IID_ImageOleCtrl ||
*lpclsid == IID_FileOleCtrl ||
*lpclsid == IID_FetchMoreOleCtrl ||
*lpclsid == IID_SeparatorBarCtrl ||
*lpclsid == IID_RichMetaFileOle ||
*lpclsid == IID_RemainderOleCtrl ||
*lpclsid == IID_AudioOleCtrl)
{
return S_OK;
}
return E_FAIL;
}
以上为OLE控件相关代码;
下边我们看看新控件的使用:
SStringW strAudio;
std::string strAudioId = KfUtility::GenerateUUID();
std::wstring wstrAudioId;
KfUtility::ConvertUtf8ToUtf16(strAudioId, wstrAudioId);
strAudio.Format(L"<audio id=\"%s\" audio_duration=\"12\" audio_path=\"D:\\imrepose\\trunk\\KFClient6\\output\\Debug_Unicode\\default_res\\test.amr\"/>", wstrAudioId.c_str());
SStringW strContent;
strContent.Format(
L"<RichEditContent type=\"ContentLeft\" align=\"left\">"
L"<para>"
L"</para>"
L"<bkele data=\"avatar\" id=\"%s\" skin=\"%s\" pos=\"0,]-2,@40,@40\" cursor=\"hand\" interactive=\"1\"/>"
L"<para id=\"msgbody\" margin=\"50,0,0,0\" break=\"1\" simulate-align=\"1\">"
L"%s"
L"</para>"
L"%s"
L"</RichEditContent>",
wstrId.c_str(), wstrFaceId.c_str(), strAudio, pEmpty);
pRecvRichEdit->InsertContent(strContent, RECONTENT_LAST);