Matt23488

Simple Gtk Calculator

May 17th, 2011
487
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.16 KB | None | 0 0
  1. #include <windows.h>
  2. #include <gtk/gtk.h>
  3.  
  4. int main( int argc, char **argv );
  5.  
  6. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  7. {
  8.   return main (__argc, __argv);
  9. }
  10.  
  11. /***********************************
  12.          GLOBAL VARIABLES
  13. ***********************************/
  14.  
  15. double accum = 0.0;     //Holds the current number
  16. char op = NULL;         //Holds the most recent operator clicked
  17. bool started = false;   //Minor influence, makes the UI look better
  18. bool op_clicked = true; //Lets the num_button_clicked start a new number input
  19.  
  20. /***********************************
  21.        FUNCTION DECLARATIONS
  22. ***********************************/
  23.  
  24. double stringToDouble(char *string);            //Converts a char* to a double
  25. gboolean containsDecimal(char *string);         //Returns TRUE if the char* passed contains a '.', and FALSE otherwise
  26. char* substr(char* string, int begin, int end); //Returns a substring of a char*
  27. char* removeZeros(char* string);                //Removes unneeded zeros after the decimal
  28. double power(double a, int b);                  //Raises a to the power of b
  29.  
  30. /***********************************
  31.            EVENT HANDLERS
  32. ***********************************/
  33.  
  34. void
  35. num_button_clicked (GtkButton *button, gpointer user_data)
  36. {
  37.     GtkEntry *entry;
  38.     const char *button_label;
  39.     char *entry_text;
  40.  
  41.     entry = GTK_ENTRY (user_data);//convert back to a GtkEntry*
  42.     int button_value;
  43.  
  44.     button_label = gtk_button_get_label (button);
  45.     if(button_label[0] == '.' && (!containsDecimal((char*)gtk_entry_get_text (entry)) || op_clicked))//Only add a decimal if there are no decimals already in the string
  46.     {
  47.         entry_text = g_strdup_printf ("%s%c", op_clicked ? "0" : gtk_entry_get_text (entry), '.');
  48.     }
  49.     else if(button_label[0] == '.')//Do nothing if there is already a decimal and the decimal button was clicked
  50.     {
  51.         return;
  52.     }
  53.     else//Concatonate the numbers to the string
  54.     {
  55.         button_value = button_label[0] - '0';
  56.         entry_text = g_strdup_printf ("%s%d", op_clicked ? "" : gtk_entry_get_text (entry), button_value);
  57.     }
  58.  
  59.     gtk_entry_set_text (entry, entry_text);
  60.     g_free (entry_text);//must free the memory that was used by g_strdup_printf
  61.     op_clicked = false;
  62. }
  63.  
  64. void
  65. buttonOp_clicked (GtkButton *button, gpointer user_data)
  66. {
  67.     GtkEntry *entry;
  68.     entry = GTK_ENTRY (user_data);
  69.  
  70.     if(!started)//Initialize accum if this is the first number entry
  71.     {
  72.         accum = stringToDouble((char*)gtk_entry_get_text (entry));
  73.     }
  74.     else//Do math otherwise
  75.     {
  76.         char* entry_text;
  77.         switch(op)
  78.         {
  79.             case '+':
  80.                 accum += stringToDouble((char*)gtk_entry_get_text (entry));
  81.                 break;
  82.             case '-':
  83.                 accum -= stringToDouble((char*)gtk_entry_get_text (entry));
  84.                 break;
  85.             case '*':
  86.                 accum *= stringToDouble((char*)gtk_entry_get_text (entry));
  87.                 break;
  88.             case '/':
  89.                 accum /= stringToDouble((char*)gtk_entry_get_text (entry));
  90.                 break;
  91.             case '^':
  92.                 accum = power(accum, (int)stringToDouble((char*)gtk_entry_get_text (entry)));
  93.         }
  94.         entry_text = g_strdup_printf ("%f", accum);
  95.         gtk_entry_set_text (entry, removeZeros(entry_text));//Update the text view
  96.         g_free(entry_text);
  97.     }
  98.     op = gtk_button_get_label (button)[0];//Update the operator
  99.     started = true;//User has started calculating
  100.     op_clicked = true;
  101. }
  102.  
  103. void
  104. buttonNeg_clicked (GtkButton *button, gpointer user_data)
  105. {
  106.     GtkEntry *entry;
  107.     entry = GTK_ENTRY (user_data);
  108.     char *entry_text;
  109.     entry_text = g_strdup (gtk_entry_get_text (entry));
  110.     if(entry_text[0] == '0' && entry_text[1] == '\0')
  111.     {
  112.         g_free (entry_text);
  113.         return;
  114.     }
  115.     if(entry_text[0] == '-')
  116.     {
  117.         gtk_entry_set_text (entry, removeZeros(substr(entry_text, 1, strlen(entry_text) - 1)));//Remove the '-'
  118.     }
  119.     else
  120.     {
  121.         g_free(entry_text);
  122.         entry_text = g_strdup_printf ("%c%s", '-', gtk_entry_get_text (entry));//Put a '-' at the beginning of the string
  123.         gtk_entry_set_text (entry, removeZeros(entry_text));
  124.     }
  125.     g_free(entry_text);//Free the memory
  126. }
  127.  
  128. void
  129. buttonFct_clicked (GtkButton *button, gpointer user_data)
  130. {
  131.     GtkEntry *entry;
  132.     entry = GTK_ENTRY (user_data);
  133.  
  134.     if(containsDecimal((char*)gtk_entry_get_text (entry)) || gtk_entry_get_text (entry)[0] == '-')//Cannot take the factorial of a non-whole number
  135.     {
  136.         char *entry_text;
  137.         entry_text = g_strdup_printf("CANNOT EVALUATE \"%s!\"", gtk_entry_get_text (entry));
  138.         gtk_entry_set_text (entry, entry_text);
  139.         g_free(entry_text);
  140.         accum = 0.0;
  141.         op = NULL;
  142.         started = false;
  143.         op_clicked = true;
  144.     }
  145.     else
  146.     {
  147.         __int64 total = 1;
  148.         __int64 prev_total = 1;
  149.         bool overflow = false;
  150.         for(int i = (int)stringToDouble((char*)gtk_entry_get_text (entry)); i > 0; i--)
  151.         {
  152.             total *= i;
  153.             if(total / i != prev_total)
  154.             {
  155.                 overflow = true;
  156.                 break;
  157.             }
  158.             prev_total = total;
  159.         }
  160.        
  161.         char *entry_text;
  162.         entry_text = g_strdup_printf ("%d", total);
  163.         if(overflow || entry_text[0] == '-')//Overflow error - This only works sometimes
  164.         {
  165.             gtk_entry_set_text (entry, "OVERFLOW");
  166.             accum = 0.0;
  167.             op = NULL;
  168.             started = false;
  169.         }
  170.         else
  171.         {
  172.             gtk_entry_set_text (entry, entry_text);
  173.         }
  174.         op_clicked = true;
  175.         g_free(entry_text);
  176.     }
  177. }
  178.  
  179. void
  180. buttonEqu_clicked (GtkButton *button, gpointer user_data)
  181. {
  182.     GtkEntry *entry;
  183.     entry = GTK_ENTRY (user_data);
  184.  
  185.     if(started)
  186.     {
  187.         char *entry_text;
  188.         if(!op_clicked)
  189.         {
  190.             switch(op)
  191.             {
  192.                 case '+':
  193.                     accum += stringToDouble((char*)gtk_entry_get_text (entry));
  194.                     break;
  195.                 case '-':
  196.                     accum -= stringToDouble((char*)gtk_entry_get_text (entry));
  197.                     break;
  198.                 case '*':
  199.                     accum *= stringToDouble((char*)gtk_entry_get_text (entry));
  200.                     break;
  201.                 case '/':
  202.                     accum /= stringToDouble((char*)gtk_entry_get_text (entry));
  203.                     break;
  204.                 case '^':
  205.                     accum = power(accum, (int)stringToDouble((char*)gtk_entry_get_text (entry)));
  206.             }
  207.         }
  208.         entry_text = g_strdup_printf ("%f", accum);
  209.         gtk_entry_set_text (entry, removeZeros(entry_text));
  210.         g_free(entry_text);
  211.         op_clicked = true;//Reset all the values to start a new calculator session
  212.         accum = 0.0;
  213.         op = NULL;
  214.         started = false;
  215.     }
  216. }
  217.  
  218. void
  219. buttonClr_clicked (GtkButton *button, gpointer user_data)
  220. {
  221.     GtkEntry *entry;
  222.     entry = GTK_ENTRY (user_data);
  223.    
  224.     gtk_entry_set_text (entry, "0");//Reset all the values to start a new calculator session
  225.     accum = 0.0;
  226.     op = NULL;
  227.     started = false;
  228.     op_clicked = true;
  229. }
  230.  
  231. /***********************************
  232.             ENTRY POINT
  233. ***********************************/
  234.  
  235. int main (int argc, char **argv)
  236. {
  237.     GtkWidget *window;
  238.     GtkWidget *vbox;
  239.     GtkWidget *hbox1;
  240.     GtkWidget *hbox2;
  241.     GtkWidget *hbox3;
  242.     GtkWidget *hbox4;
  243.     GtkWidget *hbox5;
  244.     GtkWidget *button0;
  245.     GtkWidget *button1;
  246.     GtkWidget *button2;
  247.     GtkWidget *button3;
  248.     GtkWidget *button4;
  249.     GtkWidget *button5;
  250.     GtkWidget *button6;
  251.     GtkWidget *button7;
  252.     GtkWidget *button8;
  253.     GtkWidget *button9;
  254.     GtkWidget *buttonAdd;
  255.     GtkWidget *buttonSub;
  256.     GtkWidget *buttonMul;
  257.     GtkWidget *buttonDiv;
  258.     GtkWidget *buttonEqu;
  259.     GtkWidget *buttonClr;
  260.     GtkWidget *buttonDec;
  261.     GtkWidget *buttonExp;
  262.     GtkWidget *buttonNeg;
  263.     GtkWidget *buttonFct;
  264.     GtkWidget *entry;
  265.  
  266.     //Call this before setting up widgets, etc
  267.     gtk_init (&argc, &argv);
  268.  
  269.     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  270.     gtk_window_set_title (GTK_WINDOW (window), "Calculator");
  271.     gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
  272.  
  273.     vbox = gtk_vbox_new (TRUE, 6);
  274.     hbox1 = gtk_hbox_new (TRUE, 6);
  275.     hbox2 = gtk_hbox_new (TRUE, 6);
  276.     hbox3 = gtk_hbox_new (TRUE, 6);
  277.     hbox4 = gtk_hbox_new (TRUE, 6);
  278.     hbox5 = gtk_hbox_new (TRUE, 6);
  279.  
  280.     button0 = gtk_button_new_with_label ("0");
  281.     button1 = gtk_button_new_with_label ("1");
  282.     button2 = gtk_button_new_with_label ("2");
  283.     button3 = gtk_button_new_with_label ("3");
  284.     button4 = gtk_button_new_with_label ("4");
  285.     button5 = gtk_button_new_with_label ("5");
  286.     button6 = gtk_button_new_with_label ("6");
  287.     button7 = gtk_button_new_with_label ("7");
  288.     button8 = gtk_button_new_with_label ("8");
  289.     button9 = gtk_button_new_with_label ("9");
  290.     buttonAdd = gtk_button_new_with_label ("+");
  291.     buttonSub = gtk_button_new_with_label ("-");
  292.     buttonMul = gtk_button_new_with_label ("*");
  293.     buttonDiv = gtk_button_new_with_label ("/");
  294.     buttonEqu = gtk_button_new_with_label ("=");
  295.     buttonClr = gtk_button_new_with_label ("C");
  296.     buttonDec = gtk_button_new_with_label (".");
  297.     buttonExp = gtk_button_new_with_label ("^");
  298.     buttonNeg = gtk_button_new_with_label ("~");
  299.     buttonFct = gtk_button_new_with_label ("!");
  300.  
  301.     entry = gtk_entry_new ();
  302.     gtk_entry_set_text (GTK_ENTRY (entry), "0");
  303.     gtk_entry_set_editable (GTK_ENTRY (entry), FALSE);
  304.  
  305.     g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
  306.  
  307.     g_signal_connect (G_OBJECT (button0), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  308.     g_signal_connect (G_OBJECT (button1), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  309.     g_signal_connect (G_OBJECT (button2), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  310.     g_signal_connect (G_OBJECT (button3), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  311.     g_signal_connect (G_OBJECT (button4), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  312.     g_signal_connect (G_OBJECT (button5), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  313.     g_signal_connect (G_OBJECT (button6), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  314.     g_signal_connect (G_OBJECT (button7), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  315.     g_signal_connect (G_OBJECT (button8), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  316.     g_signal_connect (G_OBJECT (button9), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  317.     g_signal_connect (G_OBJECT (buttonDec), "clicked", G_CALLBACK (num_button_clicked), (gpointer)entry);
  318.     g_signal_connect (G_OBJECT (buttonAdd), "clicked", G_CALLBACK (buttonOp_clicked), (gpointer)entry);
  319.     g_signal_connect (G_OBJECT (buttonSub), "clicked", G_CALLBACK (buttonOp_clicked), (gpointer)entry);
  320.     g_signal_connect (G_OBJECT (buttonMul), "clicked", G_CALLBACK (buttonOp_clicked), (gpointer)entry);
  321.     g_signal_connect (G_OBJECT (buttonDiv), "clicked", G_CALLBACK (buttonOp_clicked), (gpointer)entry);
  322.     g_signal_connect (G_OBJECT (buttonExp), "clicked", G_CALLBACK (buttonOp_clicked), (gpointer)entry);
  323.     g_signal_connect (G_OBJECT (buttonNeg), "clicked", G_CALLBACK (buttonNeg_clicked), (gpointer)entry);
  324.     g_signal_connect (G_OBJECT (buttonFct), "clicked", G_CALLBACK (buttonFct_clicked), (gpointer)entry);
  325.     g_signal_connect (G_OBJECT (buttonEqu), "clicked", G_CALLBACK (buttonEqu_clicked), (gpointer)entry);
  326.     g_signal_connect (G_OBJECT (buttonClr), "clicked", G_CALLBACK (buttonClr_clicked), (gpointer)entry);
  327.  
  328.     gtk_container_add (GTK_CONTAINER (window), vbox);
  329.  
  330.     gtk_box_pack_start (GTK_BOX (vbox), hbox1, FALSE, FALSE, 6);
  331.     gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 6);
  332.     gtk_box_pack_start (GTK_BOX (vbox), hbox3, FALSE, FALSE, 6);
  333.     gtk_box_pack_start (GTK_BOX (vbox), hbox4, FALSE, FALSE, 6);
  334.     gtk_box_pack_start (GTK_BOX (vbox), hbox5, FALSE, FALSE, 6);
  335.  
  336.     gtk_box_pack_start (GTK_BOX (hbox1), entry, TRUE, TRUE, 6);
  337.  
  338.     gtk_box_pack_start (GTK_BOX (hbox2), button7, TRUE, TRUE, 6);
  339.     gtk_box_pack_start (GTK_BOX (hbox2), button8, TRUE, TRUE, 6);
  340.     gtk_box_pack_start (GTK_BOX (hbox2), button9, TRUE, TRUE, 6);
  341.     gtk_box_pack_start (GTK_BOX (hbox2), buttonAdd, TRUE, TRUE, 6);
  342.     gtk_box_pack_start (GTK_BOX (hbox2), buttonNeg, TRUE, TRUE, 6);
  343.  
  344.     gtk_box_pack_start (GTK_BOX (hbox3), button4, TRUE, TRUE, 6);
  345.     gtk_box_pack_start (GTK_BOX (hbox3), button5, TRUE, TRUE, 6);
  346.     gtk_box_pack_start (GTK_BOX (hbox3), button6, TRUE, TRUE, 6);
  347.     gtk_box_pack_start (GTK_BOX (hbox3), buttonSub, TRUE, TRUE, 6);
  348.     gtk_box_pack_start (GTK_BOX (hbox3), buttonExp, TRUE, TRUE, 6);
  349.  
  350.     gtk_box_pack_start (GTK_BOX (hbox4), button1, TRUE, TRUE, 6);
  351.     gtk_box_pack_start (GTK_BOX (hbox4), button2, TRUE, TRUE, 6);
  352.     gtk_box_pack_start (GTK_BOX (hbox4), button3, TRUE, TRUE, 6);
  353.     gtk_box_pack_start (GTK_BOX (hbox4), buttonMul, TRUE, TRUE, 6);
  354.     gtk_box_pack_start (GTK_BOX (hbox4), buttonFct, TRUE, TRUE, 6);
  355.  
  356.     gtk_box_pack_start (GTK_BOX (hbox5), button0, TRUE, TRUE, 6);
  357.     gtk_box_pack_start (GTK_BOX (hbox5), buttonDec, TRUE, TRUE, 6);
  358.     gtk_box_pack_start (GTK_BOX (hbox5), buttonEqu, TRUE, TRUE, 6);
  359.     gtk_box_pack_start (GTK_BOX (hbox5), buttonDiv, TRUE, TRUE, 6);
  360.     gtk_box_pack_start (GTK_BOX (hbox5), buttonClr, TRUE, TRUE, 6);
  361.  
  362.     gtk_widget_show_all (window);
  363.  
  364.     //Call this AFTER setting up widgets etc
  365.     gtk_main ();
  366.  
  367.     return 0;
  368. }
  369.  
  370. /***********************************
  371.         FUNCTION DEFINITIONS
  372. ***********************************/
  373.  
  374. double stringToDouble(char *string)
  375. {
  376.     double d = 0.0, e = 0.0;
  377.     double sign = 1.0;
  378.     bool past_decimal = false;
  379.     int decimal_places = 0;
  380.     for (int i = 0; i < strlen(string); i++)
  381.     {
  382.         if(string[i] == '-')
  383.         {
  384.             sign = -1.0;
  385.             continue;
  386.         }
  387.         if(string[i] == '.' || past_decimal)
  388.         {
  389.             if(string[i] == '.')
  390.             {
  391.                 i++;
  392.                 past_decimal = true;
  393.             }
  394.             decimal_places++;
  395.             e *= 10.0;
  396.             e += (string[i] - '0');
  397.             continue;
  398.         }
  399.         d *= 10.0;
  400.         d += (string[i] - '0');
  401.     }
  402.     for(int i = 0; i < decimal_places; i++)
  403.     {
  404.         e /= 10.0;
  405.     }
  406.     return (d + e) * sign;
  407. }
  408.  
  409. gboolean containsDecimal(char *string)
  410. {
  411.     for(int i = 0; i < strlen(string); i++)
  412.     {
  413.         if(string[i] == '.')
  414.         {
  415.             return TRUE;
  416.         }
  417.     }
  418.     return FALSE;
  419. }
  420.  
  421. char* substr(char* string, int begin, int end)
  422. {
  423.     char* temp = new char[end - begin + 1];
  424.     strncpy(temp, string+begin, end-begin+1);
  425.     temp[end-begin+1] = '\0';
  426.     return temp;
  427. }
  428.  
  429. char* removeZeros(char* string)
  430. {
  431.     bool extras = false;
  432.     bool past_dec = false;
  433.     int end = -1;
  434.     for(int i = 0; i < strlen(string); i++)
  435.     {
  436.         if(string[i] == '.')
  437.         {
  438.             past_dec = true;
  439.             continue;
  440.         }
  441.         else if(!past_dec)
  442.         {
  443.             continue;
  444.         }
  445.         else
  446.         {
  447.             if(string[i] == '0' && !extras)
  448.             {
  449.                 int pad = 0;
  450.                 if(string[i-1] == '.')
  451.                 {
  452.                     pad = 1;
  453.                 }
  454.                 end = i - 1 - pad;
  455.                 extras = true;
  456.             }
  457.             else if(string[i] != '0' && extras)
  458.             {
  459.                 end = -1;
  460.                 extras = false;
  461.             }
  462.         }
  463.     }
  464.     if(extras)
  465.     {
  466.         return substr(string, 0, end);
  467.     }
  468.     else
  469.     {
  470.         return string;
  471.     }
  472. }
  473.  
  474. double power(double a, int b)
  475. {
  476.     double temp = 1.0;
  477.     for(int i = 0; i < b; i++)
  478.     {
  479.         temp *= a;
  480.     }
  481.     return temp;
  482. }
Advertisement
Add Comment
Please, Sign In to add comment