/* * display.c - code for this nifty display. * part of galculator * (c) 2002-2007 Simon Floery (chimaira@users.sf.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "galculator.h" #include "display.h" #include "general_functions.h" #include "config_file.h" #include "math_functions.h" #include "calc_basic.h" #include "ui.h" #include #include #include static GtkTextView *view; static GtkTextBuffer *buffer; static int display_result_counter = 0; static int display_result_line = 0; static char *number_mod_labels[5] = {" DEC ", " HEX ", " OCT ", " BIN ", NULL}, *angle_mod_labels[4] = {" DEG ", " RAD ", " GRAD ", NULL}, *notation_mod_labels[4] = {" ALG ", " RPN ", " FORM ", NULL}; /* no one outside display.c should need to call these functions */ static void display_set_line_double (double value, int line, char *tag, int number_base_status); static void display_set_line (char *string, int line, char *tag); static char *display_get_line (int line_nr); /* we do not need to remember the stack in double as this is stored outside * the stack functions in here only manipulate yzt */ double display_value=0.; /* * display.c mainly consists of two parts: first display setup code * and second display manipulation code. */ /* this code is taken from the GTK 2.0 tutorial: * http://www.gtk.org/tutorial */ gboolean on_textview_button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { static GdkAtom targets_atom = GDK_NONE; int x, y; GtkTextIter start, end; char *selected_text; if (event->button == 1) { gtk_widget_get_pointer (widget, &x, &y); gtk_text_view_get_iter_at_location (view, &start, x, y); /* we return if we are in the first line */ if (gtk_text_iter_get_line (&start) != display_result_line+1) return FALSE; /* we return if its the end iterator */ if (gtk_text_iter_is_end (&start) == TRUE) return FALSE; end = start; if (!gtk_text_iter_starts_word(&start)) gtk_text_iter_backward_word_start (&start); if (!gtk_text_iter_ends_word(&end)) gtk_text_iter_forward_word_end (&end); selected_text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); /* in a rare case, we get two options as selected_text */ if (strchr (selected_text, ' ') != NULL) return FALSE; /* rather a hack: last_arith is ignored as one char only gets selected as a word with spaces (because of iter_[back|for]ward_..). So we have to ignore the open brackets. */ if (strlen (selected_text) <= 2) return FALSE; activate_menu_item (selected_text); } else if (event->button == 2) { /* it's pasting selection time ...*/ /* Get the atom corresponding to the string "STRING" */ if (targets_atom == GDK_NONE) \ targets_atom = gdk_atom_intern ("STRING", FALSE); /* And request the "STRING" target for the primary selection */ gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom, \ GDK_CURRENT_TIME); } return FALSE; } /* this code is taken from the GTK 2.0 tutorial: * http://www.gtk.org/tutorial */ void on_textview_selection_received (GtkWidget *widget, GtkSelectionData *data, guint time, gpointer user_data) { /* **** IMPORTANT **** Check to see if retrieval succeeded */ /* occurs if we just press the middle button with no active selection */ if (data->length < 0) return; /* Make sure we got the data in the expected form */ if (data->type != GDK_SELECTION_TYPE_STRING) return; /* ok, we tried to avoid this in display.* but here we can't avoid using the global var. */ display_result_feed ((char *)data->data, current_status.number); return; } /* * display_create_text_tags - creates a tag for the result and (in-)active modules */ void display_create_text_tags () { int pixels=0; /* note: wrap MUST NOT be set to none in order to justify the text! */ if (current_status.notation == CS_PAN) pixels = 5; gtk_text_buffer_create_tag (buffer, "result", "justification", GTK_JUSTIFY_RIGHT, "font", prefs.result_font, "foreground", prefs.result_color, "pixels-above-lines", pixels, "pixels-below-lines", pixels, NULL); gtk_text_buffer_create_tag (buffer, "active_module", "font", prefs.mod_font, "foreground", prefs.act_mod_color, "wrap-mode", GTK_WRAP_NONE, NULL); gtk_text_buffer_create_tag (buffer, "inactive_module", "font", prefs.mod_font, "foreground", prefs.inact_mod_color, "wrap-mode", GTK_WRAP_NONE, NULL); gtk_text_buffer_create_tag (buffer, "stack", "font", prefs.stack_font, "foreground", prefs.stack_color, "justification", GTK_JUSTIFY_LEFT, NULL); } /* * display_init. Call this function before any other function of this file. */ void display_init () { GdkColor color; int char_width; PangoContext *pango_context; PangoFontMetrics *font_metrics; GtkTextTag *tag; PangoTabArray *tab_array; GtkTextTagTable *tag_table; current_status.calc_entry_start_new = FALSE; view = (GtkTextView *) glade_xml_get_widget (view_xml, "textview"); gdk_color_parse (prefs.bkg_color, &color); gtk_widget_modify_base ((GtkWidget *)view, GTK_STATE_NORMAL, &color); buffer = gtk_text_view_get_buffer (view); display_create_text_tags (); /* compute the approx char/digit width and create a tab stops */ tag_table = gtk_text_buffer_get_tag_table (buffer); tag = gtk_text_tag_table_lookup (tag_table, "active_module"); /* get the approx char width */ pango_context = gtk_widget_get_pango_context ((GtkWidget *)view); font_metrics = pango_context_get_metrics(pango_context, \ tag->values->font, tag->values->language); char_width = MAX (pango_font_metrics_get_approximate_char_width (font_metrics), \ pango_font_metrics_get_approximate_digit_width (font_metrics)); tab_array = pango_tab_array_new_with_positions (1, FALSE, PANGO_TAB_LEFT, 3*char_width); gtk_text_view_set_tabs (view, tab_array); pango_tab_array_free (tab_array); /* if we display a stack, this will be updated later */ display_result_line = 0; display_set_line (CLEARED_DISPLAY, display_result_line, "result"); display_update_modules (); /* number, angle and notation are now set in src/callbacks.c:: * on_scientific_mode_activate resp on_basic_mode_activate. */ /* was in general_functions::apply_preferences before, now go here*/ display_update_tags (); display_set_bkg_color (prefs.bkg_color); } /* * display_module_arith_label_update - code for the "display last arithmetic * operation" display module. put operation in static current_char to survive * an apply f preferences. */ void display_module_arith_label_update (char operation) { GtkTextMark *this_mark; GtkTextIter start, end; static char current_char=' '; if ((prefs.vis_arith == FALSE) || (prefs.mode != SCIENTIFIC_MODE)) return; if (strchr ("()", operation) != NULL) return; if ((this_mark = gtk_text_buffer_get_mark (buffer, DISPLAY_MARK_ARITH)) == NULL) \ return; gtk_text_buffer_get_iter_at_mark (buffer, &start, this_mark); end = start; gtk_text_iter_forward_chars (&end, 3); gtk_text_buffer_delete (buffer, &start, &end); gtk_text_buffer_get_iter_at_mark (buffer, &start, this_mark); if (operation != NOP) current_char = operation; gtk_text_buffer_insert_with_tags_by_name (buffer, &start, \ g_strdup_printf ("\t%c\t", current_char), -1, "active_module", NULL); } /* * display_module_bracket_label_update - code for the "display number of open * brackets" display module */ int display_module_bracket_label_update (int option) { GtkTextMark *this_mark; GtkTextIter start, end; static int nr_brackets=0; int forward_count=2; char *string; switch (option) { case ONE_MORE: nr_brackets++; if (nr_brackets > 0) forward_count = 5 + log10(nr_brackets); break; case ONE_LESS: if (nr_brackets > 0) forward_count = 5 + log10(nr_brackets); nr_brackets--; break; case RESET: if (nr_brackets > 0) forward_count = 5 + log10(nr_brackets); nr_brackets = 0; break; case GET: /* doing this here to not touch the display */ return nr_brackets; case NOP: if (nr_brackets > 0) forward_count = 5 + log10(nr_brackets); break; } if ((prefs.vis_bracket == FALSE) || (prefs.mode != SCIENTIFIC_MODE)) return nr_brackets; if ((this_mark = gtk_text_buffer_get_mark (buffer, DISPLAY_MARK_BRACKET)) == NULL) \ return nr_brackets; gtk_text_buffer_get_iter_at_mark (buffer, &start, this_mark); end = start; gtk_text_iter_forward_chars (&end, forward_count); gtk_text_buffer_delete (buffer, &start, &end); gtk_text_buffer_get_iter_at_mark (buffer, &start, this_mark); if (nr_brackets > 0) { string = g_strdup_printf ("\t(%i\t", nr_brackets); gtk_text_buffer_insert_with_tags_by_name (buffer, &start, string, \ -1, "active_module", NULL); g_free (string); } else { nr_brackets = 0; gtk_text_buffer_insert_with_tags_by_name (buffer, &start, "\t\t", \ -1, "active_module", NULL); } return nr_brackets; } /* * display_module_base_create - start_mark is the mark where this module starts. * Therefore, the single labels are inserted starting with the last (as the mark * is at the beginning!). A simple gtk_text_buffer_insert_with_tags_by_name * doesn't work as we insert in an already tagged region an tag priority rules out. * solving this matter with setting priorities is not possible, so we have to remove * all tags and apply the tag we want. */ void display_module_base_create (char **module_label, char *mark_name, int active_index) { int label_counter=0, counter; GtkTextIter start, end; GtkTextMark *this_mark; if ((this_mark = gtk_text_buffer_get_mark (buffer, mark_name)) == NULL) return; while (module_label[label_counter] != NULL) label_counter++; for (counter = (label_counter-1); counter >= 0; counter--) { gtk_text_buffer_get_iter_at_mark (buffer, &end, this_mark); gtk_text_buffer_insert (buffer, &end, module_label[counter], -1); gtk_text_buffer_get_iter_at_mark (buffer, &start, this_mark); gtk_text_buffer_remove_all_tags (buffer, &start, &end); if (counter == active_index) { gtk_text_buffer_apply_tag_by_name (buffer, "active_module", &start, &end); } else { gtk_text_buffer_apply_tag_by_name (buffer, "inactive_module", &start, &end); } } } /* * display_module_leading_spaces - the distance between two modules is done with * spaces. when inserting this spaces, we have to pay attention that it really * is between two modules (e.g. we want no spaces after the last module) and * that we don't lose the text mark pointing to the start of a module. */ void display_module_leading_spaces (char *mark_name, gboolean leading_spaces) { GtkTextIter iter; GtkTextMark *start_mark; if (leading_spaces == FALSE) return; if ((start_mark = gtk_text_buffer_get_mark (buffer, mark_name)) == NULL) return; gtk_text_buffer_get_iter_at_mark (buffer, &iter, start_mark); /* insert spaces */ gtk_text_buffer_insert (buffer, &iter, DISPLAY_MODULES_DELIM, -1); /* update text mark */ gtk_text_buffer_delete_mark (buffer, start_mark); gtk_text_buffer_create_mark (buffer, mark_name, &iter, TRUE); } /* display_module_number_activate. */ void display_module_number_activate (int number_base) { activate_menu_item (number_mod_labels[number_base]); } /* display_module_angle_activate. */ void display_module_angle_activate (int angle_unit) { activate_menu_item (angle_mod_labels[angle_unit]); } /* display_module_notation_activate. */ void display_module_notation_activate (int mode) { activate_menu_item (notation_mod_labels[mode]); } void display_get_line_end_iter (GtkTextBuffer *b, int line_index, GtkTextIter *end) { gtk_text_buffer_get_iter_at_line (b, end, line_index); gtk_text_iter_forward_to_line_end (end); } void display_get_line_iters (GtkTextBuffer *b, int line_index, GtkTextIter *start, GtkTextIter *end) { gtk_text_buffer_get_iter_at_line (b, start, line_index); *end = *start; gtk_text_iter_forward_to_line_end (end); } /* * display_delete_line - deletes given line. start points to the place where we * deleted. */ void display_delete_line (GtkTextBuffer *b, int line_index, GtkTextIter *iter) { GtkTextIter start, end; if (gtk_text_buffer_get_line_count (b) <= line_index) { fprintf (stderr, _("[%s] Line_index exceeds valid range in function \"display_delete_line\". %s\n"), PROG_NAME, BUG_REPORT); return; } display_get_line_iters (b, line_index, &start, &end); gtk_text_buffer_delete (buffer, &start, &end); *iter = start; } /* * display_create_modules - the display modules compose the second line of then * display. available modules: * - change number base * - change angle base * - change notation */ void display_update_modules () { GtkTextIter start, end; gboolean first_module = TRUE; if (prefs.mode == PAPER_MODE) return; display_get_line_end_iter (buffer, display_result_line, &start); display_get_line_end_iter (buffer, display_result_line+1, &end); gtk_text_buffer_delete (buffer, &start, &end); if (prefs.mode == BASIC_MODE) return; /* change number base */ if (prefs.vis_number == TRUE) { if (first_module) gtk_text_buffer_insert_with_tags_by_name (buffer, &start, "\n", \ -1, "result", NULL); gtk_text_buffer_get_iter_at_line (buffer, &start, display_result_line+1); gtk_text_iter_forward_to_line_end (&start); if (gtk_text_buffer_get_mark (buffer, DISPLAY_MARK_NUMBER) != NULL) \ gtk_text_buffer_delete_mark_by_name (buffer, DISPLAY_MARK_NUMBER); gtk_text_buffer_create_mark (buffer, DISPLAY_MARK_NUMBER, &start, TRUE); display_module_base_create (number_mod_labels, DISPLAY_MARK_NUMBER, current_status.number); display_module_leading_spaces (DISPLAY_MARK_NUMBER, !first_module); first_module = FALSE; } /* angle */ if (prefs.vis_angle == TRUE) { if (first_module) gtk_text_buffer_insert_with_tags_by_name (buffer, &start, "\n", \ -1, "result", NULL); gtk_text_buffer_get_iter_at_line (buffer, &start, display_result_line+1); gtk_text_iter_forward_to_line_end (&start); if (gtk_text_buffer_get_mark (buffer, DISPLAY_MARK_ANGLE) != NULL) \ gtk_text_buffer_delete_mark_by_name (buffer, DISPLAY_MARK_ANGLE); gtk_text_buffer_create_mark (buffer, DISPLAY_MARK_ANGLE, &start, TRUE); display_module_base_create (angle_mod_labels, DISPLAY_MARK_ANGLE, current_status.angle); display_module_leading_spaces (DISPLAY_MARK_ANGLE, !first_module); first_module = FALSE; } /* notation */ if (prefs.vis_notation == TRUE) { if (first_module) gtk_text_buffer_insert_with_tags_by_name (buffer, &start, "\n", \ -1, "result", NULL); gtk_text_buffer_get_iter_at_line (buffer, &start, display_result_line+1); gtk_text_iter_forward_to_line_end (&start); if (gtk_text_buffer_get_mark (buffer, DISPLAY_MARK_NOTATION) != NULL) \ gtk_text_buffer_delete_mark_by_name (buffer, DISPLAY_MARK_NOTATION); gtk_text_buffer_create_mark (buffer, DISPLAY_MARK_NOTATION, &start, TRUE); display_module_base_create (notation_mod_labels, DISPLAY_MARK_NOTATION, current_status.notation); display_module_leading_spaces (DISPLAY_MARK_NOTATION, !first_module); first_module = FALSE; } /* last arithmetic operation */ if (prefs.vis_arith == TRUE) { if (first_module) gtk_text_buffer_insert_with_tags_by_name (buffer, &start, "\n", \ -1, "result", NULL); gtk_text_buffer_get_iter_at_line (buffer, &start, display_result_line+1); gtk_text_iter_forward_to_line_end (&start); if (gtk_text_buffer_get_mark (buffer, DISPLAY_MARK_ARITH) != NULL) \ gtk_text_buffer_delete_mark_by_name (buffer, DISPLAY_MARK_ARITH); gtk_text_buffer_create_mark (buffer, DISPLAY_MARK_ARITH, &start, TRUE); display_module_arith_label_update (NOP); display_module_leading_spaces (DISPLAY_MARK_ARITH, !first_module); first_module = FALSE; } /* number of open brackets */ if (prefs.vis_bracket == TRUE) { if (first_module) gtk_text_buffer_insert_with_tags_by_name (buffer, &start, "\n", \ -1, "result", NULL); gtk_text_buffer_get_iter_at_line (buffer, &start, display_result_line+1); gtk_text_iter_forward_to_line_end (&start); if (gtk_text_buffer_get_mark (buffer, DISPLAY_MARK_BRACKET) != NULL) \ gtk_text_buffer_delete_mark_by_name (buffer, DISPLAY_MARK_BRACKET); gtk_text_buffer_create_mark (buffer, DISPLAY_MARK_BRACKET, &start, TRUE); display_module_bracket_label_update (NOP); display_module_leading_spaces (DISPLAY_MARK_BRACKET, !first_module); first_module = FALSE; } } /* * display_module_base_delete - delete the given module at given text mark. * used for display_change_option */ void display_module_base_delete (char *mark_name, char **text) { int counter=0, length=0; GtkTextIter start, end; GtkTextMark *this_mark; if ((this_mark = gtk_text_buffer_get_mark (buffer, mark_name)) == NULL) return; while (text[counter] != NULL) { length+=strlen(text[counter]); counter++; } gtk_text_buffer_get_iter_at_mark (buffer, &start, this_mark); end = start; gtk_text_iter_forward_chars (&end, length); gtk_text_buffer_delete (buffer, &start, &end); } /* * display_change_option - updates the display in case of number/angle/notation * changes. we need old_status to get display value in correct base. * The last function in the signal handling cascade of changing base etc. */ void display_change_option (int old_status, int new_status, int opt_group) { double display_value=0; double *stack; switch (opt_group) { case DISPLAY_OPT_NUMBER: update_active_buttons (new_status, current_status.notation); display_value = display_result_get_double (old_status); stack = display_stack_get_yzt_double (old_status); display_result_set_double (display_value, new_status); display_stack_set_yzt_double (stack, new_status); g_free (stack); if ((prefs.vis_number) && (prefs.mode == SCIENTIFIC_MODE)) { display_module_base_delete (DISPLAY_MARK_NUMBER, number_mod_labels); display_module_base_create (number_mod_labels, DISPLAY_MARK_NUMBER, new_status); } break; case DISPLAY_OPT_ANGLE: if ((prefs.vis_angle) && (prefs.mode == SCIENTIFIC_MODE)){ display_module_base_delete (DISPLAY_MARK_ANGLE, angle_mod_labels); display_module_base_create (angle_mod_labels, DISPLAY_MARK_ANGLE, new_status); } break; case DISPLAY_OPT_NOTATION: update_active_buttons (current_status.number, new_status); if ((prefs.vis_notation) && (prefs.mode == SCIENTIFIC_MODE)){ display_module_base_delete (DISPLAY_MARK_NOTATION, notation_mod_labels); display_module_base_create (notation_mod_labels, DISPLAY_MARK_NOTATION, new_status); } break; default: error_message (_("[%s] unknown display option in function \"display_change_option\"")); } } /* * display_set_bkg_color - change the background color of the text view */ void display_set_bkg_color (char *color_string) { GdkColor color; if (prefs.mode == PAPER_MODE) return; gdk_color_parse (color_string, &color); if (view) gtk_widget_modify_base ((GtkWidget *)view, GTK_STATE_NORMAL, &color); } /* * if we change any settings for result/module fonts this function updates the * all the tags. */ void display_update_tags () { GtkTextIter start, end; GtkTextTagTable *tag_table; GtkTextTag *tag; if (prefs.mode == PAPER_MODE) return; /* remove all tags from tag_table, so we can define the new tags */ tag_table = gtk_text_buffer_get_tag_table (buffer); tag = gtk_text_tag_table_lookup (tag_table, "result"); gtk_text_tag_table_remove (tag_table, tag); tag = gtk_text_tag_table_lookup (tag_table, "inactive_module"); gtk_text_tag_table_remove (tag_table, tag); tag = gtk_text_tag_table_lookup (tag_table, "active_module"); gtk_text_tag_table_remove (tag_table, tag); tag = gtk_text_tag_table_lookup (tag_table, "stack"); gtk_text_tag_table_remove (tag_table, tag); /* create the tags again, up2date */ display_create_text_tags (); /* apply to stack */ if (display_result_line > 0) { gtk_text_buffer_get_iter_at_line (buffer, &start, 0); display_get_line_end_iter (buffer, display_result_line - 1, &end); gtk_text_buffer_apply_tag_by_name (buffer, "stack", &start, &end); } /* apply to result */ display_get_line_iters (buffer, display_result_line, &start, &end); gtk_text_buffer_apply_tag_by_name (buffer, "result", &start, &end); /* apply to modules */ display_update_modules (); } /****************** *** END of display CONFIGuration code. *** from here on display manipulation code. ******************/ /* these is the most basic routine. all functions here finally result in a call * to this. */ static void display_set_line (char *string, int line, char *tag) { char *separator_string; GtkTextIter start; /* at first clear the result field */ display_delete_line (buffer, line, &start); separator_string = string_add_separator(string, get_sep(current_status.number), get_sep_length(current_status.number), get_sep_char(current_status.number), dec_point[0]); /* DISPLAY RESULT MODIFIED */ gtk_text_buffer_insert_with_tags_by_name (buffer, &start, separator_string, -1, tag, NULL); free (separator_string); if (line == display_result_line) { display_result_counter = strlen (string); /* this is some cosmetics. try to keep counter up2date */ if (strchr (string, 'e') != NULL) { display_result_counter -= (strchr(string, 'e') + sizeof(char) - string)/sizeof(char); display_result_counter += get_display_number_length(current_status.number) - DISPLAY_RESULT_E_LENGTH - 1; } else if (strchr (string, dec_point[0]) != NULL) display_result_counter--; } } static void display_set_line_double (double value, int line, char *tag, int number_base_status) { char *string_value; string_value = get_display_number_string (value, current_status.number); display_set_line (string_value, line, tag); g_free (string_value); } /* * display_result_add_digit. appends the given digit to the current entry, * handles zeros, decimal points. call e.g. with *(gtk_button_get_label (button)) */ void display_result_add_digit (char digit, int number_base_status) { char *display_string=NULL, *new_display_string=NULL; /* fool the following code */ if (current_status.calc_entry_start_new == TRUE) { display_result_set (CLEARED_DISPLAY, TRUE, 0.); current_status.calc_entry_start_new = FALSE; display_result_counter = 1; } display_string = display_result_get(); if (digit == dec_point[0]) { /* don't manipulate display_result_counter here! */ if (strlen (display_string) == 0) new_display_string = g_strdup_printf ("0%c", digit); else if ((strchr (display_string, dec_point[0]) == NULL) && \ (strchr (display_string, 'e') == NULL)) new_display_string = g_strdup_printf ("%s%c", display_string, digit); } else { /* replace "0" on display with new digit */ if (strcmp (display_string, CLEARED_DISPLAY) == 0) new_display_string = g_strdup_printf ("%c", digit); else if (display_result_counter < get_display_number_length(current_status.number)) { new_display_string = g_strdup_printf ("%s%c", display_string, digit); /* increment counter only in this if directive as above the counter remains 1! */ display_result_counter++; } } if (new_display_string) display_result_set (new_display_string, TRUE, string2double(new_display_string, number_base_status)); if (display_string) g_free (display_string); if (new_display_string) g_free (new_display_string); } /* * display_result_set_double. set text of calc_entry to string given by float value. * the float value is manipulated (rounded, ...) */ void display_result_set_double (double value, int number_base_status) { current_status.allow_arith_op = TRUE; display_module_arith_label_update (' '); display_set_line_double (value, display_result_line, "result", number_base_status); display_value = value; } void display_result_set (char *string_value, int update_display_value, double value) { current_status.allow_arith_op = TRUE; display_module_arith_label_update (' '); display_set_line (string_value, display_result_line, "result"); /* this should be an exceptional case and never be done to results of operations */ if (update_display_value) display_value = value; } void display_result_feed (char *string, int number_base_status) { int counter; for (counter = 0; counter < strlen(string); counter++) { if (is_valid_number(current_status.number, string[counter])) /* g_ascii_toupper to convert lower hex chars to upper */ display_result_add_digit ( g_ascii_toupper(string[counter]), number_base_status); } if (string[0] == '-') display_result_toggle_sign (NULL); } /* * display_result_get_line. The only function calling a gtk_text_buffer_get_* * function directly. */ static char *display_get_line (int line_nr) { GtkTextIter start, end; display_get_line_iters (buffer, line_nr, &start, &end); /* DISPLAY RESULT GET */ return string_del_separator(gtk_text_buffer_get_text (buffer, &start, &end, TRUE), get_sep_char(current_status.number)); } /* display_result_get. a simplfied call to display_result_get_line */ char *display_result_get () { return display_get_line (display_result_line); } /* display_result_get_double. a display_result_get plus conversion to double */ double display_result_get_double (int number_base_status) { /* char *result_string; double ret_val; result_string = display_result_get(); ret_val = string2double (result_string, number_base_status); g_free (result_string); */ return display_value; } void display_append_e (GtkToggleButton *button) { char *display_value; /* we have kind of a shortcut. we don't set to 0e+ but 1e+ */ if (current_status.number != CS_DEC) return; if ((current_status.calc_entry_start_new == FALSE) && (strcmp (display_result_get(), "0") != 0)) { if (strstr (display_result_get(), "e") == NULL) { /* DISPLAY RESULT MODIFIED display_get_line_end_iter (buffer, display_result_line, &end); gtk_text_buffer_insert_with_tags_by_name (buffer, &end, "e+", -1, "result", NULL); */ display_value = g_strdup_printf ("%se+", display_result_get()); display_result_set (display_value, FALSE, -1); g_free (display_value); } } else { display_result_set ("1e+", TRUE, 1.); current_status.calc_entry_start_new = FALSE; } display_result_counter = get_display_number_length(current_status.number) - DISPLAY_RESULT_E_LENGTH; } void display_result_toggle_sign (GtkToggleButton *button) { char *result_field, *e_pointer; if (current_status.number != CS_DEC) return; result_field = display_result_get(); /* if there is no e? we toggle the leading sign, otherwise the sign after e */ if ((e_pointer = strchr (result_field, 'e')) == NULL) { if (*result_field == '-') g_stpcpy (result_field, result_field + sizeof(char)); else if (strcmp (result_field, "0") != 0) result_field = g_strdup_printf ("-%s", result_field); } else { if (*(++e_pointer) == '-') *e_pointer = '+'; else *e_pointer = '-'; } display_result_set (result_field, FALSE, -1.); display_value *= (-1); g_free (result_field); } /* display_result_backspace - deletes the tail of the display. * sets the display with display_result_set => no additional manipulation of * display_result_counter * necessary */ void display_result_backspace (int number_base_status) { char *current_entry; if (current_status.calc_entry_start_new == TRUE) { current_status.calc_entry_start_new = FALSE; display_result_set (CLEARED_DISPLAY, TRUE, 0.); } else { current_entry = display_result_get(); /* to avoid an empty/senseless result field */ if (strlen(current_entry) == 1) current_entry[0] = '0'; else if ((strlen(current_entry) == 2) && (*current_entry == '-')) current_entry = "0\0"; else if (current_entry[strlen(current_entry) - 2] == 'e') current_entry[strlen(current_entry) - 2] = '\0'; else current_entry[strlen(current_entry) - 1] = '\0'; display_result_set (current_entry, TRUE, string2double (current_entry, number_base_status)); g_free (current_entry); } } /* display_result_getset. kind of display result redraw. use this to get and * set the display, it frees the return string of display_result_get() */ void display_result_getset () { char *result; char **stack; if (prefs.mode == PAPER_MODE) return; result = display_result_get(); stack = display_stack_get_yzt(); display_result_set(result, FALSE, -1); display_stack_set_yzt(stack); g_free(result); g_free(stack); } /* * STACK functions manipulating the display */ void display_stack_create () { int counter; GtkTextIter start; if (display_result_line > 0) return; display_result_line = 3; for (counter = 0; counter < display_result_line; counter++) { gtk_text_buffer_get_iter_at_line (buffer, &start, 0); gtk_text_buffer_insert_with_tags_by_name (buffer, &start, "0\n", -1, "stack", NULL); } } void display_stack_remove () { GtkTextIter start, end; gtk_text_buffer_get_iter_at_line (buffer, &start, 0); gtk_text_buffer_get_iter_at_line (buffer, &end, display_result_line); gtk_text_buffer_delete (buffer, &start, &end); display_result_line = 0; } /* * display_stack_set_yzt_double - stack must be a 3 dimensional array. stack in * calc_basic IS NOT modified. */ void display_stack_set_yzt_double (double *stack, int number_base_status) { int counter; for (counter = 0; counter < display_result_line; counter++) display_set_line_double (stack[counter], display_result_line - counter - 1, "stack", number_base_status); } /* * display_stack_set_yzt_double - stack in calc_basic IS NOT modified. */ void display_stack_set_yzt (char **stack) { int counter; for (counter = 0; counter < display_result_line; counter++) { display_set_line (stack[display_result_line - counter - 1], counter, "stack"); } } /* * display_stack_get_yzt - returns a three-sized char array with 1:1 copies * of the current displayed stack. */ char **display_stack_get_yzt () { char **stack; int counter; stack = (char **) malloc (3* sizeof (char *)); for (counter = 0; counter < 3; counter++) { /* DISPLAY RESULT GET display_get_line_iters (buffer, display_result_line - counter - 1, &start, &end); stack[counter] = gtk_text_buffer_get_text (buffer, &start, &end, TRUE); */ stack[counter] = display_get_line(display_result_line - counter - 1); } return stack; } /* * display_stack_get_yzt_double - returns the string array of display_stack_get_yzt * as double array. */ double *display_stack_get_yzt_double (int number_base_status) { char **string_stack; double *double_stack; int counter; double_stack = (double *) malloc (display_result_line * sizeof(double)); string_stack = display_stack_get_yzt(); for (counter = 0; counter < display_result_line; counter++) double_stack[counter] = string2double (string_stack[counter], number_base_status); return double_stack; }