h3. Udalosti Táto lekcia bude dosť rozsiahla, lebo sa tu pozrieme na významný koncept z knižnice SDL: _udalosti_. Najprv bude dlhý všeobecný teoretický pokec, v ktorom občas zmienim nejaké konkrétne funkcie. Udalosti predstavujú základnú vstupnú metódu, cez ktorú operačný systém oznamuje programu všetko možné, čo sa stalo. Udalosti môžu byť napríklad toto: * "Užívateľ klikol na krížik, skonči sa." (typ QuitEvent) * "Užívateľ pohol myšou a teraz je na pozícii [21, 178]." (typ MouseMoveEvent) * "Užívateľ natiahol okno na veľkosť 1000 krát 100." (typ ResizeEvent) * "Prešlo 15 sekúnd, tak ti to oznamujem, presne ako si chcel." (typ TimerEvent) Udalosti sa používajú na všetok vstup od užívateľa (ale nie len od neho, viď ten posledný príklad), čo program dostáva. Sú rôznych typov, a každý má nejaké iné "hodnoty": pri pohnutí myšou nás zaujíma, kam sa pohla, a pri stlačení klávesu, ktorý kláves to bol. Preto má každý typ udalosti svoju vlastnú triedu (a každá trieda svoje vlastné atribúty). Všetky dedia zo základnej udalosťovej triedy Event. Keď sa treba zachovať podľa toho, akého typu nejaká udalosť je, stačí zistiť, ktorej je triedy. Programy majú na práci aj iné veci, ako spracovávať udalosti. Tie, ktoré ešte neboli spracované, sa zaradzujú do tzv. _fronty udalostí_. Keď má program práve chvíľu času, pozrie sa, aké udalosti v nej medzičasom pribudli, a zareaguje na nich. (Preskočím na chvíľu trochu z doteraz teoretického pokecu do praxe a zmienim, že na to sa používa funkcia EventQueue.poll. Pozrie sa do fronty udalostí. Ak tam nič nie je, vráti _nil_. Ak tam niečo je, vyhodí z nej tú najstaršiu nespracovanú udalosť a vráti ju.) p(advanced). EventQueue.wait funguje podobne ako EventQueue.poll, ale ak nečaká žiadna nespracovaná udalosť, tak čaká, až kým nejaká nepríde. Treba si uvedomiť, že cez udalosti sa spracováva _všetok_ vstup programu. To zahŕňa aj stlačenie krížika. Od slušných programov sa čaká, že po stlačení krížika (a prípadnej potvrdzujúcej hláške) skončia, takže by bolo dobré, keby ste to tak mali aj vy a v cykloch testovali, či ste náhodou nejaký ten QuitEvent nedostali. h3. Myš Postupne sa v lekciách budeme učiť o rôznych udalostiach. Najprv sa v tejto lekcii naučíme pracovať s myšou. Myši sa týkajú tri typy udalostí - MouseMotionEvent, MouseButtonDownEvent a MouseButtonUpEvent. Všetky majú atribút pos určujúci pozíciu myši. Tlačítkové udalosti majú atribút button, v ktorom je číslo stlačeného tlačidla. (0 ľavé, 1 stredné, 2 pravé.) MouseMotionEvent (ktorý príde vždy, keď myš prejde z bodu na nejaký iný bod) má tiež button, ale v tomto prípade je to trojprvkové pole hodnôt true a false, podľa toho, ktoré tlačidlo je stlačené a ktoré nie. (A ešte má rel, ktorý určuje, o koľko sa myš pohla. Je v tvare [dx, dy].) S tým, čo už vieme, sa dá urobiť primitívny kresliaci program: kreslim = false loop do while (event = EventQueue.poll) case event when QuitEvent exit when KeyDownEvent exit if event.key == K_ESCAPE when MouseButtonDownEvent kreslim = true if event.button == 0 when MouseButtonUpEvent kreslim = false if event.button == 0 when MouseMotionEvent if kreslim $screen.plot(event.pos, [255,255,0]) $screen.flip end end end end case v Ruby je veľmi šikovná vec, ktorá zisťuje všetko možné: when "reťazec" zisťuje, či sa tá vec rovná reťazcu, when /regulárny vyraz/ zisťuje, či na tú vec daný regulárny výraz platí, when MenoTriedy zisťuje, či ten objekt je danej triedy. Nám sa bude hodiť zvlášť tá posledná možnosť. Celý program funguje tak, že v premennej kreslim si pamätám, či je práve stlačené tlačidlo, a keď sa pohne myš a kreslim je true, tak na obrazovku nakreslím bodku. p(advanced). Program končí, keď sa stlači krížik alebo Escape. Ten Escape zistíme pomocou KeyDownEvent, ktorý má atribút key, ktorý uchováva kód stlačeného klávesu. Klávesnici sa budeme bližšie venovať v neskoršej lekcii. *Úloha č. 1:* Napíšte, pochopte, spustite. *Úloha č. 2:* Zvládneme to aj bez premennej kreslim. Zjednodušte program: skúste ju dať úplne preč a pri spracovávaní MouseMotionEventu jednoducho zisťovať, či je ľavé tlačidlo stlačené, pomocou event.button[0]. *Úloha č. 3:* Upravte program tak, aby keď je stlačené ľavé tlačidlo kreslil žlté bodky a keď je stlačené pravé tlačidlo kreslil červené bodky. *Úloha č. 4:* Upravte program tak, aby pri stlačení ľavého tlačidla kreslil súvislú čiaru. Urobte to tak, aby sa čiara prerušila, keď ľavé tlačidlo pustíte. *Úloha č. 5:* Upravte program tak, aby tam, kde kliknete, nakreslil slniečko (sprite sln1.tga). TODO: doplniť úlohy z druhej myšovej lekcie. Možno myšové funkcie presunúť z dodatkov sem. h3. Dodatky h4. Ďalšie udalosti Existuje síce lekcia o klávesnici alebo lekcia o timeroch, ale niektoré udalosti sa inde asi nevojdú, tak ich spomeniem radšej hneď teraz. ResizeEvent nastane, keď sa zmení veľkosť okna (na to musí byť vytvorené s nastavením RESIZABLE.) Nová veľkosť okna je v ResizeEvent#size. ActiveEvent nastane pri rôznych zmenách aktivity okna, čiže keď začne alebo prestane byť aktívne, keď nad neho príde alebo odíde myš, keď sa dá na lištu (_ikonifikuje_), apod. Dokumentácia je na http://www.libsdl.org/cgi/docwiki.cgi/SDL_5fActiveEvent . QuitEvent nastane pri kliknutí na X (alebo vo Windowse pri stlačení Alt-F4 apod.) Joystick má tiež nejaké udalosti, ale tie (a celkovo prácu s joystickom) v týchto lekciách preskočíme. h4. Priamy prístup k myši Keď chcete zistiť nejaký údaj o myši, ale práve nepracujete s udalosťami, existujú náhradné funkcie. (Odporúča sa robiť to cez udalosti, je to flexibilnejšie.) Mouse.focused? zistí, či je vôbec kurzor myši v okne aplikácie. Mouse.pos zistí momentálnu pozíciu myši. Mouse.pressed? vráti pole podobné ako to, čo vráti MouseMotionEvent#button Niektoré funkcie nezisťujú, ale nastavujú, a preto nemajú pri udalostiach svoje obdoby. Mouse.pos= nastaví pozíciu myši. Mouse.visible= nastaví, či myš vidno.