using System; using Gtk; using Gon; namespace Gon { /// Publiczna klasa GtkGame. /// /// Interfejs Input Output oparty o biblotekę gtk-sharp. public class GtkGame: Game { /// Matryca rysująca planszę. /// /// Glównym zadaniem tej klasy jest łapanie zdarzeń (events) /// myszki i rysowanie planszy (goban). class GobanBox : Gtk.DrawingArea { public game: GtkGame; /// obraz białego kamienia. white: Gdk.Pixbuf; /// obraz czarnego kamienia. black: Gdk.Pixbuf; /// obraz białego właśnie postawionego kamienia. swhite: Gdk.Pixbuf; /// obraz czarnego właśnie postawionego kamienia. sblack: Gdk.Pixbuf; /// obraz tła matrycy. ibg: Gdk.Pixbuf; /// obraz podkładu planszy (wyświetlany nad tłem). //igoban: Gdk.Pixbuf; gc: Gdk.GC; hor: Gdk.Pixbuf; ver: Gdk.Pixbuf; startx: int; starty: int; bgsize: int; stonesize: int; goban_startx : int; goban_starty: int; /// po naciśnięciu przycisku myszy move zostaje /// ustwiony na odpowiednie współrzędne. public mutable move: int*int*Color; /// przy zdarzeniu move_over, check zostaje /// ustwiony na odpowiednie współrzędne. public mutable check: int*int*Color; /// Konstruktor klasy GobanBox. /// /// Funkcja bierze objekt typu gra i ścieżke do katalogu /// z grafiką. Katalog z grafiką musi zwierać wszystkie wyszczególnione /// plik dla grafiki: white.png , black.png , swhite.png , sblack.png , /// bg.png , goban.png , horizontal.png , vertical.png. public this(game: GtkGame, path = "gfx/") { base(); this.game = game; white = Gdk.Pixbuf(path + "white.png"); black = Gdk.Pixbuf(path + "black.png"); swhite = Gdk.Pixbuf(path + "swhite.png"); sblack = Gdk.Pixbuf(path + "sblack.png"); ibg = Gdk.Pixbuf(path + "bg2.jpg"); //igoban = Gdk.Pixbuf(path + "bg2.jpg"); ver = Gdk.Pixbuf(path + "horizontal.png"); hor = Gdk.Pixbuf(path + "vertical.png"); gc = null; ///Gdk.GC(area.Pixmap); startx = 15; starty = 15; bgsize = 300; stonesize = 30; move = (-1,-1, Color.Empty); check = (-1, -1, Color.Empty); def gsize = game.goban.size; goban_startx = startx + (2*bgsize - stonesize*(gsize-1)) / 2; goban_starty = starty + (2*bgsize - stonesize*(gsize-1)) / 2; ExposeEvent += fun (_) { Draw (game.goban.State()); } Events |= Gdk.EventMask.PointerMotionMask; MotionNotifyEvent += fun (_, args:MotionNotifyEventArgs) { def cx = ((args.Event.X :> int) - goban_startx + stonesize/2)/(stonesize); def cy = ((args.Event.Y :> int) - goban_starty + stonesize/2)/(stonesize); check = (cx, cy, game.current); } Events |= Gdk.EventMask.ButtonPressMask; ButtonPressEvent += fun (_, args:ButtonPressEventArgs) { def cx = ((args.Event.X :> int) - goban_startx + stonesize/2)/(stonesize); def cy = ((args.Event.Y :> int) - goban_starty + stonesize/2)/(stonesize); move = (cx, cy, game.current); } } /// Narysuj goban. /// /// Funkcja rysuje goban, dostaje jako parametr tablicę, /// która powinna być stworzona przez funkcję goban->State(); public Draw(ret: array [2, Color]):void { mutable y = starty; mutable x = startx; def w = bgsize; def h = bgsize; def of = stonesize; def gsize = game.goban.size; mutable img = swhite; def DrawBg() { GdkWindow.DrawPixbuf(gc, ibg, 0,0, x, y, w, h, 0, 0, 0); x += w; GdkWindow.DrawPixbuf(gc, ibg, 0,0, x, y, w, h, 0, 0, 0); y += h; x = startx; GdkWindow.DrawPixbuf(gc, ibg, 0,0, x, y, w, h, 0, 0, 0); x += w; GdkWindow.DrawPixbuf(gc, ibg, 0,0, x, y, w, h, 0, 0, 0); } def DrawLines() { def len = 0; for (mutable i = 0; i < gsize; i++) { if (i == 0 || i == gsize-1) { GdkWindow.DrawPixbuf (gc, ver, 0, 0, goban_startx, goban_starty + i * of, of * (gsize-1), 2, 0, 0, 0); GdkWindow.DrawPixbuf(gc, hor, 0,0, goban_startx + i*of, goban_startx, 2, of*(gsize-1), 0, 0, 0); } else { GdkWindow.DrawPixbuf (gc, ver, 0, 0, goban_startx-len, goban_starty + i * of, of * (gsize-1) + len*2, 1, 0, 0, 0); GdkWindow.DrawPixbuf(gc, hor, 0,0, goban_startx + i*of, goban_startx-len, 1, of*(gsize-1) + len*2, 0, 0, 0); } } } def DrawLastStone (m: (int*int*Gon.Color)) { x = m[0]; y = m[1]; img = swhite; when (m[2] == Color.Black) img = sblack; when (game.goban.Exists(x, y) || (m.Equals(move) && game.goban.NotEmpty(x,y))) GdkWindow.DrawPixbuf(gc, img, 0,0, goban_startx + x*of + stonesize/2 - of, goban_starty + y*of + stonesize/2 - of, stonesize, stonesize, 0, 0, 0); } def DrawStones () { for (y = 0; y < gsize; y++) { for (x = 0; x < gsize; x++) { when (ret[x,y] != Color.Empty) { if (ret[x,y] == Color.Black) img = black; else img = white; GdkWindow.DrawPixbuf(gc, img, 0,0, goban_startx + x*of + stonesize/2 - of, goban_starty + y*of + stonesize/2 - of, stonesize, stonesize, 0, 0, 0); } } } } DrawBg(); DrawLines(); DrawStones(); DrawLastStone(move); // DrawLastStone(check); Show(); } } class Panel : VBox { pas: Button; quit: Button; gobanbox : GobanBox; public this(g: GobanBox) { base(false, 0); gobanbox = g; BorderWidth = 2; pas = Button("Pas"); quit = Button("Bye"); PackStart(pas, false, false, 3); PackStart(quit, false, true, 2); pas.Clicked += fun (_) { System.Console.WriteLine ("Pas"); gobanbox.move = (-2,-2, gobanbox.game.current); } quit.Clicked += fun (_) { System.Console.WriteLine ("See ya"); Application.Quit (); } pas.Show(); quit.Show(); Show(); } } class Displayer: Window { box : HBox; public gobanbox: GobanBox; panel : Panel; game: GtkGame; public this(game: GtkGame, bg: string) { base ("gon - nemerle go."); this.game = game; SetSizeRequest (640,640); box = HBox(false, 0); gobanbox = GobanBox(game, bg); panel = Panel(gobanbox); box.PackStart (gobanbox, true, true, 0u); box.PackStart (panel, false, false, 0u); gobanbox.Show(); panel.Show(); Show(); Add(box); _ = Timeout.Add (100, game.Loop); } protected override OnShown () : void { base.OnShown(); } } displayer: Displayer; mutable lm: int*int*Color; showlast : bool; /// Główna pętla dla interfejsu gtk. /// /// Funkcja jest wywoływana co 100 ms, /// pobiera ruchy od graczy i rysuje planszę - jeśli ruch został wykonany. public Loop(): bool { mutable m = (0,0,Color.Empty); match (current) { | Black => m = black.Get(); | White => m = white.Get(); | _ => (); } when (m.Equals((0,0,Color.Empty))) m = displayer.gobanbox.move; when (m.Equals((-2,-2,current))) { if (current == Color.Black) { white.SetMove(m[0], m[1]); current = Color.White; } else { black.SetMove(m[0], m[1]); current = Color.Black; } } if (m.Equals((0,0,Color.Empty)) == false && goban.Avaible(m)) { goban.Put(m); displayer.gobanbox.Draw(goban.State()); displayer.gobanbox.move = m; if (current == Color.Black) { white.SetMove(m[0], m[1]); current = Color.White; } else { black.SetMove(m[0], m[1]); current = Color.Black; } } else { m = displayer.gobanbox.check; when (showlast && m.Equals(lm) == false && goban.Avaible(m)) { displayer.gobanbox.Draw(goban.State()); lm = m; } } true; } /// Konstruktor GtkGame. /// /// Funkcja bierze rozmiar, dwa objekty typu Player i ścieżkę do katalogu /// z grafiką dla GobanBox. public this (size: int, b: Player, w:Player, bg:string) { base(Goban(size), b, w); Application.Init(); displayer = Displayer(this, bg); displayer.DeleteEvent += fun (_) { Application.Quit () }; displayer.ShowAll (); Application.Run(); lm = (-1, -1, Color.Empty); showlast = false; } } public class GtkPlayer: Player { public this(n:string, clr: Color) { base(n, clr) } } }