/**************/ /* nappula4.c */ /****************************************************************************/ /* ** Aliohjelmakirjasto nappuloiden ja laskureiden piirtämiseksi näytölle. ** Windows-versio nappuloiden siirto ja suurennusmahdollisuudella. ** ** Kutsuvassa ohjelmassa määritellään taulukko näppäimistä ja ** taulukko laskureista. ** ** Näppäimen painamista joko näppäimistöltä tai hiireltä odotetaan ** aliohjelmalla 'lue_komento'. Aliohjelma palauttaa valittua ** komentoa vastaavan tunnuksen. Tunnukset on määritelty ** käyttäjän ohjelmassa. Negatiiviset tunnukset on varattu ** systeemikäyttöön ja käyttäjän ohjelman on reagoitava myös niihin. ** Esim. mikäli palautetaan komento PIIRRA, pitää käyttäjän piirtää ** koko näyttö uudelleen (koska joku on sen sotkenut). ** ** Nappulan tai laskurin yläreunasta tarttumalla voidaan ** laatikon paikkaa näytöllä siirtää. ** Oikeasta alakulmasta voidaan laatikon kokoa muuttaa. ** ** Useita nappuloita voidaan siirtää tai venyttää kerralla valitsemalla ** niistä joukko. Nappula voidaan liittää/poistaa joukkoon painamalla CTRL ** ja napauttamalla hiirtä nappulan päällä. Joukkoon voidaan valita myös ** suorakaiteella. Suorakaide aloitetaan painamalla CTRL-pohjaan ja ** vetämällä hiirellä alue alkaen tyhjästä kohdasta (ei siis minkään ** nappulan päältä). Joukko tyhjennetään napauttamalla tyhjän alueen päällä ** niin ETTEI CTRL-ole pohjassa! */ /****************************************************************************/ #include #include #include #include "nappula3.h" /****************************************************************************/ #define skaalaa_x(x) ((int)(((long int)x - MIN_X) * KERROIN_X + MIN_H_X)) #define skaalaa_y(y) ((int)(((long int)y - MIN_Y) * KERROIN_Y + MIN_H_Y)) #define SISA_LISA 3 /* 2x raamin sisäreunan etäisyys vars. laatikosta */ #define ULKO_LISA 6 /* 2x raamin ulkoreunan etäisyys vars. laatikosta */ #define SISA_SADE (5*SISA_LISA) #define ULKO_SADE (SISA_SADE+(ULKO_LISA-SISA_LISA)) #define RECT_TO_4(r,dr) r.left-dr,r.top-dr,r.right+dr,r.bottom+dr #define LAATIKKO_TO_4(r,dr) r.vasen_yla.x-dr,r.vasen_yla.y-dr,\ r.vasen_yla.x+r.koko.x+dr,r.vasen_yla.y+r.koko.y+dr #define MainWClass "LaskinLuokka" static nappain_tyyppi *nappaimet = NULL; static laskuri_tyyppi *laskurit = NULL; static HWND hWnd; static MSG msg; static int KERROIN_X = ( MAX_H_X - MIN_H_X + 1) / ( MAX_X - MIN_X +1 ); static int KERROIN_Y = ( MAX_H_Y - MIN_H_Y + 1) / ( MAX_Y - MIN_Y +1 ); static int MIN_LEVEYS = 0; static int lisaviesti = 0; static int paaviesti = EI_KOMENTOA; static HCURSOR hCsize; static HCURSOR hCmove; static HCURSOR hCarrow; static HCURSOR hCpress; /****************************************************************************/ /* Muutoksiin (venytys ja siirto) liittyviä glob. vakioita ja muuttujia: */ typedef struct { /* Tyyppi, jossa on muutettavan laatikon tiedot*/ laatikko_tyyppi *pmuutos; /* Osoitin muutettavaan laatikkoon */ laatikko_tyyppi alkup; /* Laatikon alkuperäiset tiedot */ } muutos_tyyppi; static muutos_tyyppi Muutettava; #define SIIRTO 1 #define VENYTYS 0 static int Muutostapa = SIIRTO; /* Onko muutos SIIRTO vai VENYTYS */ static int fMuutos = 0; /* =1 jos muutos meneillään */ static POINT AloitusPiste; /* Hiiren paikka kun muutos aloitet.*/ static laatikko_tyyppi ValintaLaatikko; /* Alueen valintalaatikko */ static int fValinta; /* Onko alueen valinta menossa? */ #define MAX_VALITTUJA 50 /* Joukkoon valittavien maksimimäärä*/ static int valittuja = 0; /* Joukkoon nyt valittuja */ static muutos_tyyppi valitut[MAX_VALITTUJA]; /* Valittujen joukko */ /* Värien määrittelyt: */ #define BLACK RGB(0,0,0) #define BLUE RGB(0,0,255) #define CYAN RGB(0,255,255) #define YELLOW RGB(255,255,0) #define GRAY RGB(180,180,180) int laatikossa(laatikko_tyyppi *tila,POINT *pt); /****************************************************************************/ void piirra_NOT_laatikko(laatikko_tyyppi *tila) /* Piirretään laatikon reunat NOT-kynällä (käännetään kaikki värit ** päinvastoin. Piirtämällä kaski kertaa sama laatikko, on se hävinnyt ** kuvasta. Kätevä siirroissa, kun voidaan tehdä: ** piirra_NOT_laatikko - pyyhkii vanhan pois ** siirra - laatikolle uudet koordinaatit ** piirra_not_laatikko - piirretään laatikko uuteen paikkaan */ { HDC hdc = GetDC(hWnd); SelectObject(hdc,GetStockObject(NULL_BRUSH)); SetROP2(hdc,R2_NOT); Rectangle(hdc,LAATIKKO_TO_4((*tila),ULKO_LISA)); ReleaseDC(hWnd,hdc); } /****************************************************************************/ void merkitse_laatikko(laatikko_tyyppi *tila) /* Merkitään laatikon yläreuna harmaalla värillä. */ { HDC hdc = GetDC(hWnd); SelectObject(hdc,GetStockObject(GRAY_BRUSH)); Rectangle(hdc,tila->vasen_yla.x,tila->vasen_yla.y-ULKO_LISA, tila->vasen_yla.x+tila->koko.x,tila->vasen_yla.y); ReleaseDC(hWnd,hdc); } /****************************************************************************/ int piirra_valitut_NOT(void) /* Piirretään valitut laatikot NOT-kynällä */ { int i; for (i=0; i 0 ); } /****************************************************************************/ int siirra_laatikko(muutos_tyyppi *muutos, LONG lParam) /* Siirretään laatikon koordinaatteja alkuperäisestä sen verran mitä hiiri ** on liikkunut siirron aloittamisesta. */ { POINT pt = MAKEPOINT(lParam); muutos->pmuutos->vasen_yla.x = muutos->alkup.vasen_yla.x + pt.x - AloitusPiste.x; muutos->pmuutos->vasen_yla.y = muutos->alkup.vasen_yla.y + pt.y - AloitusPiste.y; return 0; } /****************************************************************************/ int venyta_laatikkoa(muutos_tyyppi *muutos, LONG lParam) /* Venytetään laatikon kokoa alkuperäisestä sen verran mitä hiiri on ** liikkunut siirron aloittamisesta. */ { POINT pt = MAKEPOINT(lParam); muutos->pmuutos->koko.x = max(MIN_LEVEYS, (int)(muutos->alkup.koko.x + pt.x - AloitusPiste.x)); muutos->pmuutos->koko.y = max(MIN_LEVEYS, (int)(muutos->alkup.koko.y + pt.y - AloitusPiste.y)); return 0; } /****************************************************************************/ int siirra_valitut(LONG lParam) /* Muutetaan kaikkien valittujen laatikoiden koordinaateja. */ { int i; for (i=0; i 0 ); } /****************************************************************************/ int venyta_valitut(LONG lParam) /* Muutetaan kaikkein valittujen laatikoiden kokoa. */ { int i; for (i=0; i 0 ); } /****************************************************************************/ int muuta(LONG lParam) /* Tehdään 'valittuhin' (jollei valinta menossa ja valittuja on) ** tai 'Muutettava' -laatikkoon ** siirto (jos SIIRTO) tai venytys sen mukaisesti mitä hiiri on liikkunut ** muutoksen alkuhetken jälkeen. */ { if ( !fValinta && valittuja ) { piirra_valitut_NOT(); if ( Muutostapa == SIIRTO ) siirra_valitut(lParam); if ( Muutostapa == VENYTYS ) venyta_valitut(lParam); piirra_valitut_NOT(); return 0; } piirra_NOT_laatikko(Muutettava.pmuutos); if ( Muutostapa == SIIRTO ) siirra_laatikko(&Muutettava,lParam); if ( Muutostapa == VENYTYS ) venyta_laatikkoa(&Muutettava,lParam); piirra_NOT_laatikko(Muutettava.pmuutos); return 0; } /****************************************************************************/ int liita_valittuihin(laatikko_tyyppi *tila, int ala_poista) /* Liitetään uusi laatikko 'tila' valittujen joukkoon. Mikäli ** laatikko on jo joukossa ennestään, poistetaan se sietlä, jos lippu ** 'ala_poista' ei ole päällä. Jos lippu on päällä ja tila on ennestään ** joukossa, ei tehdä mitään. ** ** Kun laatikko lisätään joukkoon, merkitään se myös näyttöön. ** ** Palautetaan EI_KOMENTOA */ { int i,j; if ( valittuja >= MAX_VALITTUJA ) return EI_KOMENTOA; for (i=0; ivasen_yla.x; pt.y = tila->vasen_yla.y; return laatikossa(valinta,&pt); } /****************************************************************************/ int valitse_tilassa_olevat(void) /* Lisätään valitujen joukkoon kaikki ne laatikot, joiden vasen ylänurkka ** jäi ValintaLaatikon sisälle. Merkitään myös valitut näyttöön. */ { int i; for (i=0; nappaimet[i].valinta_kirjain; i++) { if ( tila_laatikossa(&ValintaLaatikko,&(nappaimet[i].nappain)) ) liita_valittuihin(&nappaimet[i].nappain,1); } for (i=0; laskurit[i].tunnus; i++) { if ( tila_laatikossa(&ValintaLaatikko,&(laskurit[i].tila)) ) liita_valittuihin(&laskurit[i].tila,1); } return 0; } /****************************************************************************/ int lopeta_muutos(LONG lParam) /* Lopetetaan muutoksen tekeminen, eli ilmoitetaan näyttö piirrettäväksi ** uudelleen ja liitetään mahdolliset ValintaLaatikon sisään jääneet ** laatikot valittujen joukkoon. ** Mikäli valittujen joukossa on vain yksi, poistetaan se sieltä, koska ** muuten yhden laatikon siirtämisen jälkeen se pitäisi itse poistaa. ** ** Yhden laatikon siirto tai venytys on toteutettu siten, että se ** liitetään ainoana joukkoon. */ { POINT pt = MAKEPOINT(lParam); fMuutos = 0; if ( fValinta == 1 ) { valitse_tilassa_olevat(); /* ValintaLaatikon sammuttaminen ei vaadi koko näytön uudelleen piirtämistä: */ piirra_NOT_laatikko(Muutettava.pmuutos); } else { /* Jos paikka ei ole muuttunut, ei koko näyttöä tarvitse piirtää */ /* vaan poistaa kaikki valitut näytöstä. */ if ( pt.x != AloitusPiste.x || pt.y != AloitusPiste.y ) InvalidateRect(hWnd,NULL,TRUE); else if ( valittuja ) piirra_valitut_NOT(); else piirra_NOT_laatikko(Muutettava.pmuutos); /* Yhden valitun käsittely : */ if ( valittuja == 1 ) { valittuja = 0; InvalidateRect(hWnd,NULL,TRUE); } } fValinta = 0; return 0; } /****************************************************************************/ int aloita_muutos( /* Palauttaa aina EI_KOMENTOA */ int muutos, /* Mikä muutos aloitetaan? */ laatikko_tyyppi *tila, /* Mitä laatikkoa muutetaan */ POINT *pt, /* Muutoksen aloituspiste. */ int lisataanko /* Saako tilan lisätä listaan? */ ) /* ** Tehdään muutoksen aloituksessa tarvittavat toimenpiteet. ** Mikäli laatikkoa ei haluta lisätä listaan, laitetaan se ** 'Muutettava'-laatikoksi. ----------------------------------------------------------------------------*/ { AloitusPiste = *pt; fMuutos = 1; Muutostapa = muutos; if ( tila ) { if ( lisataanko ) liita_valittuihin(tila,1); else { Muutettava.pmuutos = tila; Muutettava.alkup = *tila; piirra_NOT_laatikko(Muutettava.pmuutos); } } paivita_valitut(); if ( !fValinta) piirra_valitut_NOT(); return EI_KOMENTOA; } /****************************************************************************/ int aloita_tilan_valinta(POINT *pt) /* Palutetaan aina EI_KOMENTOA */ /* Aloitetaan ValintaLaatikon venytys. Laatikko on alunperin pieni. */ { ValintaLaatikko.vasen_yla.x = pt->x; ValintaLaatikko.vasen_yla.y = pt->y; ValintaLaatikko.koko.x = 1; ValintaLaatikko.koko.y = 1; ValintaLaatikko.muutettu = 1; fValinta = 1; return aloita_muutos(VENYTYS,&ValintaLaatikko,pt,0); } /****************************************************************************/ int /* 0 koord. ei laatikossa */ siirtokulmassa( /* 1 koord on laatikossa */ laatikko_tyyppi *tila, /* Tutkittava laatikko */ POINT *pt /* Tutkittava koodrinaatti */ ) /* Palautetaan tieto siitä, onko tutkittava koordinaatti siirron aloittavassa ** osassa laatikkoa (yläreuna). ----------------------------------------------------------------------------*/ { if ( ( pt->x < tila->vasen_yla.x - ULKO_LISA ) || ( pt->y < tila->vasen_yla.y - ULKO_LISA ) || ( pt->x >= tila->vasen_yla.x + tila->koko.x + ULKO_LISA ) || ( pt->y >= tila->vasen_yla.y ) ) return 0; return 1; } /****************************************************************************/ int /* 0 koord. ei laatikossa */ muutoskulmassa( /* 1 koord on laatikossa */ laatikko_tyyppi *tila, /* Tutkittava laatikko */ POINT *pt /* Tutkittava koodrinaatti */ ) /* Palautetaan tieto siitä, onko tutkittava koordinaatti venyt. aloittavassa ** osassa laatikkoa (oikea alanurkka). ----------------------------------------------------------------------------*/ { if ( ( pt->x <= tila->vasen_yla.x + tila->koko.x ) || ( pt->y <= tila->vasen_yla.y + tila->koko.y ) || ( pt->x > tila->vasen_yla.x + tila->koko.x + ULKO_LISA ) || ( pt->y > tila->vasen_yla.y + tila->koko.y + ULKO_LISA ) ) return 0; return 1; } /****************************************************************************/ int /* 0 koord. ei laatikossa */ do_siirtokulmassa( /* 1 koord on laatikossa */ laatikko_tyyppi *tila, /* Tutkittava laatikko */ POINT *pt /* Tutkittava koodrinaatti */ ) /* Palautetaan tieto siitä, onko tutkittava koordinaatti siirron aloittavassa ** osassa laatikkoa (yläreuna). Mikäli on, tehdään siirron aloittamisessa ** tarvittavat toimenpiteet ----------------------------------------------------------------------------*/ { if ( !siirtokulmassa(tila,pt) ) return 0; aloita_muutos(SIIRTO,tila,pt,1); return 1; } /****************************************************************************/ int /* 0 koord. ei laatikossa */ do_muutoskulmassa( /* 1 koord on laatikossa */ laatikko_tyyppi *tila, /* Tutkittava laatikko */ POINT *pt /* Tutkittava koodrinaatti */ ) /* Palautetaan tieto siitä, onko tutkittava koordinaatti venyt. aloittavassa ** osassa laatikkoa (oikea alanurkka). Mikäli on, tehdään venytyksen ** aloittamisessa tarvittavat toimenpiteet ----------------------------------------------------------------------------*/ { if ( !muutoskulmassa(tila,pt) ) return 0; aloita_muutos(VENYTYS,tila,pt,1); return 1; } /****************************************************************************/ int /* 0 koord. ei laatikossa */ laatikossa( /* 1 koord on laatikossa */ laatikko_tyyppi *tila, /* Tutkittava laatikko */ POINT *pt /* Tutkittava koodrinaatti */ ) /* Onko piste laatikon sisällä vai ei? */ { if ( ( tila->vasen_yla.x > pt->x ) || ( tila->vasen_yla.y > pt->y ) || ( tila->vasen_yla.x + tila->koko.x <= pt->x ) || ( tila->vasen_yla.y + tila->koko.y <= pt->y ) ) return 0; return 1; } /****************************************************************************/ int /* -1 jollei hiiri minkään napin koh */ tutki_hiiri( /* napin numero, jonka kohdalla hiiri*/ nappain_tyyppi *nappaimet, /* Tutkittavat näppäimet */ laskuri_tyyppi *laskurit, /* Tutkittavat laskurit */ LONG lparam, /* Viestin parametri */ WORD wparam /* Viestin parametri */ ) /* ** Tutkitaan onko hiiri jonkin napin kohdalla. Mikäli on, laitetaan ** vastaavan napin viestit ja palautetaan napin numero. ** Muuten palautetaan aina EI_KOMENTOA, vaikka tehtäisiin ** muutakin. ** Jos hiiri ei ole napin kohdalla, tutkitaan myös mahdollinen siirron ** tai venytken aloittaminen, tai joukkoon lisääminen. ** Valintajoukkoa käsitellään, mikäli CONTROL-näppäin on pohjassa viestin ** tullessa. ** ValintaLaatikon venytys aloitetaan, mikäli hiiri ei ole minkään ** napin tai siirto- tai venytyspaikan kohdalla ja CONTROL on pohjassa. ** Mikäli Laatikon venytys on jo menossa, ei sitä tietenkään aloiteta ** uudelleen. ** Jos hiirtä napautetaan tyhjän päällä, ilman CONTROL-näppäintä, ** poistetaan kaikki näppäimet valittujen joukosta. ----------------------------------------------------------------------------*/ { int i,control=0; POINT pt; pt = MAKEPOINT(lparam); control = wparam & MK_CONTROL ; /* Onko CONTROL-näppäin pohjassa? */ for (i=0; nappaimet[i].valinta_kirjain; i++) { if ( laatikossa(&nappaimet[i].nappain,&pt) ) if ( !control ) { paaviesti = nappaimet[i].komento; lisaviesti = nappaimet[i].lisa_viesti; return i; /* Palautetaan napin numero */ } else return liita_valittuihin(&nappaimet[i].nappain,0); if ( do_siirtokulmassa(&nappaimet[i].nappain,&pt) ) return EI_KOMENTOA; if ( do_muutoskulmassa(&nappaimet[i].nappain,&pt) ) return EI_KOMENTOA; } for (i=0; laskurit[i].tunnus; i++) { if ( laatikossa(&laskurit[i].tila,&pt) ) if ( control ) return liita_valittuihin(&laskurit[i].tila,0); if ( do_siirtokulmassa(&laskurit[i].tila,&pt) ) return EI_KOMENTOA; if ( do_muutoskulmassa(&laskurit[i].tila,&pt) ) return EI_KOMENTOA; } if ( control && !fValinta ) return aloita_tilan_valinta(&pt); fValinta = 0; if ( valittuja ) { valittuja = 0; InvalidateRect(hWnd,NULL,TRUE); } return EI_KOMENTOA; } /****************************************************************************/ int /* -1 jollei hiiri minkään napin koh */ tutki_paikka( /* napin numero, jonka kohdalla hiiri*/ nappain_tyyppi *nappaimet, /* Tutkittavat näppäimet */ laskuri_tyyppi *laskurit, /* Tutkittavat laskurit */ LONG lparam, /* Viestin parametri */ WORD wparam /* Viestin parametri */ ) /* ** Tutkitaan onko hiiri jonkin napin kohdalla. Mikäli on, laitetaan ** vastaavan paikkaa vastaava kursori näyttöön. ----------------------------------------------------------------------------*/ { #pragma argsused POINT pt; int i; pt = MAKEPOINT(lparam); for (i=0; nappaimet[i].valinta_kirjain; i++) { if ( laatikossa(&nappaimet[i].nappain,&pt) ) { SetCursor(hCpress); return i; /* Palautetaan napin numero */ } if ( siirtokulmassa(&nappaimet[i].nappain,&pt) ) { SetCursor(hCmove); return i; } if ( muutoskulmassa(&nappaimet[i].nappain,&pt) ) { SetCursor(hCsize); return i; } } for (i=0; laskurit[i].tunnus; i++) { if ( siirtokulmassa(&laskurit[i].tila,&pt) ) { SetCursor(hCmove); return i; } if ( muutoskulmassa(&laskurit[i].tila,&pt) ) { SetCursor(hCsize); return i; } } return EI_KOMENTOA; } /****************************************************************************/ int tutki_kirjaimet(nappain_tyyppi *nappaimet, WORD wParam) /* Tutkitaan onko painettu kirjain jonkin näppäimen valintakirjain. ** Mikäli on, laitetaan näppäimen viesti pääviestiksi. ** Palautetaan löytyneen napin numero. ----------------------------------------------------------------------------*/ { int i; char c = (char)toupper(wParam); for (i=0; nappaimet[i].valinta_kirjain; i++) if ( nappaimet[i].valinta_kirjain == c ) { paaviesti = nappaimet[i].komento; lisaviesti = nappaimet[i].lisa_viesti; return i; } return EI_KOMENTOA; } /****************************************************************************/ int lue_komento( /* Valitun komennon tunnistin */ nappain_tyyppi *pnappaimet, /* Tutkittavat näppäimet */ laskuri_tyyppi *plaskurit, /* Käytettävät laskurit */ int *lisa /* Komennon lisäosa. */ ) /* ** Funktio palauttaa valitun komennon tunnuksen ja mahdollisen lisäviestin. ** Windows versiossa funktio on toteutettu siten, että ohjelman pääsilmukka ** on sijoitettu tähän. 'MainWndProc' huolehtii sitten Windowsin kutsumana ** viestien käsittelystä. Mikäli viestistä seuraa, että 'lue_komento'- ** aliohjelman pitäisi palauttaa jotakin kutsuvalle ohjelmalle, asetetaan ** globaali (static) muuttuja 'paaviesti' komentoa vastaavaan arvoon. ** 'lue_komento' odottaa tämän muuttujan muuttumista muuhun arvoon kuin ** EI_KOMENTOA ja palauttaa sitten tämän arvon. ** ** Toteutus ei ole kovin elegantti, mutta mikäli itse näppäimiä käyttävät ** ohjelmat halutaan säilyttää samanlaisina vastaavien DOS-ohjelmien kanssa, ** on ratkaisun oltava jotain tämänkaltaista. ----------------------------------------------------------------------------*/ { int viesti; nappaimet = pnappaimet; laskurit = plaskurit; paaviesti = EI_KOMENTOA; paivita_valitut(); /* Jotta valitut näkyvät näytössä oikein */ while ( paaviesti == EI_KOMENTOA ) { if (!GetMessage(&msg,NULL,NULL,NULL)) return SYS_EXIT; TranslateMessage(&msg); /* Tulkitaan virtuaaliset näp. koodit */ DispatchMessage(&msg); /* Lähetetään viesti ikkunalle */ } *lisa = lisaviesti; viesti = paaviesti; paaviesti = EI_KOMENTOA; return viesti; } /****************************************************************************/ void piirra_laatikko( /* Piirretään laatikko */ laatikko_tyyppi *tila, /* Laatikon kkoordinaatit */ char *st, /* Jos laatikolla ei ole kokoa, ks.st*/ COLORREF color /* Laatikon taustan väri. */ ) /* ** Laatikkotyypissä on kenttä 'muutettu'. Mikäli tämä kenttä on tosi, on ** laatikon koordinaatit laitekoordenaateissa. Muuten laatikon koordin. ** ovat X-kirjaimen kokoina ilmoitettu. Aluksi tehdään koon muutos ** laitekoordinaatteihin. Jos laatikon kokoa ei ole annettu, laitetaan ** laatikon korkeudeksi parametrina tulevan tekstin korkeus ja leveydeksi ** parametrina tulevan teksin leveys. Leveyttä ei kuitenkaan laiteta ** M-kirjaimen leveyttä pienemmäksi. ** Jos laatikon koko-koordinaateista jompi kumpi on <0, ei laatikkoa ** piirretä näkyviin. ** ** Laatikkoon piirretään 2x raami ja pyöreät kulmat. ----------------------------------------------------------------------------*/ { HDC hDC; DWORD dw; RECT nelio; HBRUSH hbrOld,hbr; int x_lev,y_kork; if ( ( hDC = GetDC(hWnd) ) == NULL ) return; x_lev = tila->koko.x; y_kork = tila->koko.y; if ( !tila->muutettu ) { /* Muutetaan tilan tiedot laitekoordinaatteihin */ dw = GetTextExtent(hDC,st,lstrlen(st)); if ( x_lev == 0 ) { x_lev = max((int)LOWORD(dw),MIN_LEVEYS); tila->koko.x = x_lev; } else tila->koko.x = ( x_lev *= KERROIN_X ); if ( y_kork == 0 ) { y_kork = HIWORD(dw); tila->koko.y = y_kork; } else tila->koko.y = ( y_kork *= KERROIN_Y ); tila->vasen_yla.x = skaalaa_x(tila->vasen_yla.x); tila->vasen_yla.y = skaalaa_y(tila->vasen_yla.y); tila->muutettu = 1; } if ( ( x_lev < 0 ) || ( y_kork < 0 ) ) return; /*------------------------------------------------------------------------*/ /* Maalataan laatikon sisus taustavärillä: */ nelio.left = tila->vasen_yla.x; nelio.top = tila->vasen_yla.y; nelio.right = tila->vasen_yla.x + x_lev; nelio.bottom = tila->vasen_yla.y + y_kork; hbr = CreateSolidBrush(color); hbrOld = SelectObject(hDC, hbr); #if 1 RoundRect(hDC,RECT_TO_4(nelio,ULKO_LISA),ULKO_SADE,ULKO_SADE); RoundRect(hDC,RECT_TO_4(nelio,SISA_LISA),SISA_SADE,SISA_SADE); #else Rectangle(hDC,RECT_TO_4(nelio,ULKO_LISA)); Rectangle(hDC,RECT_TO_4(nelio,SISA_LISA)); #endif SelectObject(hDC,hbrOld); DeleteObject(hbr); ReleaseDC(hWnd,hDC); } /****************************************************************************/ void tulosta_jono_laatikkoon( /* Tulostetaan jono laatikkoon. */ laatikko_tyyppi *tila, /* Laatikko johon tulostetaan */ char *st, /* Tulostettava merkkijono */ COLORREF tcolor, /* Tekstin väri */ COLORREF bcolor, /* Taustan väri */ WORD textalign /* Tekstin keskitys */ ) /* ** Tulostetaan jono laatikkoon. Jono keskitetään aina korkeussuunnassa, ** mutta leveyssuunnassa keskitykseen voidaan vaikuttaa textalign-param. ** Tunnetut kesitykset: ** TA_CENTER - keskitys ** TA_RIGHT - oikeaan reunaan ** muut - vasempaan reunaan ** ** Mikäli jono ei mahdu laatikkoon, menee se sen reunojen yli! ----------------------------------------------------------------------------*/ { HDC hDC; int x,y; x = tila->vasen_yla.x; if ( textalign == TA_CENTER ) x += tila->koko.x/2; if ( textalign == TA_RIGHT ) x += tila->koko.x; y = tila->vasen_yla.y + (tila->koko.y - KERROIN_Y)/2; if ( ( hDC = GetDC(hWnd) ) == NULL ) return; SetTextColor(hDC,tcolor); SetBkColor(hDC,bcolor); SetTextAlign(hDC, textalign); TextOut(hDC,x,y,st,lstrlen(st)); ReleaseDC(hWnd,hDC); } /****************************************************************************/ void nayta_laskuri(laskuri_tyyppi *laskuri) { char s[200]; sprintf(s,laskuri->format,laskuri->arvo); tulosta_jono_laatikkoon(&laskuri->tila,s,BLACK,CYAN,TA_RIGHT); } /****************************************************************************/ void piirra_nappula(nappain_tyyppi *nappula) { if ( paaviesti == PIIRRA ) return; piirra_laatikko(&nappula->nappain,nappula->teksti,YELLOW); tulosta_jono_laatikkoon(&nappula->nappain,nappula->teksti,BLACK,YELLOW,TA_CENTER); } /****************************************************************************/ void piirra_laskuri(laskuri_tyyppi *laskuri) { if ( paaviesti == PIIRRA ) return; piirra_laatikko(&laskuri->tila,"X",CYAN); nayta_laskuri(laskuri); } /****************************************************************************/ void nollaa_laskurit(laskuri_tyyppi *laskurit) { int i; for (i=0; laskurit[i].tunnus; i++) { laskurit[i].arvo=0; piirra_laskuri(&laskurit[i]); } } /****************************************************************************/ void lisaa_laskuria(laskuri_tyyppi *laskurit,int tunnus) /* Lisätään valitun laskurin arvoa yhdellä. */ { int i; for (i=0; laskurit[i].tunnus; i++) { /* Ets. laskuri */ if ( laskurit[i].tunnus == tunnus ) { laskurit[i].arvo++; nayta_laskuri(&laskurit[i]); return; } } } /****************************************************************************/ void alusta_nappulat(nappain_tyyppi *pnappulat) { nappaimet = pnappulat; } /****************************************************************************/ void init_globals(void) /* Alustetaan globaalit muuttujat: */ { HDC hDC; DWORD dw; if ( ( hDC = GetDC(hWnd) ) == NULL ) return; dw = GetTextExtent(hDC,"X",1); KERROIN_X = LOWORD(dw); KERROIN_Y = HIWORD(dw); dw = GetTextExtent(hDC,"M",1); MIN_LEVEYS = LOWORD(dw); ReleaseDC(hWnd,hDC); } /****************************************************************************/ void tyhjenna_ruutu(void) { /* UpdateWindow(hWnd); */ } /****************************************************************************/ LONG FAR PASCAL /* Palautetaan miten viesti käs. */ MainWndProc( /* Usein WIndowsin oletuskäsit. arvo */ HWND hWnd, /* Ikkunan kahva, jolle viesti tulee */ unsigned message, /* Viestin arvo. */ WPARAM wParam, /* Viestin lisäosa. */ LPARAM lParam /* Viestin lisäosa. */ ) /* ** Käsitellään Windowsilta tulevat viestit. Mikäli viesti aiheuttaa ** jonkin varsinaisen ohjelman komennon, laitetaan globaaliin muuttujaan ** 'paaviesti' tämän komennon arvo. Tällöin aliohjelmassa 'lue_komento' ** loppuu viestisilmukan käsittely ja komennon arvo palautuu varsinaiselle ** ohjelmalle. ----------------------------------------------------------------------------*/ { switch (message) { case WM_CHAR: /* Painettu kirjainnäppäintä: */ tutki_kirjaimet(nappaimet,wParam); break; case WM_LBUTTONDOWN: /* Hiiren vasen nappi alas: */ tutki_paikka(nappaimet,laskurit,lParam,wParam); tutki_hiiri(nappaimet,laskurit,lParam,wParam); break; case WM_LBUTTONUP: /* Hiiren vasen nappi ylös: */ tutki_paikka(nappaimet,laskurit,lParam,wParam); if ( !fMuutos ) break; lopeta_muutos(lParam); break; case WM_MOUSEMOVE : /* Hiirtä siirretty: */ tutki_paikka(nappaimet,laskurit,lParam,wParam); if ( !fMuutos ) break; return muuta(lParam); case WM_PAINT: /* Viesti: Piirrä ikkuna uudelleen */ fMuutos = 0; paaviesti = PIIRRA; break; case WM_CREATE: hCsize = LoadCursor(NULL, IDC_SIZENWSE); hCmove = LoadCursor(NULL, IDC_UPARROW); hCpress = LoadCursor(NULL, IDC_CROSS); hCarrow = LoadCursor(NULL, IDC_ARROW); break; case WM_DESTROY: /* Viesti: ikkuna hävitetään */ PostQuitMessage(0); return NULL; default: /* Antaa Windowsin käsitellä muut */ break; } return (DefWindowProc(hWnd, message, wParam, lParam)); } /****************************************************************************/ int PASCAL /* NULL-jos ohjelmaa ei saada käynt. */ WinMain( /* Muuten ohjelman onnist. kuv. arvo */ HINSTANCE hInstance, /* Esiintymän kahva */ HINSTANCE hPrevInstance, /* Edellisen esiintymän kahva. */ LPSTR lpCmdLine, /* Kutsun komentorivi. */ int nCmdShow /* Miten ikkuna näytetään? */ ) /* ** Tämä on Windows-pääohjelma, joka alustaa ikkunaluokan ja ikkunan. ** Alustamisen jälkeen pitäisi pyörittää viestisilmukkaa, mutta koska ** aliohjelmakirjsto on tehty DOS-yhteensopivaksi, on viestisilmukan ** pyörittäminen jätetty aliohjelman 'lue_komento'-huoleksi. ** Käyttäjän pääohjelman, jonka nimen täytyy aina olla 'laskin_main', ** pitää pitää huoli siitä, että aliohjelmaa 'lue_komento' kutsutaan ** riittävän usein, jotta muutkin Windows-ohjelmat saavat vuoronsa. ** ----------------------------------------------------------------------------*/ { #pragma argsused WNDCLASS wc; /* Ikkunaluokka */ if (!hPrevInstance) { /* Onko muita esiintymiä käynnisssä? */ wc.style = NULL; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = MainWClass; if (!RegisterClass(&wc)) return (FALSE); } hWnd = CreateWindow(MainWClass,"Windows Laskuri 0.2",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,hInstance,NULL); if (!hWnd) return (FALSE); ShowWindow(hWnd, nCmdShow); /* Näytetään ikkuna */ init_globals(); laskin_main(); return (msg.wParam); /* Palautetaan PostQuitMessage-funktion arvo */ }