Can Anybody Direct Me To Information On Skinning In C++ using API only ??? Perferably the same way Winamp does its skinning or something similiar, any help would be appreciated.
Thanx for any help.
AAG
Printable View
Can Anybody Direct Me To Information On Skinning In C++ using API only ??? Perferably the same way Winamp does its skinning or something similiar, any help would be appreciated.
Thanx for any help.
AAG
I have been looking for the same info, but...never found it. Let's hope from here has it :)
What you are asking is a huge request.
The way that winamp skins work:
BitBlt the main image on an empty window
BitBlt the buttons, bars, etc over the top of that
All these imges have a certian X/Y system which is fixed to match the X and Y from the main bmp file and the X and Y of the BitBlt pos on the form.
There is also a X/Y system that keeps track of the X/Y of all the things on the screen that can change, buttons, bars, etc. When a user clicks in an area that matchs the X/Y that system knows it has to change, it BitBlt the changed image over the top of the coressponding pos on the window, until the user releases the button. Then runs the function that coresponds what was pushed, like stop.
Thats the bare basics of how the skins works. Its really complex, believe me I made a MP3 player that used winamp skins.
Well could you possibly send me some sample sourcecode of your mp3 player. I'm creating a full fledged media player, and i would like to create skins for it. All i need is just a form with a skinned button on it, and i can figure out the rest. Or could you possibly give me another way to do the skinning. how would I go about detecting what hwnd the mouse is over when its down. Do I use the wParam in the WM_LBUTTONDOWN ??
Sorry about my last post I rushed through it, there was only 2 mins before I left work :D
My player, which is prob only 50% done, I made in VB. But I can help you with what you need to do in C++.
Do you know how to use BitBlt? I sure hope so because I am going to skip how to use it. If you need help with using it let me know and I will help you with that too.
If you open a .wsz file, which is just a renamed .zip file, you will see all the .bmp files that make up a winamp skin. If you look at main.bmp you will see the main boby image for winamp. It is about 275x116. So what you need to do is make a window with no caption, no control buttons, etc. Basically a really blank window. It should be 275x116 of course.
Then make a static control that will cover the whole window. Use the SS_REALSIZEIMAGE in your flags on create window. Then BitBlt the main.bmp on to the static control.
Then lets say you want to have the play button on it. Most of those buttons are in CButton.bmp. You will see that there are 2 sets of buttons. The top set, is the up position buttons. The bottom set, is the down position buttons. Each button I think is 19x18 with 2 pixels in between each button. Its real easy to BitBlt the up buttons with a loop, skiping 2 pixels after each button.
So back to play, lets say you BitBlt that button to position (I am just going to make it up because I dont have my orginal player here right now. But you are going to have to play with were you position your buttons until you get them aligned) 10X10. What you need to do is use WM_LBUTTONDOWN and WM_BUTTONUP in you Message function.
Basically the function would look like this:
Here is what that function looks like:PHP Code:case WM_LBUTTONDOWN:
{ //Not needed
if(hWnd == ThehWndOfYourStaticControl)
{
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
GetButtonClicked(pt, true); //This is a function I made to handle just the buttons
break;
}
break;
} //Not needed
case WM_LBUTTONUP:
{ //Not needed
if(hWnd == ThehWndOfYourStaticControl)
{
POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
GetButtonClicked(pt, false); //This is a function I made to handle just the buttons
break;
}
break;
} //Not needed
Well thats the jist of it. Thats prob more than you wanted to know, but I rather give more info than to little.PHP Code:void GetButtonClicked(POINT pt, bool Down)
{
//Remeber we put the button at 10x10
//So if the mouse is clicked somewhere between 10-29 on the x (Remeber the button is 19 pixels wide)
//And if it clicked somewhere between 10-28 on the y (18 pixles long)
if(((pt.x >= 10) && (pt.x <= 29)) && ((pt.y >= 10) && (pt.y <= 28)))
{
if(Down) //We pass in a bool to see if the button is pushed down or not)
BitBltTheDownButton();
else
{
BitBltTheUpButton();
Sleep(0); //Make Sure BitBlt Finshed Before Moving On
PlayMusic();
}
}
}
I wrote all the code by hand and all the skin info from memory so there maybe some mistakes there.
Let me know if you need anymore help.
Oh and here is a tip that I have learned the hard way many, many times, doing skins. Either do the exit buttons first. Or build in a case statement that will run your exit functions on any button pushed, or when the left mouse button is clicked on the form and is not in a button area. If you don't then its hard to close the window, and if you dont destory your hDCs, hBitmaps, etc your going to memory leak everywhere.
I didn't need as much information as you gave me. I've created winamp skins before and have created a full fledged MP3 Player in vb6 using the MCI API that was almost completely compatible with winamp skins, there were a couple of things i hadn't implemented yet, but it even bitblt the skinned fonts :). I just wasn't sure what exactly I was supposed to be handling in C++. Thanx for the info.
AAG
I got mine to do all the skin, up and down. It was a perfect match with winamp except for that second before VB BitBlt'd the image. I never finished doing any of the abilities, VB is just to weak to handle most of that stuff well.
If nothing else maybe someone else can use all that info.
Ok I don't know why this isn't working. It was working when I tried it a while back. here's my code.
I've also inlcuded the project that I did. Its probably the wrong way to do bitblt or something in c++. I forgot where I learned this, I think it was from winprog.org, but not sure.Code:#include <windows.h>
#include "resource.h"
static char g_szClassName[] = "MyWindowClass";
static HINSTANCE g_hInst = NULL;
HBITMAP MainBitmap;
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_CREATE:
MainBitmap= LoadBitmap(g_hInst, "MAIN_BITMAP");
if(!MainBitmap){
MessageBox(hwnd, "Resource Loading failed.", "Oops",
MB_OK | MB_ICONEXCLAMATION);
}
break;
case WM_PAINT:
if(MainBitmap)
{
PAINTSTRUCT ps;
HDC hdcMemory, hdcWindow;
BITMAP bm;
hdcWindow = BeginPaint(hwnd, &ps);
hdcMemory = CreateCompatibleDC(hdcWindow);
SelectObject(hdcMemory, MainBitmap);
GetObject(MainBitmap, sizeof(bm), &bm);
BitBlt(hdcWindow, 0, 0, bm.bmWidth, bm.bmHeight, hdcMemory, 0, 0, SRCCOPY);
DeleteDC(hdcMemory);
EndPaint(hwnd, &ps);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
DeleteObject(MainBitmap);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WndClass;
HWND hwnd;
MSG Msg;
g_hInst = hInstance;
WndClass.cbSize = sizeof(WNDCLASSEX);
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = g_hInst;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = g_szClassName;
WndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&WndClass))
{
MessageBox(0, "Could Not Register Window", "Oops",
MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"Test",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 320, 240,
NULL, NULL, g_hInst, NULL);
if(hwnd == NULL)
{
MessageBox(0, "ERROR Window Was Not Created", "Oops",
MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
Thanks for posting the .zip because I would missed it without it.
You were real close change:
PHP Code:MainBitmap= LoadBitmap(g_hInst, MAKEINTRESOURCE(MAIN_BITMAP));
Opps got a memory leak. Add:
PHP Code:DeleteDC(hdcWindow);
Ok, The Images are displaying fine, but when I attempt to handle the WM_LBUTTONDOWN message, it does nothing. This is the exact code I have in the WM_LBUTTONDOWN
I don't know why it doesn't do anything. do You ?? Below Is The Code I Used To Create The Static Control.Code:case WM_LBUTTONDOWN:
if(hwnd == static1)
{
PostQuitMessage(0);
}
break;
Code:#define ID_STATIC1 9001;
HWND static1;
static1 = CreateWindow("Static", NULL, WS_CHILD | WS_VISIBLE | SS_REALSIZEIMAGE ,0,0,200,25,hwnd,(HMENU)ID_STATIC1,g_hInst,0);
Can you .zip it again and post it
I've attatched the zip below.
I don't think that is the way to control a click event
the hwnd you are using is the one from the window
try something like:
Code:if((HWND)lParam == static1)
{
}
Still Didn't work :(
Sorry it's been awhile since I have done this so I missed something. If you make your window and static control the same size you can just use WM_LBUTTON because nothing else on the window will send that message. If you want your static control to deal with the message you need add the flag SS_NOTIFY:
Then the notification will go to WM_COMMAND:PHP Code:static1 = CreateWindow("Static",NULL,WS_CHILD | WS_VISIBLE | SS_REALSIZEIMAGE | SS_NOTIFY,0,0,600,600,hwnd,NULL,g_hInst,0);
PHP Code:case WM_COMMAND:
case STN_CLICKED:
PostQuitMessage(0);
break;