/* A demo GTK application in Pawn, using gtk-server and the "process control" * module for Pawn. This example also illustrates the use of (communicating) * finite state machines. */ #include #include #pragma tabsize 0 enum Btn{ Btn0, Btn1, Btn2, Btn3, Btn4, Btn5, Btn6, Btn7, Btn8, Btn9, BtnDot, BtnC, BtnCE, BtnPlus, BtnMin, BtnMul, BtnDiv, BtnEqual, BtnNone, } static entry; /* GTK "entry" widget */ static numberstring[40 char]; static accum; static Btn:pending_op; adddigit(digit, bool:reset = false){ new command[80 char], charstr[2 char]; charstr{0} = (0 <= digit <= 9) ? digit + '0' : digit; if(reset)numberstring[0] = EOS; strcat(numberstring, charstr); strformat(command, _, true, "gtk_entry_set_text %d %s", entry, numberstring); GTK(command); } displayresult(value){ new command[80 char]; valstr numberstring, value, true; strformat(command, _, true, "gtk_entry_set_text %d %s", entry, numberstring); GTK(command); } resetentry(digit) { adddigit('-', .reset = true); adddigit(digit); } resetentry(digit) <>{ adddigit(digit, .reset = true); } event_0() { resetentry(0); } event_0() { adddigit(0); } event_1_9(Btn:idx) { resetentry(_:(idx - Btn0)); state number:int; } event_1_9(Btn:idx) { adddigit(_:(idx - Btn0)); } event_dot() { resetentry(0); adddigit('.'); state number:frac; } event_dot() { adddigit('.'); state number:frac; } event_dot() { /*Do Something*/ } event_minus() { state number:negated; resetentry(0); } event_minus() <>{ event_oper(BtnMin); /* forward to the "calc" automaton */ } /* helper function for the calculator automaton */ performoperation(){ /* get the other operand, perform the operation */ new val = strval(numberstring); switch (pending_op){ case BtnPlus:accum += val case BtnMin:accum -= val case BtnMul:accum *= val case BtnDiv:accum = (val == 0) ? 0 : accum / val } displayresult(accum); } event_oper(Btn:idx) { /* save operand and operator */ accum = strval(numberstring); pending_op = idx; state number:zero; state calc:pending; } event_oper(Btn:idx) { performoperation(); /* do the pending operation */ pending_op = idx /* save the operator for the next operation */ state number:zero } event_equal() { /* ignore */ } event_equal() { performoperation(); /* do the pending operation */ state calc:idle; /* reset the calculator */ state number:zero; } event_C(){ state calc:idle; state number:zero; resetentry(0); } event_CE(){ state number:zero; resetentry(0); } main(){ if (!procexec("gtk-server -stdin") && !procexec("gtk-server.exe -stdin"))fatal("unable to launch gtk-server"); /* make a window */ GTK("gtk_init NULL NULL"); new win = GTK("gtk_window_new 0"); GTK("gtk_window_set_title %d \"GUI Test in Pawn\"", win); GTK("gtk_widget_set_usize %d 200 200", win); /* add a table (align the other controls) */ new table = GTK("gtk_table_new 50 50 1"); GTK("gtk_container_add %d %d", win, table); /* the number entry */ entry = GTK("gtk_entry_new"); GTK("gtk_table_attach_defaults %d %d 1 49 1 9", table, entry); /* the key pad */ new buttons[Btn]; buttons[BtnDot] = GTK("gtk_button_new_with_label ."); GTK("gtk_table_attach_defaults %d %d 21 29 41 49", table, buttons[BtnDot]); buttons[Btn0] = GTK("gtk_button_new_with_label 0"); GTK("gtk_table_attach_defaults %d %d 1 19 41 49", table, buttons[Btn0]); buttons[Btn1] = GTK("gtk_button_new_with_label 1"); GTK("gtk_table_attach_defaults %d %d 1 9 31 39", table, buttons[Btn1]); buttons[Btn2] = GTK("gtk_button_new_with_label 2"); GTK("gtk_table_attach_defaults %d %d 11 19 31 39", table, buttons[Btn2]); buttons[Btn3] = GTK("gtk_button_new_with_label 3"); GTK("gtk_table_attach_defaults %d %d 21 29 31 39", table, buttons[Btn3]); buttons[Btn4] = GTK("gtk_button_new_with_label 4"); GTK("gtk_table_attach_defaults %d %d 1 9 21 29", table, buttons[Btn4]); buttons[Btn5] = GTK("gtk_button_new_with_label 5"); GTK("gtk_table_attach_defaults %d %d 11 19 21 29", table, buttons[Btn5]); buttons[Btn6] = GTK("gtk_button_new_with_label 6"); GTK("gtk_table_attach_defaults %d %d 21 29 21 29", table, buttons[Btn6]); buttons[Btn7] = GTK("gtk_button_new_with_label 7"); GTK("gtk_table_attach_defaults %d %d 1 9 11 19", table, buttons[Btn7]); buttons[Btn8] = GTK("gtk_button_new_with_label 8"); GTK("gtk_table_attach_defaults %d %d 11 19 11 19", table, buttons[Btn8]); buttons[Btn9] = GTK("gtk_button_new_with_label 9"); GTK("gtk_table_attach_defaults %d %d 21 29 11 19", table, buttons[Btn9]); buttons[BtnC] = GTK("gtk_button_new_with_label C"); GTK("gtk_table_attach_defaults %d %d 31 39 11 19", table, buttons[BtnC]); buttons[BtnCE] = GTK("gtk_button_new_with_label CE"); GTK("gtk_table_attach_defaults %d %d 41 49 11 19", table, buttons[BtnCE]); buttons[BtnPlus] = GTK("gtk_button_new_with_label +"); GTK("gtk_table_attach_defaults %d %d 31 39 21 29", table, buttons[BtnPlus]); buttons[BtnMin] = GTK("gtk_button_new_with_label -"); GTK("gtk_table_attach_defaults %d %d 41 49 21 29", table, buttons[BtnMin]); buttons[BtnMul] = GTK("gtk_button_new_with_label x"); GTK("gtk_table_attach_defaults %d %d 31 39 31 39", table, buttons[BtnMul]); buttons[BtnDiv] = GTK("gtk_button_new_with_label /"); GTK("gtk_table_attach_defaults %d %d 41 49 31 39", table, buttons[BtnDiv]); buttons[BtnEqual] = GTK("gtk_button_new_with_label ="); GTK("gtk_table_attach_defaults %d %d 31 49 41 49", table, buttons[BtnEqual]); /* initialize automata */ state number:zero; state calc:idle; /* wait for events, and dispatch them */ GTK("gtk_widget_show_all %d", win); resetentry(0); new event; new Btn:idx; do{ event = GTK("gtk_server_callback wait"); /* find the button matching the event, generate the event */ for (idx = Btn0; idx < BtnNone && buttons[idx] != event; idx++) {} switch (idx){ case Btn0:event_0 case Btn1 .. Btn9:event_1_9 idx case BtnDot:event_dot case BtnMin:event_minus case BtnPlus, BtnMul, BtnDiv:event_oper idx case BtnEqual:event_equal case BtnC:event_C case BtnCE:event_CE } } while (event != win); /* direct call, because we must not wait for a reply on this command */ procwrite("gtk_server_exit", true); } GTK(const format[], ...){ new command[256 char]; switch (numargs()){ case 1:strpack(command, format); case 2:strformat(command, _, true, format, getarg(1)); case 3:strformat(command, _, true, format, getarg(1), getarg(2)); case 4:strformat(command, _, true, format, getarg(1), getarg(2), getarg(3)); case 5:strformat(command, _, true, format, getarg(1), getarg(2), getarg(3), getarg(4)); } procwrite(command, true); new reply[30]; procread(reply, .striplf=true); if (strcmp(reply, "ok") == 0)return true; return strval(reply); } fatal(const message[]){ printf("FATAL: %s\n", message); exit; }