/* tabhand.c */ /***************************************************************************** PROGRAM: tabhand.c PURPOSE: Taulukkoviestit käsittelevä aliohjelma. Käyttö: ks. tabhand.h Täällä on myös valmiita käsittelijäfunktioita: EVENTHANDLER_WM_DESTROY 1) Jos checker.c on käytössä, täytyy EndPaint kutsun sijasta kutsua CheckEndPaint. 2) Jos kyseessä on dialogin ikkunafunktio, pitää palauttaa TRUE (=viesti käsitelty) ja FALSE (viestiä ei käsitelty). Samalla funktion tyyppi täytyy olla BOOL 3) Vastaavasti tavallisilla ikkunoilla kutsutaan DefWindowProc, jollei viestiä ole käsitelty. Tällöin funktion tyyppi täytyy olla LONG Nämä ominaisuudet määrätään tabhand.h:n makrojen TWINDOWPROC(tbl,name) TDIALOGPROC(tbl,name) TCDIALOGPROC(tbl,name) TWINDOWPROC_C(tbl,name) luomilla funktiolla. Editor: Vesa Lappalainen 11.7.1994 *****************************************************************************/ #include #include #include "tabhand.h" /*****************************************************************************/ /* Taulukko, jossa viestit, joista osataan ottaa id, cmd ja hWnd */ /* ks. windowsx.h, esim. GET_WM_COMMAND_ID ja muut vastaavat. */ static UINT MSG_table[]={ WM_ACTIVATE,WM_CHARTOITEM,WM_COMMAND,WM_MENUSELECT,WM_MENUCHAR, WM_PARENTNOTIFY,WM_VKEYTOITEM, 0 }; /*****************************************************************************/ static int find_table_entry(WPARAM wParam, LONG address, LPARAM *e) /* Tutkitaan onko wParam jokin taulukosta löytyvä tunnus! */ { tMsgTTable *t = (tMsgTTable*)address; for ( ; t->wParam != DONT_CARE; t++) if ( t->wParam == wParam ) { if ( t->extra == SAME_AS_W ) *e = wParam; else *e = t->extra; return 1; } return 0; } typedef enum { OtherMsg,CommandMsg,ScrollMsg } tmsgType; /*****************************************************************************/ static tmsgType GetMsgType(UINT message) /* Tutkitaan onko viesti jokin, josta ostaan otta id, cmd ja hWnd */ { UINT *m = MSG_table; for (; *m; m++) if ( *m == message ) return CommandMsg;; if ( message == WM_VSCROLL || message == WM_HSCROLL ) return ScrollMsg; return OtherMsg; } /*****************************************************************************/ typedef struct { WPARAM wp; LPARAM e; LPARAM lp; EndPaintHandler EndPaint; tmsgType msgType; tMSGParam msg; } tMsgFindParam; /*****************************************************************************/ static LONG DoMsgTableEntry(const tMSGEntry *m, tMsgFindParam *tmf) /* Suoritetaan varsinainen käsittelijän kutsu */ { PAINTSTRUCT ps; LONG ret = DEFRETURN; tMSGParam *msg = &tmf->msg; switch ( tmf->msgType ) { case OtherMsg: msg->id = 0; msg->cmd = 0; msg->chWnd = 0; break; case CommandMsg: /* WM_COMMAND -tyyliset viestit */ msg->id = tmf->wp; msg->cmd = (WPARAM)(tmf->lp); msg->chWnd = GET_WM_COMMAND_HWND(msg->wParam,msg->lParam); break; case ScrollMsg: /* Scrollbarin viestit */ msg->id = tmf->wp; msg->cmd = (WPARAM)(tmf->lp); msg->chWnd = GET_WM_VSCROLL_HWND(msg->wParam,msg->lParam); msg->flag = SB_CTL; if ( msg->chWnd == NULL ) { msg->chWnd = msg->hWnd; msg->flag = ( msg->message == WM_VSCROLL ? SB_VERT : SB_HORZ ); } msg->value = GetScrollPos(msg->chWnd,msg->flag); break; } msg->hDC = 0; if ( m->extra == SAME_AS_W ) msg->extra = tmf->wp; else if ( m->extra == FROM_TBL ) msg->extra = tmf->e; else msg->extra = m->extra; if ( m->make_hDC ) { /* Tehdään valmis DC */ if ( msg->message == WM_PAINT ) { if ( BeginPaint(msg->hWnd,&ps) == NULL ) return DEFRETURN; msg->hDC = ps.hdc; } else if ( ( msg->hDC = GetDC(msg->hWnd) ) == NULL ) return DEFRETURN; } /* Tehdään valmis DC */ if ( m->pMSGFunctions && m->pMSGFunctions->before ) if ( m->pMSGFunctions->before(&(tmf->msg)) ) return -1; if ( m->handler ) ret = m->handler(&(tmf->msg)); if ( m->make_hDC ) { /* poistetaan DC */ if ( msg->message == WM_PAINT ) tmf->EndPaint(msg->hWnd,&ps); else ReleaseDC(msg->hWnd,msg->hDC); if ( tmf->EndPaint != EndPaint ) /* Toivottovasti on CheckEndPaint */ tmf->EndPaint(msg->hWnd,NULL); /* Jolloin tämä tekee CheckDelayMes..*/ } if ( m->pMSGFunctions && m->pMSGFunctions->after ) m->pMSGFunctions->after(&(tmf->msg)); return ret; } /*****************************************************************************/ static LONG FindMsgEntry(const tMSGEntry *MsgTbl, tMsgFindParam *tmf) /* Etsitään taulukosta löytyykö oikea käsittelijä. Jos löytyy, kutsutaan ** sitä ja etsimistä jatketaan vain jos käsittelijä sitä vaatii. ** Jos tulukosta löytyy haaroja (TB_LOOK_TABLE) muihin taulukoihin, ** käydään ne rekursiivisesti läpi ja jatketaan perustaulukkoa mikäli ** haarataulukko pyytää jatkamaan ( CONTINUE_TABLE ). */ { const tMSGEntry *n,*m; long ret; UINT message = tmf->msg.message; for (m = MsgTbl; m->message; m++) { /* Etsitään viestin käsittelijää */ if ( ( m->message == message || m->message == DONT_CARE || ( m->message == WM_SCROLL && ( message == WM_VSCROLL || message == WM_HSCROLL ) ) ) && ( m->wParam == tmf->wp || m->wParam == DONT_CARE || ( m->wParam == TRANGE && (WPARAM)m->ex1 <= tmf->wp && tmf->wp <= (WPARAM)m->ex2 ) || ( m->wParam == TTABLE && find_table_entry(tmf->wp,m->ex1,&tmf->e) ) ) && ( m->lParam == tmf->lp || m->lParam == DONT_CARE ) ) { ret = DoMsgTableEntry(m,tmf); if ( ret != CONTINUE_TABLE ) return ret; } if ( m->message == TB_LOOK_TABLE ) { /* Siirrytään rekurs. etsimiseen */ n = (const tMSGEntry *)(m->handler); if ( n == NULL ) continue; ret = FindMsgEntry(n,tmf); if ( ret != CONTINUE_TABLE ) return ret; } } return CONTINUE_TABLE; } /*****************************************************************************/ LONG MSGTableHandler(const tMSGEntry *MsgTbl, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, EndPaintHandler EndPaint) { long ret; tMsgFindParam tmf; switch ( tmf.msgType = GetMsgType(message) ) { case OtherMsg: tmf.wp = wParam; tmf.lp = lParam; break; case CommandMsg: tmf.wp = GET_WM_COMMAND_ID(wParam,lParam); tmf.lp = GET_WM_COMMAND_CMD(wParam,lParam); break; case ScrollMsg: tmf.wp = GetDlgCtrlID(GET_WM_VSCROLL_HWND(wParam,lParam)); tmf.lp = GET_WM_VSCROLL_CODE(wParam,lParam); if ( tmf.wp == 0 ) if ( message == WM_HSCROLL ) tmf.wp = SB_HORZ; else if ( message == WM_VSCROLL ) tmf.wp = SB_VERT; break; } tmf.e = tmf.wp; tmf.EndPaint = EndPaint; tmf.msg.hWnd = hWnd; tmf.msg.message = message; tmf.msg.wParam = wParam; tmf.msg.lParam = lParam; ret = FindMsgEntry(MsgTbl,&tmf); return ret == CONTINUE_TABLE ? DEFRETURN : ret; } /*****************************************************************************/ int SetNewScrollPos(tMSGParam *msg,int pagesize,BOOL modify) { int value = msg->value; int smin,smax; if ( msg->message != WM_VSCROLL && msg->message != WM_HSCROLL ) return 0; GetScrollRange(msg->chWnd,msg->flag,&smin,&smax); switch ( msg->cmd ) { case SB_BOTTOM : value = smin; break; case SB_TOP : value = smax; break; case SB_LINEDOWN : value++; break; case SB_PAGEDOWN : value += pagesize; break; case SB_LINEUP : value--; break; case SB_PAGEUP : value -= pagesize; break; case SB_THUMBPOSITION: case SB_THUMBTRACK : value = GET_WM_VSCROLL_POS(msg->wParam,msg->lParam); break; } if ( value < smin ) value = smin; if ( smax < value ) value = smax; if ( modify ) { SetScrollPos(msg->chWnd,msg->flag,value,TRUE); msg->value = value; } return value; } /*****************************************************************************/ int AddWaiting(HWND hWnd,tWaitingShow *WaitShow) /* Lisätään ikkunan kahva odottamaan WM_SHOWWINDOW-kutsua. */ /* Näin saadaan myös CLASS-dialogeille järjestettyä WM_INITDIALOG-viesti. */ { if ( WaitShow->n >= MAX_WAITINGS ) return 1; WaitShow->hwnds[WaitShow->n++] = hWnd; return 0; } /*****************************************************************************/ int IsWaiting(HWND hWnd,tWaitingShow *WaitShow) /* Tutkitaan onko hWnd odottamassa WM_SHOWWINDOW-viestiä. Jos on, palaut. 1 */ /* ja poistetaan samalla hWnd odotuksesta! */ { int i; if ( WaitShow->n == 0 ) return 0; for (i=0; i < WaitShow->n; i++ ) if ( WaitShow->hwnds[i] == hWnd ) { for ( ; i < WaitShow->n-1; i++ ) WaitShow->hwnds[i] = WaitShow->hwnds[i+1]; WaitShow->hwnds[i] = 0; WaitShow->n--; return 1; } return 0; } /*****************************************************************************/ HWND DoClassWindowCmd(HINSTANCE hInstance, char *classname, char *iconname, HWND phWnd, char *wtitle, WNDPROC MainWndProc, DWORD more_style,int nCmdShow, tWNDCLASSHandler wcHandler) { tCreWndSt c; HWND hWnd; /* ikkunan kahva */ DWORD style = WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; if ( more_style & WS_CAPTION ) style = more_style; else style |= more_style; c.cs.lpCreateParams = NULL; c.cs.hInstance = hInstance; c.cs.hMenu = NULL; c.cs.hwndParent = phWnd; c.cs.cy = CW_USEDEFAULT; c.cs.cx = CW_USEDEFAULT; c.cs.y = CW_USEDEFAULT; c.cs.x = CW_USEDEFAULT; c.cs.style = style; c.cs.lpszName = wtitle; c.cs.lpszClass = classname; c.cs.dwExStyle = 0; /* if ( ) */ { /* Onko muita esiintymiä käynnisssä? */ c.wc.style = 0; // NULL; c.wc.lpfnWndProc = MainWndProc; c.wc.cbClsExtra = 0; c.wc.cbWndExtra = 0; c.wc.hInstance = hInstance; c.wc.hIcon = iconname ? LoadIcon(hInstance, iconname) : LoadIcon(NULL, IDI_APPLICATION); c.wc.hCursor = LoadCursor(NULL, IDC_ARROW); c.wc.hbrBackground = GetStockObject(WHITE_BRUSH); c.wc.lpszMenuName = "menu"; c.wc.lpszClassName = classname; if ( wcHandler ) wcHandler(&c); RegisterClass(&c.wc); /* if ( !RegisterClass(&wc) ) return NULL; */ } hWnd = CreateWindowEx(c.cs.dwExStyle, c.cs.lpszClass,c.cs.lpszName,c.cs.style, c.cs.x,c.cs.y,c.cs.cx,c.cs.cy, c.cs.hwndParent,c.cs.hMenu,c.cs.hInstance, c.cs.lpCreateParams); if ( !hWnd ) return NULL; ShowWindow(hWnd,nCmdShow); /* Näytetään ikkuna */ return hWnd; } /*****************************************************************************/ int tMessageLoop(void) { MSG msg; while ( GetMessage(&msg,NULL,0,0) ) { TranslateMessage(&msg); /* Tulkitaan virtuaaliset näp. koodit */ DispatchMessage(&msg); /* Lähetetään viesti ikkunalle */ } return msg.wParam; /* Palautetaan PostQuitMessage-funktion arvo */ } /*****************************************************************************/ POINT tGetClientLost(HWND hWnd) { RECT cRC,wRC; POINT p; GetWindowRect(hWnd,&wRC); GetClientRect(hWnd,&cRC); p.x = ( wRC.right - wRC.left ) - ( cRC.right - cRC.left ); p.y = ( wRC.bottom - wRC.top ) - ( cRC.bottom - cRC.top ); return p; } /*****************************************************************************/ void tGetClientWindowRect(HWND hWnd,HWND hWndc,RECT *rcc) { RECT rcp,rci; POINT p = tGetClientLost(hWnd); int dx = p.x/2; GetWindowRect(hWnd,&rcp); GetWindowRect(hWndc,&rci); rcc->top = rci.top - rcp.top - p.y + dx; rcc->left = rci.left - rcp.left - dx; rcc->bottom = rcc->top + ( rci.bottom - rci.top ); rcc->right = rcc->left + ( rci.right - rci.left); } /*****************************************************************************/ /* Valmiita käsittelijöitä: */ /*****************************************************************************/ EVENT EVENT_handler_WM_destroy(tMSGParam *msg) { #pragma argsused PostQuitMessage(0); return 0; }