📄 subwnds.h
字号:
/*! 本文件中的类封装了视频子窗口的若干操作
* \mainpage 视频子窗口功能
* \author nodman (nodman@163.com)
* \date 2003-6-11
*/
#ifndef _SUBWNDS_H
#define _SUBWNDS_H
#include "utils.h"
#include "vector"
#include "rect.h"
/// 当视频子窗口被鼠标点击时触发该消息
/// WPARAM: 窗口指针
/// LPARAM: 鼠标点击类型
#define WM_VIDEO_WND_INVOKED WM_USER + 32777
#define WM_VIDEO_ALARM_SHOW WM_USER + 32778
#define WM_SHOW_MENU WM_USER + 32779
#define WM_MENU_CLOSE WM_USER + 32780
#define WM_USER_MENU WM_USER + 32781
/// 子窗口类.
/// @see basic_wnd
class video_wnd: public basic_wnd<CStatic>
{
typedef basic_wnd<CStatic> baseclass;
CFont ft; // window text font
protected:
CString title; // window title
int i; ///< 本窗口序号, i>=0. 如果i==-1, 说明本窗口没有初始化.
/// 重载CWnd::PreTranslateMessage()
virtual BOOL PreTranslateMessage(MSG* pMsg)
{
WPARAM w = 0;
LPARAM l = 0;
switch( pMsg->message )
{
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
w = (WPARAM)this;
l = (LPARAM)pMsg->message;
if( GetParent() )
if( GetParent()->SendMessage(WM_VIDEO_WND_INVOKED, w, l) )
return TRUE;
break;
// return TRUE;
/*
case WM_PAINT:
CPaintDC dc(this);
client_rect rc(this);
#ifdef _DEBUG
dc.FillRect(rc, &CBrush(RGB(0,0,0)));
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(RGB(255,255,255));
CFont *old = dc.SelectObject(&ft);
dc.TextOut(10,10,title);
dc.SelectObject(old);
#endif
// 在窗口边缘画白色方框
dc.FrameRect(rc, &CBrush(framecl));
return TRUE;
*/
}
return basic_wnd<CStatic>::PreTranslateMessage(pMsg);
}
public:
/// 构造函数.
video_wnd():i(-1){ft.CreatePointFont(90,_T("Arial"), NULL);}
/// 析构函数, 自动销毁窗口.
virtual ~video_wnd()
{
destroy();
}
/// @name 初始化 与 销毁.
//@{
/// 初始化本窗口.
/// @param parent 父窗口.
/// @param style 窗口风格, 默认值为黑色矩形.
/// @return true 成功, false 失败.
/// @see is_window()
virtual bool create(int index, CWnd* parent, const CRect& rc = CRect(0,0,0,0),
DWORD style = SS_GRAYRECT | WS_CHILD | SS_NOTIFY)
{
// already created
if( is_window(this) )
return true;
i = index;
if( !Create(_T(""), style, rc, parent ) )
return false;
title.Format(_T("Ch%02d"), index+1);
// ModifyStyleEx(0, WS_EX_STATICEDGE, 0);
return true;
}
/// 销毁本窗口.
/// @see is_window()
void destroy()
{
if( !is_window(this) )
return;
DestroyWindow();
i = -1;
}
//@}
/// 取得本窗口序号.
/// @return 本窗口序号.
int index() const {return i;}
};
/// 子窗口管理基类.
class sub_wnds_mgr
{
protected:
typedef std::vector<video_wnd*> sub_wnd_list;
/// @see sub_wnd_list
sub_wnd_list lst; ///< 子窗口列表.
int cnt; ///< 子窗口个数.
/// 构造函数.
/// @param count 子窗口的个数.
sub_wnds_mgr(int count):cnt(count){}
public:
/// 子窗口参数.
struct sub_wnd_param
{
CRect rc; ///< 子窗口容器区域
int hm; ///< 子窗口之间水平方向间距.
int vm; ///< 子窗口之间垂直方向间距.
};
/// 查询子窗口个数.
/// @return 子窗口个数.
int sub_wnds_count() const {return cnt;}
/// 刷新所有子窗口.
/// @param swp 子窗口参数.
/// @see sub_wnd_param.
/// @see calc_rect().
void update(const sub_wnd_param& swp)
{
for( int i=0; i<cnt; i++ )
{
video_wnd*& ref = lst[i];
ref->MoveWindow(calc_rect(i, swp));
}
for( i=0; i<cnt; i++ )
{
video_wnd*& ref = lst[i];
ref->show();
}
}
/// 显示窗口.
void show(int index)
{
lst[index]->show();
}
/// 隐藏窗口.
void hide(int index)
{
lst[index]->hide();
}
/// 显示所有.
void show_all()
{
for( int i=0; i<cnt; i++ )
{
video_wnd*& ref = lst[i];
ref->show();
}
}
/// 隐藏所有.
void hide_all()
{
for( int i=0; i<cnt; i++ )
{
video_wnd*& ref = lst[i];
ref->hide();
}
}
/*
void show_all_except(const video_wnd* vm)
{
for( int i=0; i<cnt; i++ )
{
video_wnd*& ref = lst[i];
if( ref != vm )
ref->show();
}
}
void hide_all_except(const video_wnd* vm)
{
for( int i=0; i<cnt; i++ )
{
video_wnd*& ref = lst[i];
if( ref != vm )
ref->hide();
}
}
*/
/// 往队列中加入一个窗口.
/// 注意顺序, 第一个加入的窗口为1号窗口, 依此类推.
void add(video_wnd* wnd)
{
lst.push_back(wnd);
}
void add(video_wnd& wnd){add(&wnd);}
/// 清除窗口列表.
void clear()
{
lst.clear();
}
/// 查询某路窗口对象.
video_wnd* operator[](int index)
{
if( index >= lst.size() )
return NULL;
return lst[index];
}
/// 根据窗口序号计算子窗口位置和大小.
/// 该功能必须由派生类实现, 以供create()使用.
/// @param index 子窗口的序号.
/// @param swp 子窗口参数.
/// @return 该子窗口的位置(CRect).
/// @see sub_wnd_param.
virtual CRect calc_rect(int index, const sub_wnd_param& swp){return CRect(0,0,0,0);}
};
/// 规则视频子窗口基类.
/// 本类要用到其派生类中的枚举类型: count, cols, rows.
template<typename T>
class video_square: public sub_wnds_mgr
{
public:
/// 构造函数, 为基类确定子窗口个数.
video_square(): sub_wnds_mgr(T::count){}
/// 计算某个子窗口位置.
/// @param index 子窗口序号.
/// @param swp 子窗口参数.
/// @return 子窗口位置.
/// @see sub_wnds_mgr::sub_wnd_param
virtual CRect calc_rect(int index, const sub_wnd_param& swp)
{
// w = sub_w*2 + hm*3;
// h = sub_h*2 + vm*3;
// =>
// sub_w = (w-hm*3)/2;
// sub_h = (h-vm*3)/2;
int sub_w = 0, sub_h = 0;
CRect ret(0,0,0,0);
// for convenience :)
const CRect& rc = swp.rc;
const int& hm = swp.hm;
const int& vm = swp.vm;
sub_w = (swp.rc.Width() - hm*(T::cols+1))/T::cols;
sub_h = (swp.rc.Height() - vm*(T::rows+1))/T::rows;
int h_factor = index % T::cols; // horizontal video wnds
int v_factor = index / T::cols; // vertical video wnds
ret.left = swp.rc.left + hm*(h_factor+1) + sub_w*h_factor;
ret.top = swp.rc.top + vm*(v_factor+1) + sub_h*v_factor;
ret.right = ret.left + sub_w;
ret.bottom = ret.top + sub_h;
return ret;
}
};
/// 4路子窗口.
/// @see video_square
class video_4ch: public video_square<video_4ch>
{
public:
enum {count=4, cols=2, rows=2}; ///< 子窗口个数.
};
/// 单路.
/// @see video_square
class video_1ch: public video_square<video_1ch>
{
public:
enum {count=1, cols=1, rows=1};
};
/// 9路.
/// @see video_square
class video_9ch: public video_square<video_9ch>
{
public:
enum {count=9, cols=3, rows=3};
};
/// 16路.
/// @see video_square
class video_16ch: public video_square<video_16ch>
{
public:
enum {count=16, cols=4, rows=4};
};
/// 32路.
/// @see video_square
class video_25ch: public video_square<video_25ch>
{
public:
enum {count=25, cols=5, rows=5};
};
/// 12路.
/// @see video_square
class video_12ch: public video_square<video_12ch>
{
public:
enum {count=12, cols=3, rows=4};
};
/// 6路.
/// 本类描述的子窗口序列是不规则的.
class video_6ch: public sub_wnds_mgr
{
public:
enum {count=6, cols=0, rows=0}; ///< 特殊窗口.
video_6ch(): sub_wnds_mgr(count){}
/// 指定放大窗口.
/// 该函数将要放大的窗口放到队列的第一个.
/// @param zoom 放大的窗口.
/// @param w 放大窗口的宽度.
/// @param h 放大窗口的高度.
void set_zoom(video_wnd* zoom)
{
// if the one is already the first one
// OK, return
if( zoom == lst[0] )
return;
std::vector<video_wnd*> tmp;
// find the one
for( int i=0; i<lst.size(); i++ )
{
if( zoom == lst[i] )
tmp.push_back(lst[i]);
}
if( tmp.empty() ) // specified item not found in the list
return;
// add the remaining items to tail
for( i=0; i<lst.size(); i++ )
{
if( zoom != lst[i] )
tmp.push_back(lst[i]);
}
// save the result
lst.swap(tmp);
}
/*
* |-----------| |----|
* | | | 01 |
* | | |----|
* | z |
* | | |----|
* | | | 02 |
* |-----------| |----|
*
* |----| |----| |----|
* | 03 | | 04 | | 05 |
* |----| |----| |----|
*/
/// 计算窗口位置.
/// @see video_square::calc_rect()
virtual CRect calc_rect(int index, const sub_wnd_param& swp)
{
CRect ret(0,0,0,0);
int sub_w = 0, sub_h = 0;
// for convenience :)
const CRect& rc = swp.rc;
const int& hm = swp.hm;
const int& vm = swp.vm;
// 宽度高度按照3x3方法计算
sub_w = (swp.rc.Width() - hm*(3+1))/3;
sub_h = (swp.rc.Height() - vm*(3+1))/3;
// 如果是放大窗口
if( index == 0 )
{
ret.left = swp.rc.left + hm;
ret.top = swp.rc.top + vm;
ret.right = ret.left + sub_w*2+hm;
ret.bottom = ret.top + sub_h*2+vm;
return ret;
}
/* this:
* -------
* 0 1
* 2
* 3 4 5
*
* +++++++
*
* 3x3
* -------
* 0 1 2
* 3 4 5
* 6 7 8
*/
// 用对应法则, 建立一张表格, 按照3x3的算法计算
// 1 2 3 4 5 // 6路的窗口序列
int table[5] = {2, 5, 6, 7, 8}; // 对应的3x3窗口序列号
int h_factor = table[index-1] % 3; // horizontal video wnds
int v_factor = table[index-1] / 3; // vertical video wnds
ret.left = swp.rc.left + hm*(h_factor+1) + sub_w*h_factor;
ret.top = swp.rc.top + vm*(v_factor+1) + sub_h*v_factor;
ret.right = ret.left + sub_w;
ret.bottom = ret.top + sub_h;
return ret;
}
};
#endif // _SUBWNDS_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -