2015-04-28 13:45:35 -04:00
|
|
|
/**
|
|
|
|
* @file
|
2016-05-05 12:19:00 -04:00
|
|
|
* @brief QWIN GUI facilities for building realistic embedded front panels
|
2015-04-28 13:45:35 -04:00
|
|
|
* @cond
|
|
|
|
******************************************************************************
|
2016-11-01 15:38:29 -04:00
|
|
|
* Last Updated for Version: 5.7.4
|
|
|
|
* Date of the Last Update: 2016-10-21
|
2012-08-14 18:07:04 -04:00
|
|
|
*
|
|
|
|
* Q u a n t u m L e a P s
|
|
|
|
* ---------------------------
|
|
|
|
* innovating embedded systems
|
|
|
|
*
|
2015-04-28 13:45:35 -04:00
|
|
|
* Copyright (C) Quantum Leaps, LLC. All rights reserved.
|
2012-08-14 18:07:04 -04:00
|
|
|
*
|
|
|
|
* This program is open source software: you can redistribute it and/or
|
2015-06-05 17:05:16 -04:00
|
|
|
* modify it under the terms of the GNU General Public License as published
|
|
|
|
* by the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
2012-08-14 18:07:04 -04:00
|
|
|
*
|
2015-06-05 17:05:16 -04:00
|
|
|
* Alternatively, this program may be distributed and modified under the
|
|
|
|
* terms of Quantum Leaps commercial licenses, which expressly supersede
|
|
|
|
* the GNU General Public License and are specifically designed for
|
|
|
|
* licensees interested in retaining the proprietary status of their code.
|
2012-08-14 18:07:04 -04:00
|
|
|
*
|
2015-06-05 17:05:16 -04:00
|
|
|
* This program 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 General Public License for more details.
|
2015-04-28 13:45:35 -04:00
|
|
|
*
|
2015-06-05 17:05:16 -04:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2012-08-14 18:07:04 -04:00
|
|
|
*
|
|
|
|
* Contact information:
|
2017-05-17 13:16:32 -04:00
|
|
|
* https://state-machine.com
|
2016-05-05 12:19:00 -04:00
|
|
|
* mailto:info@state-machine.com
|
2015-04-28 13:45:35 -04:00
|
|
|
******************************************************************************
|
|
|
|
* @endcond
|
|
|
|
*/
|
2016-05-05 12:19:00 -04:00
|
|
|
#include "qwin_gui.h"
|
2012-08-14 18:07:04 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2016-06-10 21:50:26 -04:00
|
|
|
static HWND l_hWnd;
|
|
|
|
static HDC l_hDC;
|
|
|
|
|
2012-08-14 18:07:04 -04:00
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
HWND CreateCustDialog(HINSTANCE hInst, int iDlg, HWND hParent,
|
|
|
|
WNDPROC lpfnWndProc, LPCTSTR lpWndClass)
|
|
|
|
{
|
|
|
|
WNDCLASSEX wndclass;
|
|
|
|
|
|
|
|
wndclass.cbSize = sizeof(wndclass);
|
|
|
|
wndclass.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
wndclass.lpfnWndProc = lpfnWndProc;
|
|
|
|
wndclass.cbClsExtra = 0;
|
|
|
|
wndclass.cbWndExtra = DLGWINDOWEXTRA;
|
|
|
|
wndclass.hInstance = hInst;
|
|
|
|
wndclass.hIcon = NULL;
|
|
|
|
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
wndclass.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
|
|
|
wndclass.lpszMenuName = NULL;
|
|
|
|
wndclass.lpszClassName = lpWndClass;
|
|
|
|
wndclass.hIconSm = NULL;
|
|
|
|
|
|
|
|
RegisterClassEx(&wndclass);
|
|
|
|
|
2016-06-10 21:50:26 -04:00
|
|
|
l_hWnd = CreateDialog(hInst, MAKEINTRESOURCE(iDlg), hParent, NULL);
|
|
|
|
l_hDC = GetDC(l_hWnd); /* obtain the DC for the client area of the window */
|
2012-08-14 18:07:04 -04:00
|
|
|
|
|
|
|
/* NOTE: WM_INITDIALOG provides stimulus for initializing dialog controls.
|
|
|
|
* Dialog box procedures typically use this message to initialize controls
|
|
|
|
* and carry out any other initialization tasks that affect the appearance
|
|
|
|
* of the dialog box.
|
|
|
|
*/
|
2016-06-10 21:50:26 -04:00
|
|
|
SendMessage(l_hWnd, WM_INITDIALOG, (WPARAM)0, (LPARAM)0);
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2016-06-10 21:50:26 -04:00
|
|
|
return l_hWnd;
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void OwnerDrawnButton_init(OwnerDrawnButton * const me,
|
2016-06-10 21:50:26 -04:00
|
|
|
UINT itemID,
|
2012-08-14 18:07:04 -04:00
|
|
|
HBITMAP hBitmapUp, HBITMAP hBitmapDwn,
|
|
|
|
HCURSOR hCursor)
|
|
|
|
{
|
2016-06-10 21:50:26 -04:00
|
|
|
me->itemID = itemID;
|
2012-08-14 18:07:04 -04:00
|
|
|
me->hBitmapUp = hBitmapUp;
|
|
|
|
me->hBitmapDown = hBitmapDwn;
|
|
|
|
me->hCursor = hCursor;
|
2016-06-10 21:50:26 -04:00
|
|
|
me->isDepressed = 0;
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
|
|
void OwnerDrawnButton_xtor(OwnerDrawnButton * const me) {
|
|
|
|
DeleteObject(me->hBitmapUp);
|
|
|
|
DeleteObject(me->hBitmapDown);
|
2016-06-10 21:50:26 -04:00
|
|
|
DeleteObject(me->hCursor);
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
|
|
enum OwnerDrawnButtonAction OwnerDrawnButton_draw(
|
|
|
|
OwnerDrawnButton * const me,
|
|
|
|
LPDRAWITEMSTRUCT lpdis)
|
|
|
|
{
|
|
|
|
enum OwnerDrawnButtonAction ret = BTN_NOACTION;
|
|
|
|
|
|
|
|
if ((lpdis->itemAction & ODA_DRAWENTIRE) != 0U) {
|
|
|
|
if (me->hCursor != NULL) {
|
2016-11-01 15:38:29 -04:00
|
|
|
SetClassLongPtr(lpdis->hwndItem,
|
|
|
|
GCLP_HCURSOR, (LONG_PTR)me->hCursor);
|
2015-04-28 13:45:35 -04:00
|
|
|
me->hCursor = NULL; /* mark the cursor set */
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
DrawBitmap(lpdis->hDC, me->hBitmapUp,
|
|
|
|
lpdis->rcItem.left, lpdis->rcItem.top);
|
2016-06-10 21:50:26 -04:00
|
|
|
me->isDepressed = 0;
|
2012-08-14 18:07:04 -04:00
|
|
|
ret = BTN_PAINTED;
|
|
|
|
}
|
|
|
|
else if ((lpdis->itemAction & ODA_SELECT) != 0U) {
|
|
|
|
if ((lpdis->itemState & ODS_SELECTED) != 0U) {
|
|
|
|
DrawBitmap(lpdis->hDC, me->hBitmapDown,
|
|
|
|
lpdis->rcItem.left, lpdis->rcItem.top);
|
2016-06-10 21:50:26 -04:00
|
|
|
me->isDepressed = !0;
|
2012-08-14 18:07:04 -04:00
|
|
|
ret = BTN_DEPRESSED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* NOTE: the bitmap for button "UP" look will be
|
|
|
|
* drawn in the ODA_DRAWENTIRE action
|
|
|
|
*/
|
2016-06-10 21:50:26 -04:00
|
|
|
me->isDepressed = 0;
|
2012-08-14 18:07:04 -04:00
|
|
|
ret = BTN_RELEASED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2016-06-10 21:50:26 -04:00
|
|
|
/*..........................................................................*/
|
|
|
|
void OwnerDrawnButton_set(OwnerDrawnButton * const me, int isDepressed) {
|
|
|
|
if (me->isDepressed != isDepressed) {
|
|
|
|
HWND hItem = GetDlgItem(l_hWnd, me->itemID);
|
|
|
|
me->isDepressed = isDepressed;
|
|
|
|
if (isDepressed) {
|
|
|
|
DrawBitmap(GetDC(hItem), me->hBitmapDown, 0, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DrawBitmap(GetDC(hItem), me->hBitmapUp, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
|
|
BOOL OwnerDrawnButton_isDepressed(OwnerDrawnButton const * const me) {
|
|
|
|
return me->isDepressed;
|
|
|
|
}
|
2012-08-14 18:07:04 -04:00
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
2013-09-23 14:34:35 -04:00
|
|
|
void GraphicDisplay_init(GraphicDisplay * const me,
|
2016-06-10 21:50:26 -04:00
|
|
|
UINT width, UINT height,
|
|
|
|
UINT itemID, BYTE const bgColor[3])
|
2012-08-14 18:07:04 -04:00
|
|
|
{
|
|
|
|
BITMAPINFO bi24BitInfo;
|
2016-06-10 21:50:26 -04:00
|
|
|
RECT rect;
|
|
|
|
|
|
|
|
me->src_width = width;
|
|
|
|
me->src_height = height;
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2016-06-10 21:50:26 -04:00
|
|
|
me->hItem = GetDlgItem(l_hWnd, itemID);
|
|
|
|
me->dst_hDC = GetDC(me->hItem);
|
|
|
|
GetWindowRect(me->hItem, &rect);
|
|
|
|
me->dst_width = rect.right - rect.left;
|
|
|
|
me->dst_height = rect.bottom - rect.top;
|
2012-08-14 18:07:04 -04:00
|
|
|
|
|
|
|
me->bgColor[0] = bgColor[0];
|
|
|
|
me->bgColor[1] = bgColor[1];
|
|
|
|
me->bgColor[2] = bgColor[2];
|
|
|
|
|
2015-04-28 13:45:35 -04:00
|
|
|
bi24BitInfo.bmiHeader.biBitCount = 3U*8U; /* 3 RGB bytes */
|
|
|
|
bi24BitInfo.bmiHeader.biCompression = BI_RGB; /* RGB color */
|
2012-08-14 18:07:04 -04:00
|
|
|
bi24BitInfo.bmiHeader.biPlanes = 1U;
|
|
|
|
bi24BitInfo.bmiHeader.biSize = sizeof(bi24BitInfo.bmiHeader);
|
2016-06-10 21:50:26 -04:00
|
|
|
bi24BitInfo.bmiHeader.biWidth = me->src_width;
|
|
|
|
bi24BitInfo.bmiHeader.biHeight = me->src_height;
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2016-06-10 21:50:26 -04:00
|
|
|
me->src_hDC = CreateCompatibleDC(me->dst_hDC);
|
|
|
|
me->hBitmap = CreateDIBSection(me->src_hDC, &bi24BitInfo, DIB_RGB_COLORS,
|
2012-08-14 18:07:04 -04:00
|
|
|
(void **)&me->bits, 0, 0);
|
2016-06-10 21:50:26 -04:00
|
|
|
SelectObject(me->src_hDC, me->hBitmap);
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
GraphicDisplay_clear(me);
|
|
|
|
GraphicDisplay_redraw(me);
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
2013-09-23 14:34:35 -04:00
|
|
|
void GraphicDisplay_xtor(GraphicDisplay * const me) {
|
2016-06-10 21:50:26 -04:00
|
|
|
DeleteDC(me->src_hDC);
|
2012-08-14 18:07:04 -04:00
|
|
|
DeleteObject(me->hBitmap);
|
2016-06-10 21:50:26 -04:00
|
|
|
OutputDebugString("GraphicDisplay_xtor\n");
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
2013-09-23 14:34:35 -04:00
|
|
|
void GraphicDisplay_clear(GraphicDisplay * const me) {
|
2012-08-14 18:07:04 -04:00
|
|
|
UINT n;
|
|
|
|
BYTE r = me->bgColor[0];
|
|
|
|
BYTE g = me->bgColor[1];
|
|
|
|
BYTE b = me->bgColor[2];
|
|
|
|
BYTE *bits = me->bits;
|
|
|
|
|
2016-06-10 21:50:26 -04:00
|
|
|
for (n = me->src_width * me->src_height; n != 0U; --n, bits += 3) {
|
2012-08-14 18:07:04 -04:00
|
|
|
bits[0] = b;
|
|
|
|
bits[1] = g;
|
|
|
|
bits[2] = r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
2013-09-23 14:34:35 -04:00
|
|
|
void GraphicDisplay_redraw(GraphicDisplay * const me) {
|
2016-06-10 21:50:26 -04:00
|
|
|
StretchBlt(me->dst_hDC, 0, 0, me->dst_width, me->dst_height,
|
|
|
|
me->src_hDC, 0, 0, me->src_width, me->src_height, SRCCOPY);
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SegmentDisplay ----------------------------------------------------------*/
|
|
|
|
void SegmentDisplay_init(SegmentDisplay * const me,
|
|
|
|
UINT segmentNum, UINT bitmapNum)
|
|
|
|
{
|
|
|
|
UINT n;
|
|
|
|
|
|
|
|
me->hSegment = (HWND *)calloc(segmentNum, sizeof(HWND));
|
|
|
|
me->segmentNum = segmentNum;
|
|
|
|
for (n = 0U; n < segmentNum; ++n) {
|
|
|
|
me->hSegment[n] = NULL;
|
|
|
|
}
|
|
|
|
me->hBitmap = (HBITMAP *)calloc(bitmapNum, sizeof(HBITMAP));
|
|
|
|
me->bitmapNum = bitmapNum;
|
|
|
|
for (n = 0U; n < bitmapNum; ++n) {
|
|
|
|
me->hBitmap[n] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
|
|
void SegmentDisplay_xtor(SegmentDisplay * const me) {
|
|
|
|
UINT n;
|
|
|
|
|
|
|
|
for (n = 0U; n < me->segmentNum; ++n) {
|
|
|
|
DeleteObject(me->hSegment[n]);
|
|
|
|
}
|
|
|
|
free(me->hSegment);
|
|
|
|
|
|
|
|
for (n = 0U; n < me->bitmapNum; ++n) {
|
|
|
|
DeleteObject(me->hBitmap[n]);
|
|
|
|
}
|
|
|
|
free(me->hBitmap);
|
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
|
|
BOOL SegmentDisplay_initSegment(SegmentDisplay * const me,
|
2016-06-10 21:50:26 -04:00
|
|
|
UINT segmentNum, UINT segmentID)
|
2012-08-14 18:07:04 -04:00
|
|
|
{
|
2016-06-10 21:50:26 -04:00
|
|
|
if (segmentNum < me->segmentNum) {
|
|
|
|
me->hSegment[segmentNum] = GetDlgItem(l_hWnd, segmentID);
|
|
|
|
return me->hSegment[segmentNum] != NULL;
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
|
|
BOOL SegmentDisplay_initBitmap(SegmentDisplay * const me,
|
|
|
|
UINT bitmapNum, HBITMAP hBitmap)
|
|
|
|
{
|
|
|
|
if ((bitmapNum < me->bitmapNum) && (hBitmap != NULL)) {
|
|
|
|
me->hBitmap[bitmapNum] = hBitmap;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*..........................................................................*/
|
|
|
|
BOOL SegmentDisplay_setSegment(SegmentDisplay * const me,
|
|
|
|
UINT segmentNum, UINT bitmapNum)
|
|
|
|
{
|
|
|
|
if ((segmentNum < me->segmentNum) && (bitmapNum < me->bitmapNum)) {
|
|
|
|
SendMessage(me->hSegment[segmentNum], STM_SETIMAGE,
|
|
|
|
IMAGE_BITMAP,
|
|
|
|
(LPARAM)me->hBitmap[bitmapNum]);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* DrawBitmap() function adapted from the book "Programming Windows" by
|
|
|
|
* Charles Petzold.
|
|
|
|
*/
|
|
|
|
void DrawBitmap(HDC hdc, HBITMAP hBitmap,
|
|
|
|
int xStart, int yStart)
|
|
|
|
{
|
|
|
|
BITMAP bm;
|
|
|
|
POINT ptSize, ptOrg;
|
|
|
|
HDC hdcMem = CreateCompatibleDC(hdc);
|
|
|
|
|
|
|
|
SelectObject(hdcMem, hBitmap);
|
|
|
|
SetMapMode(hdcMem, GetMapMode(hdc));
|
|
|
|
|
|
|
|
GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
|
|
|
|
ptSize.x = bm.bmWidth;
|
|
|
|
ptSize.y = bm.bmHeight;
|
|
|
|
DPtoLP(hdc, &ptSize, 1);
|
|
|
|
|
|
|
|
ptOrg.x = 0;
|
|
|
|
ptOrg.y = 0;
|
|
|
|
DPtoLP(hdcMem, &ptOrg, 1);
|
|
|
|
|
|
|
|
BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y,
|
|
|
|
hdcMem, ptOrg.x, ptOrg.y, SRCCOPY);
|
|
|
|
DeleteDC(hdcMem);
|
|
|
|
}
|
|
|
|
|
|
|
|
|