Duilib拡張カラーセレクタコントロールを共有します(Duilibの肌交換時に使用します)
概要
[カラーセレクタ](Color Selector)パレットではありません.パレットでは任意のカラー値を選択できますが、カラー選択期間では一定のカラー値しか使用できません.例えば、QQパソコンの執事の肌交換機能では、デフォルトの色をインタフェース全体の背景色として使用することができ、その中の色は固定されており、選択をやり直すしかありません.それが色セレクタです.
インプリメンテーション
データ構造:まず、固定された2 Dテーブルを使用して、行、列の座標に基づいて色のセットを格納する必要があります.ユーザーが色を選択したとき、この点に基づいてテーブルの対応する色の値をクエリーします.
インタフェース処理:選択された状態とマウスのフォーカス状態.現在選択されている色の座標を記録し、変更を選択して色値を復元する必要があります.マウスの移動中にフォーカスブロックのカラー値を描画し、前のカラーブロックの値を復元します.残りはGDI基本功,領域充填,二重バッファ描画,局所リフレッシュである.
コード#コード#
わざわざ注釈をつけて、読者にもっとよく理解してほしい.
コンフィギュレーション
リロードコントロール関数の作成、新規追加コントロール処理
XMLレイアウトの設定
うんてん
[カラーセレクタ](Color Selector)パレットではありません.パレットでは任意のカラー値を選択できますが、カラー選択期間では一定のカラー値しか使用できません.例えば、QQパソコンの執事の肌交換機能では、デフォルトの色をインタフェース全体の背景色として使用することができ、その中の色は固定されており、選択をやり直すしかありません.それが色セレクタです.
インプリメンテーション
データ構造:まず、固定された2 Dテーブルを使用して、行、列の座標に基づいて色のセットを格納する必要があります.ユーザーが色を選択したとき、この点に基づいてテーブルの対応する色の値をクエリーします.
インタフェース処理:選択された状態とマウスのフォーカス状態.現在選択されている色の座標を記録し、変更を選択して色値を復元する必要があります.マウスの移動中にフォーカスブロックのカラー値を描画し、前のカラーブロックの値を復元します.残りはGDI基本功,領域充填,二重バッファ描画,局所リフレッシュである.
コード#コード#
わざわざ注釈をつけて、読者にもっとよく理解してほしい.
/**********************************
*Author: Jelin
*Time: 2014-12-18
*Email: mailto://[email protected]
*/
#pragma once
#include <map>
using std::map;
//
template<class T, int row=0, int column=0>
class CMyArray
{
public:
CMyArray()
:m_pData(NULL)
,m_nRow(row)
,m_nColumn(column)
{
if ( m_nRow>0 && m_nColumn>0 )
Allocate();
}
~CMyArray()
{
Free();
}
bool Resize(const int nRow, const int nColumn)
{
if ( nRow<=0 || nColumn<=0 )
return false;
m_nRow = nRow;
m_nColumn = nColumn;
Allocate();
return true;
}
T GetAt(const int nRow, const int nColumn)
{
if ( nRow>=m_nRow || nColumn>=m_nColumn )
return T();
return *(m_pData+nRow*m_nColumn+nColumn);
}
void SetAt(const int nRow, const int nColumn, const T& data)
{
if ( nRow>=m_nRow || nColumn>=m_nColumn )
return ;
*(m_pData+nRow*m_nColumn+nColumn) = data;
}
protected:
void Allocate()
{
Free();
m_pData = (T*)malloc(m_nRow*m_nColumn*sizeof(T));
}
void Free()
{
if ( m_pData )
{
free(m_pData);
m_pData = NULL;
}
}
private:
T* m_pData;
int m_nRow;
int m_nColumn;
};
//
class CSelectColorCallback
{
public:
virtual void ColorTest(DWORD color)=0;
};
class CColorSkinUI
: public CControlUI
{
public:
CColorSkinUI();
virtual ~CColorSkinUI();
virtual void SetPos(RECT rc);
virtual void DoInit();
virtual void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
virtual void DoPaint(HDC hDC, const RECT& rcPaint);
virtual void DoEvent(TEventUI& event);
void SetSelectColorCallback(CSelectColorCallback* pCallback) { m_pSelectCallback = pCallback; }
DWORD GetSelectColor();
int GetCurSelLine() { return m_nCurSelLine; }
int GetCurSelCol() { return m_nCurSelCol; }
void SetCurSelLine(const int nLine) { m_nCurSelLine = nLine; }
void SetCurSelCol(const int nColumn) { m_nCurSelCol = nColumn; }
void SetCurSelPos(const int nLine, const int nColumn);
protected:
void InitBitmap(int nWidth, int nHeight);
void PaintPalette(bool bPaintAll=true, const int nCurLine=0, const int nCulCol=0);
DWORD PaintSide(HDC hDC, const int nLine, const int nColumn, bool bSelect);
private:
int m_nSideLen;
int m_nLine;
int m_nColumn;
HDC m_hMemDC;
HBITMAP m_hMemBmp;
BITMAP m_bitmap;
void* m_pBuffer;
int m_nPreWidth;
int m_nPreHeight;
int m_nCurSelLine;
int m_nCurSelCol;
int m_nPreCurSelLine;
int m_nPreCurSelCol;
CMyArray<DWORD> m_arrColor;
CSelectColorCallback* m_pSelectCallback;
};
#include "StdAfx.h"
#include "UIColorSkin.h"
#define MAX_VALUE 230 //
#define ORG_VALUE 125 //
#define ASS_VALUE 100 //
#define RATE_SEL_VALUE 0.6 // ,
#define RATE_OVER_VALUE 0.8 // ,
// ,
static const DWORD g_Palette[]=
{
RGB(ORG_VALUE, 0, 0), RGB(ORG_VALUE, 0, ASS_VALUE), RGB(ORG_VALUE, ASS_VALUE, 0), RGB(ORG_VALUE, ASS_VALUE, ASS_VALUE),
RGB(0, ORG_VALUE, 0), RGB(0, ORG_VALUE, ASS_VALUE), RGB(ASS_VALUE, ORG_VALUE, 0), RGB(ASS_VALUE, ORG_VALUE, ASS_VALUE),
RGB(0, 0, ORG_VALUE), RGB(0, ASS_VALUE, ORG_VALUE), RGB(ASS_VALUE, 0, ORG_VALUE), RGB(ASS_VALUE, ASS_VALUE, ORG_VALUE),
RGB(ORG_VALUE, ORG_VALUE, 0), RGB(ORG_VALUE, ORG_VALUE, ASS_VALUE),
RGB(ORG_VALUE, 0, ORG_VALUE), RGB(ORG_VALUE, ASS_VALUE, ORG_VALUE),
RGB(ASS_VALUE, ORG_VALUE, ORG_VALUE), RGB(0, ORG_VALUE, ORG_VALUE),
RGB(ORG_VALUE, ORG_VALUE, ORG_VALUE),
};
const int g_nMaxColumn = sizeof(g_Palette)/sizeof(DWORD);
CColorSkinUI::CColorSkinUI()
:m_nSideLen(0)
,m_nLine(0)
,m_nColumn(0)
,m_hMemDC(NULL)
,m_hMemBmp(NULL)
,m_pBuffer(NULL)
,m_nPreWidth(-1)
,m_nPreHeight(-1)
,m_nCurSelLine(0)
,m_nCurSelCol(0)
,m_nPreCurSelLine(-1)
,m_nPreCurSelCol(-1)
,m_pSelectCallback(NULL)
{
ZeroMemory(&m_bitmap, sizeof(BITMAP));
}
CColorSkinUI::~CColorSkinUI()
{
if ( m_hMemDC )
{
DeleteDC(m_hMemDC);
m_hMemDC = NULL;
}
if ( m_hMemBmp )
{
DeleteObject(m_hMemBmp);
m_hMemBmp = NULL;
}
if ( m_pBuffer )
{
free(m_pBuffer);
m_pBuffer = NULL;
}
}
void CColorSkinUI::SetPos( RECT rc )
{
CControlUI::SetPos(rc);
int nWidth = GetWidth();
int nHeight = GetHeight();
m_nColumn = (nWidth+1)/(m_nSideLen+1);
if ( m_nColumn>g_nMaxColumn )
{
m_nColumn = g_nMaxColumn;
m_nSideLen = (nWidth+1)/m_nColumn-1;
}
m_nLine = (nHeight+1)/(m_nSideLen+1);
m_arrColor.Resize(m_nLine, m_nColumn);
InitBitmap(nWidth, nHeight);
}
void CColorSkinUI::DoInit()
{
CControlUI::DoInit();
}
void CColorSkinUI::SetAttribute( LPCTSTR pstrName, LPCTSTR pstrValue )
{
if ( _tcscmp(pstrName, _T("sidelen")) == 0 )
m_nSideLen = _ttoi(pstrValue);
else
CControlUI::SetAttribute(pstrName, pstrValue);
}
void CColorSkinUI::DoPaint( HDC hDC, const RECT& rcPaint )
{
if ( NULL == m_hMemDC )
m_hMemDC = CreateCompatibleDC(hDC);
RECT rcInsert;
IntersectRect(&rcInsert, &m_rcItem, &rcPaint);
HBITMAP hOldBmp = (HBITMAP)SelectObject(m_hMemDC, m_hMemBmp);
::BitBlt(hDC, rcInsert.left, rcInsert.top, rcInsert.right-rcInsert.left, rcInsert.bottom-rcInsert.top, \
m_hMemDC, rcInsert.left-m_rcItem.left, rcInsert.top-m_rcItem.top, SRCCOPY);
m_hMemBmp = (HBITMAP)::SelectObject(m_hMemDC, hOldBmp);
}
void CColorSkinUI::InitBitmap(int nWidth, int nHeight)
{
m_bitmap.bmWidth =nWidth;
m_bitmap.bmHeight =nHeight;
m_bitmap.bmBitsPixel=32;
m_bitmap.bmPlanes =1;
m_bitmap.bmWidthBytes=nWidth*4;
m_bitmap.bmType =0;
int nBytes = (((nWidth*32+31)>>5)<<2)*nHeight;
if ( nWidth != m_nPreWidth || nHeight != m_nPreHeight )
{
if ( m_pBuffer )
free(m_pBuffer);
m_pBuffer =malloc(nBytes);
m_nPreWidth =nWidth;
m_nPreHeight=nHeight;
}
memset(m_pBuffer, 0xff, nBytes);
m_bitmap.bmBits =m_pBuffer;
PaintPalette();
}
void CColorSkinUI::DoEvent( TEventUI& event )
{
switch( event.Type )
{
case UIEVENT_MOUSEMOVE:
{//
int xPos = (event.ptMouse.x-m_rcItem.left)/(m_nSideLen+1);
int yPos = (event.ptMouse.y-m_rcItem.top)/(m_nSideLen+1);
PaintPalette(false, yPos, xPos);// ,
Invalidate();
break;
}
case UIEVENT_BUTTONDOWN:
{
int xPos = (event.ptMouse.x-m_rcItem.left)/(m_nSideLen+1);
int yPos = (event.ptMouse.y-m_rcItem.top)/(m_nSideLen+1);
if ( yPos>=m_nLine || xPos>=m_nColumn )
break;
m_nCurSelCol = xPos;
m_nCurSelLine = yPos;
//
PaintPalette(true);
if ( m_pSelectCallback )
{// , ( ……)
DWORD dwColor = m_arrColor.GetAt(m_nCurSelLine, m_nCurSelCol);
dwColor = 0xff000000 + RGB( GetBValue(dwColor), GetGValue(dwColor), GetRValue(dwColor) );
m_pSelectCallback->ColorTest(dwColor);
}
Invalidate();
}
break;
case UIEVENT_MOUSEHOVER:
break;
case UIEVENT_MOUSELEAVE:
//
PaintPalette(false, m_nCurSelLine, m_nCurSelCol);
Invalidate();
break;
default:
break;
}
CControlUI::DoEvent(event);
}
void CColorSkinUI::PaintPalette(bool bPaintAll/*=true*/, const int nCurLine/*=0*/, const int nCulCol/*=0*/)
{// ,
if ( nCurLine == m_nPreCurSelLine && nCulCol == m_nPreCurSelCol )
return ;// ,
if ( nCurLine>=m_nLine || nCulCol>=m_nColumn )
return ;// ,
if ( bPaintAll )
{
if ( m_hMemBmp )
{
DeleteObject(m_hMemBmp);
m_hMemBmp = NULL;
}
m_hMemBmp = CreateBitmapIndirect(&m_bitmap);
}
// m_hMemBmp
HDC hDC = CreateCompatibleDC(NULL);
HBITMAP hBmp = (HBITMAP)SelectObject(hDC, m_hMemBmp);
if ( bPaintAll )
{
for ( int i=0; i<m_nLine; ++i )
for ( int j=0; j<m_nColumn; ++j )
{
DWORD dwColor = PaintSide(hDC, i, j, (i == m_nCurSelLine && j == m_nCurSelCol));
m_arrColor.SetAt(i, j, dwColor);
}
}
else
{
if ( m_nPreCurSelCol!=-1 && m_nPreCurSelLine!=-1 )
{//
PaintSide(hDC, m_nPreCurSelLine, m_nPreCurSelCol, (m_nPreCurSelLine == m_nCurSelLine && m_nPreCurSelCol == m_nCurSelCol));
}
//
PaintSide(hDC, nCurLine, nCulCol, true);
m_nPreCurSelLine= nCurLine;
m_nPreCurSelCol = nCulCol;
}
m_hMemBmp = (HBITMAP)SelectObject(hDC, hBmp);
DeleteDC(hDC);
}
DWORD CColorSkinUI::PaintSide( HDC hDC, const int nLine, const int nColumn, bool bSelect )
{//
DWORD dwRetColor = 0;
RECT rcFill = {0, 0, 0, 0};
DWORD dwColor = 0, dwPreColor = 0;
int r = 0, g = 0, b = 0;
float fRate = (MAX_VALUE-ORG_VALUE)/(float)(m_nLine-1);
rcFill.left = (m_nSideLen+1)*nColumn;
rcFill.top = (m_nSideLen+1)*nLine;
rcFill.right= rcFill.left+m_nSideLen;
rcFill.bottom=rcFill.top+m_nSideLen;
if ( nLine == 0 )
dwColor = g_Palette[nColumn];//
else
{//
r = GetRValue(g_Palette[nColumn]);
g = GetGValue(g_Palette[nColumn]);
b = GetBValue(g_Palette[nColumn]);
if ( r>=ORG_VALUE ) r+=(int)(nLine*fRate);
if ( g>=ORG_VALUE ) g+=(int)(nLine*fRate);
if ( b>=ORG_VALUE ) b+=(int)(nLine*fRate);
dwColor = RGB(r, g, b);
}
dwRetColor = dwColor;
if ( bSelect )
{// , 0.6 ,
dwColor = RGB(GetRValue(dwColor)*RATE_SEL_VALUE, GetGValue(dwColor)*RATE_SEL_VALUE, \
GetBValue(dwColor)*RATE_SEL_VALUE );
}
HBRUSH hBrush = CreateSolidBrush(dwColor);
FillRect(hDC, &rcFill, hBrush);
DeleteObject(hBrush);
return dwRetColor;
}
DWORD CColorSkinUI::GetSelectColor()
{
DWORD dwColor = m_arrColor.GetAt(m_nCurSelLine, m_nCurSelCol);
// RGB
dwColor = 0xff000000 + RGB( GetBValue(dwColor), GetGValue(dwColor), GetRValue(dwColor) );
return dwColor;
}
void CColorSkinUI::SetCurSelPos( const int nLine, const int nColumn )
{
m_nCurSelLine = nLine;
m_nCurSelCol = nColumn;
}
コンフィギュレーション
リロードコントロール関数の作成、新規追加コントロール処理
CControlUI* CSkinWnd::CreateControl( LPCTSTR pstrClass )
{
if ( _tcscmp(pstrClass, _T("ColorSkin")) == 0 )
{
return new CColorSkinUI;
}
return NULL;
}
XMLレイアウトの設定
<HorizontalLayout bkcolor="#FFFFFFFF">
<ColorSkin name="color" float="true" pos="9,6,0,0" sidelen="16" width="310" height="120" bkcolor="#FFFFFFFF"/>
<Button name="btn_ok" text=" " float="true" pos="220,132,0,0" width="76" height="26" textcolor="#FFF9F9F9" align="center" normalimage="blue_nor.png" hotimage="blue_hot.png" pushedimage="blue_down.png" hottextcolor="#FFFFFFFF" font="3"/>
</HorizontalLayout>
うんてん