lists.geany.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
February
January
2012
December
November
October
September
August
July
June
May
April
March
February
January
2011
December
November
October
September
August
July
June
May
April
March
February
January
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
December
November
October
September
August
July
June
May
April
March
February
January
2007
December
November
October
September
August
July
June
May
April
March
February
January
2006
December
November
October
September
August
July
June
May
List overview
Commits
August 2014
----- 2024 -----
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
----- 2007 -----
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
----- 2006 -----
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
commits@lists.geany.org
1 participants
94 discussions
Start a n
N
ew thread
[geany/geany] ba8899: Merge branch 'small-dialogs-cleanup'
by Colomban Wendling
12 Aug '14
12 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Tue, 12 Aug 2014 12:18:04 UTC Commit: ba8899b09cb8635a3b3c67bef07d9ea4cba9780f
https://github.com/geany/geany/commit/ba8899b09cb8635a3b3c67bef07d9ea4cba97…
Log Message: ----------- Merge branch 'small-dialogs-cleanup' Modified Paths: -------------- src/build.c src/dialogs.c src/dialogs.h Modified: src/build.c 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -1361,7 +1361,7 @@ static void build_command(GeanyDocument *doc, GeanyBuildGroup grp, guint cmd, gc * Create build menu and handle callbacks (&toolbar callbacks) * *----------------------------------------------------------------*/ -static void on_make_custom_input_response(const gchar *input) +static void on_make_custom_input_response(const gchar *input, gpointer data) { GeanyDocument *doc = document_get_current(); @@ -1393,7 +1393,7 @@ static void on_build_menu_item(GtkWidget *w, gpointer user_data) { dialog = dialogs_show_input_persistent(_("Custom Text"), GTK_WINDOW(main_widgets.window), _("Enter custom text here, all entered text is appended to the command."), - build_info.custom_target, &on_make_custom_input_response); + build_info.custom_target, &on_make_custom_input_response, NULL); } else { Modified: src/dialogs.c 135 lines changed, 65 insertions(+), 70 deletions(-) =================================================================== @@ -922,70 +922,30 @@ on_input_numeric_activate(GtkEntry *entry, GtkDialog *dialog) } -static void -on_input_dialog_response(GtkDialog *dialog, gint response, GtkWidget *entry) +typedef struct { - gboolean persistent = (gboolean) GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dialog), "has_combo")); - - if (response == GTK_RESPONSE_ACCEPT) - { - const gchar *str = gtk_entry_get_text(GTK_ENTRY(entry)); - GeanyInputCallback input_cb = - (GeanyInputCallback) g_object_get_data(G_OBJECT(dialog), "input_cb"); + GtkWidget *entry; + GtkWidget *combo; - if (persistent) - { - GtkWidget *combo = (GtkWidget *) g_object_get_data(G_OBJECT(dialog), "combo"); - ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(combo), str, 0); - } - input_cb(str); - } - gtk_widget_hide(GTK_WIDGET(dialog)); + GeanyInputCallback callback; + gpointer data; } +InputDialogData; -static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox, - const gchar *label_text, const gchar *default_text, gboolean persistent, - GCallback insert_text_cb) +static void +on_input_dialog_response(GtkDialog *dialog, gint response, InputDialogData *data) { - GtkWidget *entry; - - if (label_text) + if (response == GTK_RESPONSE_ACCEPT) { - GtkWidget *label = gtk_label_new(label_text); - gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); - gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); - gtk_container_add(GTK_CONTAINER(vbox), label); - } + const gchar *str = gtk_entry_get_text(GTK_ENTRY(data->entry)); - if (persistent) /* remember previous entry text in a combo box */ - { - GtkWidget *combo = gtk_combo_box_text_new_with_entry(); + if (data->combo != NULL) + ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(data->combo), str, 0); - entry = gtk_bin_get_child(GTK_BIN(combo)); - ui_entry_add_clear_icon(GTK_ENTRY(entry)); - g_object_set_data(G_OBJECT(dialog), "combo", combo); - gtk_container_add(GTK_CONTAINER(vbox), combo); - } - else - { - entry = gtk_entry_new(); - ui_entry_add_clear_icon(GTK_ENTRY(entry)); - gtk_container_add(GTK_CONTAINER(vbox), entry); + data->callback(str, data->data); } - - if (default_text != NULL) - { - gtk_entry_set_text(GTK_ENTRY(entry), default_text); - } - gtk_entry_set_max_length(GTK_ENTRY(entry), 255); - gtk_entry_set_width_chars(GTK_ENTRY(entry), 30); - - if (insert_text_cb != NULL) - g_signal_connect(entry, "insert-text", insert_text_cb, NULL); - g_signal_connect(entry, "activate", G_CALLBACK(on_input_entry_activate), dialog); - g_signal_connect(dialog, "show", G_CALLBACK(on_input_dialog_show), entry); - g_signal_connect(dialog, "response", G_CALLBACK(on_input_dialog_response), entry); + gtk_widget_hide(GTK_WIDGET(dialog)); } @@ -997,9 +957,11 @@ static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox, static GtkWidget * dialogs_show_input_full(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text, - gboolean persistent, GeanyInputCallback input_cb, GCallback insert_text_cb) + gboolean persistent, GeanyInputCallback input_cb, gpointer input_cb_data, + GCallback insert_text_cb, gpointer insert_text_cb_data) { GtkWidget *dialog, *vbox; + InputDialogData *data = g_malloc(sizeof *data); dialog = gtk_dialog_new_with_buttons(title, parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, @@ -1008,10 +970,45 @@ dialogs_show_input_full(const gchar *title, GtkWindow *parent, gtk_widget_set_name(dialog, "GeanyDialog"); gtk_box_set_spacing(GTK_BOX(vbox), 6); - g_object_set_data(G_OBJECT(dialog), "has_combo", GINT_TO_POINTER(persistent)); - g_object_set_data(G_OBJECT(dialog), "input_cb", (gpointer) input_cb); + data->combo = NULL; + data->entry = NULL; + data->callback = input_cb; + data->data = input_cb_data; + + if (label_text) + { + GtkWidget *label = gtk_label_new(label_text); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + gtk_container_add(GTK_CONTAINER(vbox), label); + } + + if (persistent) /* remember previous entry text in a combo box */ + { + data->combo = gtk_combo_box_text_new_with_entry(); + data->entry = gtk_bin_get_child(GTK_BIN(data->combo)); + ui_entry_add_clear_icon(GTK_ENTRY(data->entry)); + gtk_container_add(GTK_CONTAINER(vbox), data->combo); + } + else + { + data->entry = gtk_entry_new(); + ui_entry_add_clear_icon(GTK_ENTRY(data->entry)); + gtk_container_add(GTK_CONTAINER(vbox), data->entry); + } - add_input_widgets(dialog, vbox, label_text, default_text, persistent, insert_text_cb); + if (default_text != NULL) + { + gtk_entry_set_text(GTK_ENTRY(data->entry), default_text); + } + gtk_entry_set_max_length(GTK_ENTRY(data->entry), 255); + gtk_entry_set_width_chars(GTK_ENTRY(data->entry), 30); + + if (insert_text_cb != NULL) + g_signal_connect(data->entry, "insert-text", insert_text_cb, insert_text_cb_data); + g_signal_connect(data->entry, "activate", G_CALLBACK(on_input_entry_activate), dialog); + g_signal_connect(dialog, "show", G_CALLBACK(on_input_dialog_show), data->entry); + g_signal_connect_data(dialog, "response", G_CALLBACK(on_input_dialog_response), data, (GClosureNotify)g_free, 0); if (persistent) { @@ -1032,18 +1029,16 @@ dialogs_show_input_full(const gchar *title, GtkWindow *parent, GtkWidget * dialogs_show_input_persistent(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text, - GeanyInputCallback input_cb) + GeanyInputCallback input_cb, gpointer input_cb_data) { - return dialogs_show_input_full(title, parent, label_text, default_text, TRUE, input_cb, NULL); + return dialogs_show_input_full(title, parent, label_text, default_text, TRUE, input_cb, input_cb_data, NULL, NULL); } -/* ugly hack - user_data not supported for callback */ -static gchar *dialog_input = NULL; - -static void on_dialog_input(const gchar *str) +static void on_dialog_input(const gchar *str, gpointer data) { - dialog_input = g_strdup(str); + gchar **dialog_input = data; + *dialog_input = g_strdup(str); } @@ -1058,8 +1053,8 @@ static void on_dialog_input(const gchar *str) gchar *dialogs_show_input(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text) { - dialog_input = NULL; - dialogs_show_input_full(title, parent, label_text, default_text, FALSE, on_dialog_input, NULL); + gchar *dialog_input = NULL; + dialogs_show_input_full(title, parent, label_text, default_text, FALSE, on_dialog_input, &dialog_input, NULL, NULL); return dialog_input; } @@ -1070,10 +1065,10 @@ gchar *dialogs_show_input(const gchar *title, GtkWindow *parent, const gchar *la gchar *dialogs_show_input_goto_line(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text) { - dialog_input = NULL; + gchar *dialog_input = NULL; dialogs_show_input_full( - title, parent, label_text, default_text, FALSE, on_dialog_input, - G_CALLBACK(ui_editable_insert_text_callback)); + title, parent, label_text, default_text, FALSE, on_dialog_input, &dialog_input, + G_CALLBACK(ui_editable_insert_text_callback), NULL); return dialog_input; } Modified: src/dialogs.h 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -34,7 +34,7 @@ G_BEGIN_DECLS -typedef void (*GeanyInputCallback)(const gchar *text); +typedef void (*GeanyInputCallback)(const gchar *text, gpointer data); void dialogs_show_open_file(void); @@ -56,7 +56,7 @@ gchar *dialogs_show_input_goto_line(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text); GtkWidget *dialogs_show_input_persistent(const gchar *title, GtkWindow *parent, - const gchar *label_text, const gchar *default_text, GeanyInputCallback input_cb); + const gchar *label_text, const gchar *default_text, GeanyInputCallback input_cb, gpointer input_cb_data); gboolean dialogs_show_input_numeric(const gchar *title, const gchar *label_text, gdouble *value, gdouble min, gdouble max, gdouble step); -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] 36a6dd: dialogs: Don't abuse GObject data
by Colomban Wendling
11 Aug '14
11 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Mon, 11 Aug 2014 14:52:26 UTC Commit: 36a6dd2e2c1808adedcc1135ffc70a210c77350d
https://github.com/geany/geany/commit/36a6dd2e2c1808adedcc1135ffc70a210c773…
Log Message: ----------- dialogs: Don't abuse GObject data Modified Paths: -------------- src/dialogs.c Modified: src/dialogs.c 70 lines changed, 37 insertions(+), 33 deletions(-) =================================================================== @@ -922,24 +922,28 @@ on_input_numeric_activate(GtkEntry *entry, GtkDialog *dialog) } -static void -on_input_dialog_response(GtkDialog *dialog, gint response, GtkWidget *entry) +typedef struct { - gboolean persistent = (gboolean) GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dialog), "has_combo")); + GtkWidget *entry; + GtkWidget *combo; + + GeanyInputCallback callback; + gpointer data; +} +InputDialogData; + +static void +on_input_dialog_response(GtkDialog *dialog, gint response, InputDialogData *data) +{ if (response == GTK_RESPONSE_ACCEPT) { - const gchar *str = gtk_entry_get_text(GTK_ENTRY(entry)); - GeanyInputCallback input_cb = - (GeanyInputCallback) g_object_get_data(G_OBJECT(dialog), "input_cb"); - gpointer input_cb_data = g_object_get_data(G_OBJECT(dialog), "input_cb_data"); + const gchar *str = gtk_entry_get_text(GTK_ENTRY(data->entry)); - if (persistent) - { - GtkWidget *combo = (GtkWidget *) g_object_get_data(G_OBJECT(dialog), "combo"); - ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(combo), str, 0); - } - input_cb(str, input_cb_data); + if (data->combo != NULL) + ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(data->combo), str, 0); + + data->callback(str, data->data); } gtk_widget_hide(GTK_WIDGET(dialog)); } @@ -956,7 +960,8 @@ dialogs_show_input_full(const gchar *title, GtkWindow *parent, gboolean persistent, GeanyInputCallback input_cb, gpointer input_cb_data, GCallback insert_text_cb, gpointer insert_text_cb_data) { - GtkWidget *dialog, *vbox, *entry; + GtkWidget *dialog, *vbox; + InputDialogData *data = g_malloc(sizeof *data); dialog = gtk_dialog_new_with_buttons(title, parent, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, @@ -965,9 +970,10 @@ dialogs_show_input_full(const gchar *title, GtkWindow *parent, gtk_widget_set_name(dialog, "GeanyDialog"); gtk_box_set_spacing(GTK_BOX(vbox), 6); - g_object_set_data(G_OBJECT(dialog), "has_combo", GINT_TO_POINTER(persistent)); - g_object_set_data(G_OBJECT(dialog), "input_cb", (gpointer) input_cb); - g_object_set_data(G_OBJECT(dialog), "input_cb_data", input_cb_data); + data->combo = NULL; + data->entry = NULL; + data->callback = input_cb; + data->data = input_cb_data; if (label_text) { @@ -979,32 +985,30 @@ dialogs_show_input_full(const gchar *title, GtkWindow *parent, if (persistent) /* remember previous entry text in a combo box */ { - GtkWidget *combo = gtk_combo_box_text_new_with_entry(); - - entry = gtk_bin_get_child(GTK_BIN(combo)); - ui_entry_add_clear_icon(GTK_ENTRY(entry)); - g_object_set_data(G_OBJECT(dialog), "combo", combo); - gtk_container_add(GTK_CONTAINER(vbox), combo); + data->combo = gtk_combo_box_text_new_with_entry(); + data->entry = gtk_bin_get_child(GTK_BIN(data->combo)); + ui_entry_add_clear_icon(GTK_ENTRY(data->entry)); + gtk_container_add(GTK_CONTAINER(vbox), data->combo); } else { - entry = gtk_entry_new(); - ui_entry_add_clear_icon(GTK_ENTRY(entry)); - gtk_container_add(GTK_CONTAINER(vbox), entry); + data->entry = gtk_entry_new(); + ui_entry_add_clear_icon(GTK_ENTRY(data->entry)); + gtk_container_add(GTK_CONTAINER(vbox), data->entry); } if (default_text != NULL) { - gtk_entry_set_text(GTK_ENTRY(entry), default_text); + gtk_entry_set_text(GTK_ENTRY(data->entry), default_text); } - gtk_entry_set_max_length(GTK_ENTRY(entry), 255); - gtk_entry_set_width_chars(GTK_ENTRY(entry), 30); + gtk_entry_set_max_length(GTK_ENTRY(data->entry), 255); + gtk_entry_set_width_chars(GTK_ENTRY(data->entry), 30); if (insert_text_cb != NULL) - g_signal_connect(entry, "insert-text", insert_text_cb, insert_text_cb_data); - g_signal_connect(entry, "activate", G_CALLBACK(on_input_entry_activate), dialog); - g_signal_connect(dialog, "show", G_CALLBACK(on_input_dialog_show), entry); - g_signal_connect(dialog, "response", G_CALLBACK(on_input_dialog_response), entry); + g_signal_connect(data->entry, "insert-text", insert_text_cb, insert_text_cb_data); + g_signal_connect(data->entry, "activate", G_CALLBACK(on_input_entry_activate), dialog); + g_signal_connect(dialog, "show", G_CALLBACK(on_input_dialog_show), data->entry); + g_signal_connect_data(dialog, "response", G_CALLBACK(on_input_dialog_response), data, (GClosureNotify)g_free, 0); if (persistent) { -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] 571239: dialogs: Remove an unnecessary function indirection
by Colomban Wendling
11 Aug '14
11 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Mon, 11 Aug 2014 14:38:09 UTC Commit: 571239e0bf07752b2059376ca815f3b1efa115a9
https://github.com/geany/geany/commit/571239e0bf07752b2059376ca815f3b1efa11…
Log Message: ----------- dialogs: Remove an unnecessary function indirection Having add_input_widgets() didn't really make the code any simpler, rather obfuscating it a little. Modified Paths: -------------- src/dialogs.c Modified: src/dialogs.c 54 lines changed, 22 insertions(+), 32 deletions(-) =================================================================== @@ -945,11 +945,29 @@ on_input_dialog_response(GtkDialog *dialog, gint response, GtkWidget *entry) } -static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox, - const gchar *label_text, const gchar *default_text, gboolean persistent, - GCallback insert_text_cb, gpointer insert_text_cb_data) +/* Create and display an input dialog. + * persistent: whether to remember previous entry text in a combo box; + * in this case the dialog returned is not destroyed on a response, + * and can be reshown. + * Returns: the dialog widget. */ +static GtkWidget * +dialogs_show_input_full(const gchar *title, GtkWindow *parent, + const gchar *label_text, const gchar *default_text, + gboolean persistent, GeanyInputCallback input_cb, gpointer input_cb_data, + GCallback insert_text_cb, gpointer insert_text_cb_data) { - GtkWidget *entry; + GtkWidget *dialog, *vbox, *entry; + + dialog = gtk_dialog_new_with_buttons(title, parent, + GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); + vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog)); + gtk_widget_set_name(dialog, "GeanyDialog"); + gtk_box_set_spacing(GTK_BOX(vbox), 6); + + g_object_set_data(G_OBJECT(dialog), "has_combo", GINT_TO_POINTER(persistent)); + g_object_set_data(G_OBJECT(dialog), "input_cb", (gpointer) input_cb); + g_object_set_data(G_OBJECT(dialog), "input_cb_data", input_cb_data); if (label_text) { @@ -987,34 +1005,6 @@ static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox, g_signal_connect(entry, "activate", G_CALLBACK(on_input_entry_activate), dialog); g_signal_connect(dialog, "show", G_CALLBACK(on_input_dialog_show), entry); g_signal_connect(dialog, "response", G_CALLBACK(on_input_dialog_response), entry); -} - - -/* Create and display an input dialog. - * persistent: whether to remember previous entry text in a combo box; - * in this case the dialog returned is not destroyed on a response, - * and can be reshown. - * Returns: the dialog widget. */ -static GtkWidget * -dialogs_show_input_full(const gchar *title, GtkWindow *parent, - const gchar *label_text, const gchar *default_text, - gboolean persistent, GeanyInputCallback input_cb, gpointer input_cb_data, - GCallback insert_text_cb, gpointer insert_text_cb_data) -{ - GtkWidget *dialog, *vbox; - - dialog = gtk_dialog_new_with_buttons(title, parent, - GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); - vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog)); - gtk_widget_set_name(dialog, "GeanyDialog"); - gtk_box_set_spacing(GTK_BOX(vbox), 6); - - g_object_set_data(G_OBJECT(dialog), "has_combo", GINT_TO_POINTER(persistent)); - g_object_set_data(G_OBJECT(dialog), "input_cb", (gpointer) input_cb); - g_object_set_data(G_OBJECT(dialog), "input_cb_data", input_cb_data); - - add_input_widgets(dialog, vbox, label_text, default_text, persistent, insert_text_cb, insert_text_cb_data); if (persistent) { -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] 5fcacf: Add user data to GeanyInputCallback, avoiding global variable hacks
by Colomban Wendling
11 Aug '14
11 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Mon, 11 Aug 2014 13:44:51 UTC Commit: 5fcacf066d7150cdfa9408b82141230209bafe2e
https://github.com/geany/geany/commit/5fcacf066d7150cdfa9408b82141230209baf…
Log Message: ----------- Add user data to GeanyInputCallback, avoiding global variable hacks Modified Paths: -------------- src/build.c src/dialogs.c src/dialogs.h Modified: src/build.c 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -1361,7 +1361,7 @@ static void build_command(GeanyDocument *doc, GeanyBuildGroup grp, guint cmd, gc * Create build menu and handle callbacks (&toolbar callbacks) * *----------------------------------------------------------------*/ -static void on_make_custom_input_response(const gchar *input) +static void on_make_custom_input_response(const gchar *input, gpointer data) { GeanyDocument *doc = document_get_current(); @@ -1393,7 +1393,7 @@ static void on_build_menu_item(GtkWidget *w, gpointer user_data) { dialog = dialogs_show_input_persistent(_("Custom Text"), GTK_WINDOW(main_widgets.window), _("Enter custom text here, all entered text is appended to the command."), - build_info.custom_target, &on_make_custom_input_response); + build_info.custom_target, &on_make_custom_input_response, NULL); } else { Modified: src/dialogs.c 35 lines changed, 18 insertions(+), 17 deletions(-) =================================================================== @@ -932,13 +932,14 @@ on_input_dialog_response(GtkDialog *dialog, gint response, GtkWidget *entry) const gchar *str = gtk_entry_get_text(GTK_ENTRY(entry)); GeanyInputCallback input_cb = (GeanyInputCallback) g_object_get_data(G_OBJECT(dialog), "input_cb"); + gpointer input_cb_data = g_object_get_data(G_OBJECT(dialog), "input_cb_data"); if (persistent) { GtkWidget *combo = (GtkWidget *) g_object_get_data(G_OBJECT(dialog), "combo"); ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(combo), str, 0); } - input_cb(str); + input_cb(str, input_cb_data); } gtk_widget_hide(GTK_WIDGET(dialog)); } @@ -946,7 +947,7 @@ on_input_dialog_response(GtkDialog *dialog, gint response, GtkWidget *entry) static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox, const gchar *label_text, const gchar *default_text, gboolean persistent, - GCallback insert_text_cb) + GCallback insert_text_cb, gpointer insert_text_cb_data) { GtkWidget *entry; @@ -982,7 +983,7 @@ static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox, gtk_entry_set_width_chars(GTK_ENTRY(entry), 30); if (insert_text_cb != NULL) - g_signal_connect(entry, "insert-text", insert_text_cb, NULL); + g_signal_connect(entry, "insert-text", insert_text_cb, insert_text_cb_data); g_signal_connect(entry, "activate", G_CALLBACK(on_input_entry_activate), dialog); g_signal_connect(dialog, "show", G_CALLBACK(on_input_dialog_show), entry); g_signal_connect(dialog, "response", G_CALLBACK(on_input_dialog_response), entry); @@ -997,7 +998,8 @@ static void add_input_widgets(GtkWidget *dialog, GtkWidget *vbox, static GtkWidget * dialogs_show_input_full(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text, - gboolean persistent, GeanyInputCallback input_cb, GCallback insert_text_cb) + gboolean persistent, GeanyInputCallback input_cb, gpointer input_cb_data, + GCallback insert_text_cb, gpointer insert_text_cb_data) { GtkWidget *dialog, *vbox; @@ -1010,8 +1012,9 @@ dialogs_show_input_full(const gchar *title, GtkWindow *parent, g_object_set_data(G_OBJECT(dialog), "has_combo", GINT_TO_POINTER(persistent)); g_object_set_data(G_OBJECT(dialog), "input_cb", (gpointer) input_cb); + g_object_set_data(G_OBJECT(dialog), "input_cb_data", input_cb_data); - add_input_widgets(dialog, vbox, label_text, default_text, persistent, insert_text_cb); + add_input_widgets(dialog, vbox, label_text, default_text, persistent, insert_text_cb, insert_text_cb_data); if (persistent) { @@ -1032,18 +1035,16 @@ dialogs_show_input_full(const gchar *title, GtkWindow *parent, GtkWidget * dialogs_show_input_persistent(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text, - GeanyInputCallback input_cb) + GeanyInputCallback input_cb, gpointer input_cb_data) { - return dialogs_show_input_full(title, parent, label_text, default_text, TRUE, input_cb, NULL); + return dialogs_show_input_full(title, parent, label_text, default_text, TRUE, input_cb, input_cb_data, NULL, NULL); } -/* ugly hack - user_data not supported for callback */ -static gchar *dialog_input = NULL; - -static void on_dialog_input(const gchar *str) +static void on_dialog_input(const gchar *str, gpointer data) { - dialog_input = g_strdup(str); + gchar **dialog_input = data; + *dialog_input = g_strdup(str); } @@ -1058,8 +1059,8 @@ static void on_dialog_input(const gchar *str) gchar *dialogs_show_input(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text) { - dialog_input = NULL; - dialogs_show_input_full(title, parent, label_text, default_text, FALSE, on_dialog_input, NULL); + gchar *dialog_input = NULL; + dialogs_show_input_full(title, parent, label_text, default_text, FALSE, on_dialog_input, &dialog_input, NULL, NULL); return dialog_input; } @@ -1070,10 +1071,10 @@ gchar *dialogs_show_input(const gchar *title, GtkWindow *parent, const gchar *la gchar *dialogs_show_input_goto_line(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text) { - dialog_input = NULL; + gchar *dialog_input = NULL; dialogs_show_input_full( - title, parent, label_text, default_text, FALSE, on_dialog_input, - G_CALLBACK(ui_editable_insert_text_callback)); + title, parent, label_text, default_text, FALSE, on_dialog_input, &dialog_input, + G_CALLBACK(ui_editable_insert_text_callback), NULL); return dialog_input; } Modified: src/dialogs.h 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -34,7 +34,7 @@ G_BEGIN_DECLS -typedef void (*GeanyInputCallback)(const gchar *text); +typedef void (*GeanyInputCallback)(const gchar *text, gpointer data); void dialogs_show_open_file(void); @@ -56,7 +56,7 @@ gchar *dialogs_show_input_goto_line(const gchar *title, GtkWindow *parent, const gchar *label_text, const gchar *default_text); GtkWidget *dialogs_show_input_persistent(const gchar *title, GtkWindow *parent, - const gchar *label_text, const gchar *default_text, GeanyInputCallback input_cb); + const gchar *label_text, const gchar *default_text, GeanyInputCallback input_cb, gpointer input_cb_data); gboolean dialogs_show_input_numeric(const gchar *title, const gchar *label_text, gdouble *value, gdouble min, gdouble max, gdouble step); -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] 5832c4: Merge branch 'prefs-less-globals'
by Colomban Wendling
10 Aug '14
10 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Sun, 10 Aug 2014 14:28:56 UTC Commit: 5832c4b64c293e6091cf4da555b59d7931b13cb9
https://github.com/geany/geany/commit/5832c4b64c293e6091cf4da555b59d7931b13…
Log Message: ----------- Merge branch 'prefs-less-globals' Modified Paths: -------------- src/prefs.c Modified: src/prefs.c 177 lines changed, 85 insertions(+), 92 deletions(-) =================================================================== @@ -68,20 +68,22 @@ GeanyPrefs prefs; GeanyToolPrefs tool_prefs; -/* keybinding globals, should be put in a struct */ -static GtkTreeIter g_iter; -static GtkTreeStore *store = NULL; -static GtkTreeView *tree = NULL; -static GtkWidget *dialog_label; -static gboolean edited = FALSE; +typedef struct +{ + GtkTreeStore *store; + GtkTreeView *tree; + gboolean edited; +} +KbData; +static KbData global_kb_data = { NULL, NULL, FALSE }; static GtkTreeView *various_treeview = NULL; static GeanyKeyBinding *kb_index(guint gidx, guint kid); -static void kb_cell_edited_cb(GtkCellRendererText *cellrenderertext, gchar *path, gchar *new_text, gpointer user_data); -static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, gpointer user_data); -static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, gpointer user_data); -static gboolean kb_find_duplicate(GtkWidget *parent, GtkTreeIter *old_iter, +static void kb_cell_edited_cb(GtkCellRendererText *cellrenderertext, gchar *path, gchar *new_text, KbData *kbdata); +static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, GtkLabel *label); +static void kb_change_iter_shortcut(KbData *kbdata, GtkTreeIter *iter, const gchar *new_text); +static gboolean kb_find_duplicate(GtkTreeStore *store, GtkWidget *parent, GtkTreeIter *old_iter, guint key, GdkModifierType mods, const gchar *shortcut); static void on_toolbar_show_toggled(GtkToggleButton *togglebutton, gpointer user_data); static void on_show_notebook_tabs_toggled(GtkToggleButton *togglebutton, gpointer user_data); @@ -144,33 +146,35 @@ enum }; -static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, gpointer data) +static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, KbData *kbdata) { GtkTreeModel *model; + GtkTreeIter iter; GtkTreeSelection *selection; gchar *name; - selection = gtk_tree_view_get_selection(tree); - if (gtk_tree_selection_get_selected(selection, &model, &g_iter)) + selection = gtk_tree_view_get_selection(kbdata->tree); + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - if (gtk_tree_model_iter_has_child(model, &g_iter)) + if (gtk_tree_model_iter_has_child(model, &iter)) { /* double click on a section to expand or collapse it */ - GtkTreePath *path = gtk_tree_model_get_path(model, &g_iter); + GtkTreePath *path = gtk_tree_model_get_path(model, &iter); - if (gtk_tree_view_row_expanded(tree, path)) - gtk_tree_view_collapse_row(tree, path); + if (gtk_tree_view_row_expanded(kbdata->tree, path)) + gtk_tree_view_collapse_row(kbdata->tree, path); else - gtk_tree_view_expand_row(tree, path, FALSE); + gtk_tree_view_expand_row(kbdata->tree, path, FALSE); gtk_tree_path_free(path); return; } - gtk_tree_model_get(model, &g_iter, KB_TREE_ACTION, &name, -1); + gtk_tree_model_get(model, &iter, KB_TREE_ACTION, &name, -1); if (name != NULL) { GtkWidget *dialog; GtkWidget *label; + GtkWidget *accel_label; gchar *str; dialog = gtk_dialog_new_with_buttons(_("Grab Key"), GTK_WINDOW(ui_widgets.prefs_dialog), @@ -184,15 +188,22 @@ static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, gpointer da gtk_misc_set_padding(GTK_MISC(label), 5, 10); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label); - dialog_label = gtk_label_new(""); - gtk_misc_set_padding(GTK_MISC(dialog_label), 5, 10); - gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), dialog_label); + accel_label = gtk_label_new(""); + gtk_misc_set_padding(GTK_MISC(accel_label), 5, 10); + gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), accel_label); g_signal_connect(dialog, "key-press-event", - G_CALLBACK(kb_grab_key_dialog_key_press_cb), NULL); - g_signal_connect(dialog, "response", G_CALLBACK(kb_grab_key_dialog_response_cb), NULL); + G_CALLBACK(kb_grab_key_dialog_key_press_cb), accel_label); gtk_widget_show_all(dialog); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + const gchar *new_text = gtk_label_get_text(GTK_LABEL(accel_label)); + + kb_change_iter_shortcut(kbdata, &iter, new_text); + } + gtk_widget_destroy(dialog); + g_free(str); g_free(name); } @@ -200,16 +211,7 @@ static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, gpointer da } -static void kb_expand_collapse_cb(GtkWidget *item, gpointer user_data) -{ - if (user_data != NULL) - gtk_tree_view_expand_all(tree); - else - gtk_tree_view_collapse_all(tree); -} - - -static void kb_show_popup_menu(GtkWidget *widget, GdkEventButton *event) +static void kb_show_popup_menu(KbData *kbdata, GtkWidget *widget, GdkEventButton *event) { GtkWidget *item; static GtkWidget *menu = NULL; @@ -223,12 +225,12 @@ static void kb_show_popup_menu(GtkWidget *widget, GdkEventButton *event) item = ui_image_menu_item_new(GTK_STOCK_ADD, _("_Expand All")); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(menu), item); - g_signal_connect(item, "activate", G_CALLBACK(kb_expand_collapse_cb), GINT_TO_POINTER(TRUE)); + g_signal_connect_swapped(item, "activate", G_CALLBACK(gtk_tree_view_expand_all), kbdata->tree); item = ui_image_menu_item_new(GTK_STOCK_REMOVE, _("_Collapse All")); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(menu), item); - g_signal_connect(item, "activate", G_CALLBACK(kb_expand_collapse_cb), NULL); + g_signal_connect_swapped(item, "activate", G_CALLBACK(gtk_tree_view_collapse_all), kbdata->tree); gtk_menu_attach_to_widget(GTK_MENU(menu), widget, NULL); } @@ -248,52 +250,52 @@ static void kb_show_popup_menu(GtkWidget *widget, GdkEventButton *event) } -static gboolean kb_popup_menu_cb(GtkWidget *widget, gpointer data) +static gboolean kb_popup_menu_cb(GtkWidget *widget, KbData *kbdata) { - kb_show_popup_menu(widget, NULL); + kb_show_popup_menu(kbdata, widget, NULL); return TRUE; } static gboolean kb_tree_view_button_press_event_cb(GtkWidget *widget, GdkEventButton *event, - gpointer user_data) + KbData *kbdata) { if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { - kb_show_popup_menu(widget, event); + kb_show_popup_menu(kbdata, widget, event); return TRUE; } else if (event->type == GDK_2BUTTON_PRESS) { - kb_tree_view_change_button_clicked_cb(NULL, NULL); + kb_tree_view_change_button_clicked_cb(NULL, kbdata); return TRUE; } return FALSE; } -static void kb_init_tree(void) +static void kb_init_tree(KbData *kbdata) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; - tree = GTK_TREE_VIEW(ui_lookup_widget(ui_widgets.prefs_dialog, "treeview7")); + kbdata->tree = GTK_TREE_VIEW(ui_lookup_widget(ui_widgets.prefs_dialog, "treeview7")); - store = gtk_tree_store_new(KB_TREE_COLUMNS, + kbdata->store = gtk_tree_store_new(KB_TREE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_INT); - gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(store)); - g_object_unref(store); + gtk_tree_view_set_model(GTK_TREE_VIEW(kbdata->tree), GTK_TREE_MODEL(kbdata->store)); + g_object_unref(kbdata->store); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Action"), renderer, "text", KB_TREE_ACTION, "weight", KB_TREE_WEIGHT, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); + gtk_tree_view_append_column(GTK_TREE_VIEW(kbdata->tree), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Shortcut"), renderer, "text", KB_TREE_SHORTCUT, "editable", KB_TREE_EDITABLE, "weight", KB_TREE_WEIGHT, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); + gtk_tree_view_append_column(GTK_TREE_VIEW(kbdata->tree), column); /* set policy settings for the scrolled window around the treeview again, because glade * doesn't keep the settings */ @@ -301,11 +303,11 @@ static void kb_init_tree(void) GTK_SCROLLED_WINDOW(ui_lookup_widget(ui_widgets.prefs_dialog, "scrolledwindow8")), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - g_signal_connect(renderer, "edited", G_CALLBACK(kb_cell_edited_cb), NULL); - g_signal_connect(tree, "button-press-event", G_CALLBACK(kb_tree_view_button_press_event_cb), NULL); - g_signal_connect(tree, "popup-menu", G_CALLBACK(kb_popup_menu_cb), NULL); + g_signal_connect(renderer, "edited", G_CALLBACK(kb_cell_edited_cb), kbdata); + g_signal_connect(kbdata->tree, "button-press-event", G_CALLBACK(kb_tree_view_button_press_event_cb), kbdata); + g_signal_connect(kbdata->tree, "popup-menu", G_CALLBACK(kb_popup_menu_cb), kbdata); g_signal_connect(ui_lookup_widget(ui_widgets.prefs_dialog, "button2"), "clicked", - G_CALLBACK(kb_tree_view_change_button_clicked_cb), NULL); + G_CALLBACK(kb_tree_view_change_button_clicked_cb), kbdata); } @@ -336,8 +338,9 @@ void prefs_kb_search_name(const gchar *search) GtkTreeIter iter; gboolean valid; GtkTreeModel *model; + KbData *kbdata = &global_kb_data; - model = gtk_tree_view_get_model(tree); + model = gtk_tree_view_get_model(kbdata->tree); valid = gtk_tree_model_get_iter_first(model, &iter); while (valid) { @@ -347,7 +350,7 @@ void prefs_kb_search_name(const gchar *search) if (g_strcmp0(name, search) == 0) { GtkTreePath *path = gtk_tree_model_get_path(model, &iter); - gtk_tree_view_scroll_to_cell(tree, path, NULL, TRUE, .0f, .0f); + gtk_tree_view_scroll_to_cell(kbdata->tree, path, NULL, TRUE, .0f, .0f); gtk_tree_path_free(path); g_free(name); break; @@ -358,7 +361,7 @@ void prefs_kb_search_name(const gchar *search) } -static void kb_init(void) +static void kb_init(KbData *kbdata) { GtkTreeIter parent, iter; gsize g, i; @@ -366,26 +369,26 @@ static void kb_init(void) GeanyKeyGroup *group; GeanyKeyBinding *kb; - if (store == NULL) - kb_init_tree(); + if (kbdata->store == NULL) + kb_init_tree(kbdata); foreach_ptr_array(group, g, keybinding_groups) { - gtk_tree_store_append(store, &parent, NULL); - gtk_tree_store_set(store, &parent, KB_TREE_ACTION, group->label, + gtk_tree_store_append(kbdata->store, &parent, NULL); + gtk_tree_store_set(kbdata->store, &parent, KB_TREE_ACTION, group->label, KB_TREE_INDEX, g, -1); foreach_ptr_array(kb, i, group->key_items) { label = keybindings_get_label(kb); - gtk_tree_store_append(store, &iter, &parent); - gtk_tree_store_set(store, &iter, KB_TREE_ACTION, label, + gtk_tree_store_append(kbdata->store, &iter, &parent); + gtk_tree_store_set(kbdata->store, &iter, KB_TREE_ACTION, label, KB_TREE_EDITABLE, TRUE, KB_TREE_INDEX, kb->id, -1); - kb_set_shortcut(store, &iter, kb->key, kb->mods); + kb_set_shortcut(kbdata->store, &iter, kb->key, kb->mods); g_free(label); } } - gtk_tree_view_expand_all(GTK_TREE_VIEW(tree)); + gtk_tree_view_expand_all(GTK_TREE_VIEW(kbdata->tree)); } @@ -704,7 +707,7 @@ static void prefs_init_dialog(void) /* Keybindings */ - kb_init(); + kb_init(&global_kb_data); /* Printing */ { @@ -813,9 +816,9 @@ static GeanyKeyBinding *kb_index(guint gidx, guint kid) /* read the treeview shortcut fields into keybindings */ -static void kb_update(void) +static void kb_update(KbData *kbdata) { - GtkTreeModel *model = GTK_TREE_MODEL(store); + GtkTreeModel *model = GTK_TREE_MODEL(kbdata->store); GtkTreeIter child, parent; guint gid = 0; @@ -1189,9 +1192,9 @@ on_prefs_dialog_response(GtkDialog *dialog, gint response, gpointer user_data) /* Keybindings */ - if (edited) + if (global_kb_data.edited) { - kb_update(); + kb_update(&global_kb_data); tools_create_insert_custom_command_menu_items(); keybindings_write_to_file(); } @@ -1309,7 +1312,7 @@ on_prefs_dialog_response(GtkDialog *dialog, gint response, gpointer user_data) } else if (response != GTK_RESPONSE_APPLY) { - gtk_tree_store_clear(store); + gtk_tree_store_clear(global_kb_data.store); gtk_widget_hide(GTK_WIDGET(dialog)); } } @@ -1370,45 +1373,47 @@ static void on_prefs_font_choosed(GtkFontButton *widget, gpointer user_data) } -static void kb_change_iter_shortcut(GtkTreeIter *iter, const gchar *new_text) +static void kb_change_iter_shortcut(KbData *kbdata, GtkTreeIter *iter, const gchar *new_text) { guint lkey; GdkModifierType lmods; gtk_accelerator_parse(new_text, &lkey, &lmods); - if (kb_find_duplicate(ui_widgets.prefs_dialog, iter, lkey, lmods, new_text)) + if (kb_find_duplicate(kbdata->store, ui_widgets.prefs_dialog, iter, lkey, lmods, new_text)) return; /* set the values here, because of the above check, setting it in * gtk_accelerator_parse would return a wrong key combination if it is duplicate */ - kb_set_shortcut(store, iter, lkey, lmods); + kb_set_shortcut(kbdata->store, iter, lkey, lmods); - edited = TRUE; + kbdata->edited = TRUE; } static void kb_cell_edited_cb(GtkCellRendererText *cellrenderertext, - gchar *path, gchar *new_text, gpointer user_data) + gchar *path, gchar *new_text, KbData *kbdata) { if (path != NULL && new_text != NULL) { GtkTreeIter iter; - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, path); - if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter)) + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(kbdata->store), &iter, path); + if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(kbdata->store), &iter)) return; /* ignore group items */ - kb_change_iter_shortcut(&iter, new_text); + kb_change_iter_shortcut(kbdata, &iter, new_text); } } -static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, gpointer user_data) +static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, GtkLabel *label) { gchar *str; guint state; + g_return_val_if_fail(GTK_IS_LABEL(label), FALSE); + state = event->state & gtk_accelerator_get_default_mod_mask(); if (event->keyval == GDK_Escape) @@ -1416,28 +1421,16 @@ static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey * str = gtk_accelerator_name(event->keyval, state); - gtk_label_set_text(GTK_LABEL(dialog_label), str); + gtk_label_set_text(label, str); g_free(str); return TRUE; } -static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, G_GNUC_UNUSED gpointer iter) -{ - if (response == GTK_RESPONSE_ACCEPT) - { - const gchar *new_text = gtk_label_get_text(GTK_LABEL(dialog_label)); - - kb_change_iter_shortcut(&g_iter, new_text); - } - gtk_widget_destroy(dialog); -} - - /* test if the entered key combination is already used * returns true if cancelling duplicate */ -static gboolean kb_find_duplicate(GtkWidget *parent, GtkTreeIter *old_iter, +static gboolean kb_find_duplicate(GtkTreeStore *store, GtkWidget *parent, GtkTreeIter *old_iter, guint key, GdkModifierType mods, const gchar *shortcut) { GtkTreeModel *model = GTK_TREE_MODEL(store); -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] 2559cd: prefs: Remove some global state in keybinding-related code
by Colomban Wendling
10 Aug '14
10 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Sun, 10 Aug 2014 13:47:18 UTC Commit: 2559cda95408bd8b32a96baff1918a78ce649c75
https://github.com/geany/geany/commit/2559cda95408bd8b32a96baff1918a78ce649…
Log Message: ----------- prefs: Remove some global state in keybinding-related code Use gtk_dialog_run() to run the key input dialog, which is modal anyway. This avoids having to pass the label and the iter around for the dialog response callback to have them, as they now only are used directly in the function setting them in the first place. Modified Paths: -------------- src/prefs.c Modified: src/prefs.c 53 lines changed, 25 insertions(+), 28 deletions(-) =================================================================== @@ -70,21 +70,19 @@ GeanyToolPrefs tool_prefs; typedef struct { - GtkTreeIter iter; GtkTreeStore *store; GtkTreeView *tree; - GtkWidget *dialog_label; gboolean edited; } KbData; -static KbData global_kb_data = { {0}, NULL, NULL, NULL, FALSE }; +static KbData global_kb_data = { NULL, NULL, FALSE }; static GtkTreeView *various_treeview = NULL; static GeanyKeyBinding *kb_index(guint gidx, guint kid); static void kb_cell_edited_cb(GtkCellRendererText *cellrenderertext, gchar *path, gchar *new_text, KbData *kbdata); -static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, KbData *kbdata); -static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, KbData *kbdata); +static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, GtkLabel *label); +static void kb_change_iter_shortcut(KbData *kbdata, GtkTreeIter *iter, const gchar *new_text); static gboolean kb_find_duplicate(GtkTreeStore *store, GtkWidget *parent, GtkTreeIter *old_iter, guint key, GdkModifierType mods, const gchar *shortcut); static void on_toolbar_show_toggled(GtkToggleButton *togglebutton, gpointer user_data); @@ -151,15 +149,16 @@ enum static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, KbData *kbdata) { GtkTreeModel *model; + GtkTreeIter iter; GtkTreeSelection *selection; gchar *name; selection = gtk_tree_view_get_selection(kbdata->tree); - if (gtk_tree_selection_get_selected(selection, &model, &kbdata->iter)) + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - if (gtk_tree_model_iter_has_child(model, &kbdata->iter)) + if (gtk_tree_model_iter_has_child(model, &iter)) { /* double click on a section to expand or collapse it */ - GtkTreePath *path = gtk_tree_model_get_path(model, &kbdata->iter); + GtkTreePath *path = gtk_tree_model_get_path(model, &iter); if (gtk_tree_view_row_expanded(kbdata->tree, path)) gtk_tree_view_collapse_row(kbdata->tree, path); @@ -170,11 +169,12 @@ static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, KbData *kbd return; } - gtk_tree_model_get(model, &kbdata->iter, KB_TREE_ACTION, &name, -1); + gtk_tree_model_get(model, &iter, KB_TREE_ACTION, &name, -1); if (name != NULL) { GtkWidget *dialog; GtkWidget *label; + GtkWidget *accel_label; gchar *str; dialog = gtk_dialog_new_with_buttons(_("Grab Key"), GTK_WINDOW(ui_widgets.prefs_dialog), @@ -188,15 +188,22 @@ static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, KbData *kbd gtk_misc_set_padding(GTK_MISC(label), 5, 10); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label); - kbdata->dialog_label = gtk_label_new(""); - gtk_misc_set_padding(GTK_MISC(kbdata->dialog_label), 5, 10); - gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), kbdata->dialog_label); + accel_label = gtk_label_new(""); + gtk_misc_set_padding(GTK_MISC(accel_label), 5, 10); + gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), accel_label); g_signal_connect(dialog, "key-press-event", - G_CALLBACK(kb_grab_key_dialog_key_press_cb), kbdata); - g_signal_connect(dialog, "response", G_CALLBACK(kb_grab_key_dialog_response_cb), kbdata); + G_CALLBACK(kb_grab_key_dialog_key_press_cb), accel_label); gtk_widget_show_all(dialog); + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) + { + const gchar *new_text = gtk_label_get_text(GTK_LABEL(accel_label)); + + kb_change_iter_shortcut(kbdata, &iter, new_text); + } + gtk_widget_destroy(dialog); + g_free(str); g_free(name); } @@ -1400,11 +1407,13 @@ static void kb_cell_edited_cb(GtkCellRendererText *cellrenderertext, } -static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, KbData *kbdata) +static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, GtkLabel *label) { gchar *str; guint state; + g_return_val_if_fail(GTK_IS_LABEL(label), FALSE); + state = event->state & gtk_accelerator_get_default_mod_mask(); if (event->keyval == GDK_Escape) @@ -1412,25 +1421,13 @@ static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey * str = gtk_accelerator_name(event->keyval, state); - gtk_label_set_text(GTK_LABEL(kbdata->dialog_label), str); + gtk_label_set_text(label, str); g_free(str); return TRUE; } -static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, KbData *kbdata) -{ - if (response == GTK_RESPONSE_ACCEPT) - { - const gchar *new_text = gtk_label_get_text(GTK_LABEL(kbdata->dialog_label)); - - kb_change_iter_shortcut(kbdata, &kbdata->iter, new_text); - } - gtk_widget_destroy(dialog); -} - - /* test if the entered key combination is already used * returns true if cancelling duplicate */ static gboolean kb_find_duplicate(GtkTreeStore *store, GtkWidget *parent, GtkTreeIter *old_iter, -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] 852f32: prefs: Pack keybinding-related globals together and avoid much direct access
by Colomban Wendling
10 Aug '14
10 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Sun, 10 Aug 2014 13:46:44 UTC Commit: 852f3266507ccd06a894a797c67881cc21e5dca7
https://github.com/geany/geany/commit/852f3266507ccd06a894a797c67881cc21e5d…
Log Message: ----------- prefs: Pack keybinding-related globals together and avoid much direct access This however doesn't get rid of any of the global data itself, it only pack it in a struct and passes pointer to this struct around instead of accessing the global whenever possible. Modified Paths: -------------- src/prefs.c Modified: src/prefs.c 162 lines changed, 79 insertions(+), 83 deletions(-) =================================================================== @@ -68,20 +68,24 @@ GeanyPrefs prefs; GeanyToolPrefs tool_prefs; -/* keybinding globals, should be put in a struct */ -static GtkTreeIter g_iter; -static GtkTreeStore *store = NULL; -static GtkTreeView *tree = NULL; -static GtkWidget *dialog_label; -static gboolean edited = FALSE; +typedef struct +{ + GtkTreeIter iter; + GtkTreeStore *store; + GtkTreeView *tree; + GtkWidget *dialog_label; + gboolean edited; +} +KbData; +static KbData global_kb_data = { {0}, NULL, NULL, NULL, FALSE }; static GtkTreeView *various_treeview = NULL; static GeanyKeyBinding *kb_index(guint gidx, guint kid); -static void kb_cell_edited_cb(GtkCellRendererText *cellrenderertext, gchar *path, gchar *new_text, gpointer user_data); -static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, gpointer user_data); -static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, gpointer user_data); -static gboolean kb_find_duplicate(GtkWidget *parent, GtkTreeIter *old_iter, +static void kb_cell_edited_cb(GtkCellRendererText *cellrenderertext, gchar *path, gchar *new_text, KbData *kbdata); +static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, KbData *kbdata); +static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, KbData *kbdata); +static gboolean kb_find_duplicate(GtkTreeStore *store, GtkWidget *parent, GtkTreeIter *old_iter, guint key, GdkModifierType mods, const gchar *shortcut); static void on_toolbar_show_toggled(GtkToggleButton *togglebutton, gpointer user_data); static void on_show_notebook_tabs_toggled(GtkToggleButton *togglebutton, gpointer user_data); @@ -144,29 +148,29 @@ enum }; -static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, gpointer data) +static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, KbData *kbdata) { GtkTreeModel *model; GtkTreeSelection *selection; gchar *name; - selection = gtk_tree_view_get_selection(tree); - if (gtk_tree_selection_get_selected(selection, &model, &g_iter)) + selection = gtk_tree_view_get_selection(kbdata->tree); + if (gtk_tree_selection_get_selected(selection, &model, &kbdata->iter)) { - if (gtk_tree_model_iter_has_child(model, &g_iter)) + if (gtk_tree_model_iter_has_child(model, &kbdata->iter)) { /* double click on a section to expand or collapse it */ - GtkTreePath *path = gtk_tree_model_get_path(model, &g_iter); + GtkTreePath *path = gtk_tree_model_get_path(model, &kbdata->iter); - if (gtk_tree_view_row_expanded(tree, path)) - gtk_tree_view_collapse_row(tree, path); + if (gtk_tree_view_row_expanded(kbdata->tree, path)) + gtk_tree_view_collapse_row(kbdata->tree, path); else - gtk_tree_view_expand_row(tree, path, FALSE); + gtk_tree_view_expand_row(kbdata->tree, path, FALSE); gtk_tree_path_free(path); return; } - gtk_tree_model_get(model, &g_iter, KB_TREE_ACTION, &name, -1); + gtk_tree_model_get(model, &kbdata->iter, KB_TREE_ACTION, &name, -1); if (name != NULL) { GtkWidget *dialog; @@ -184,13 +188,13 @@ static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, gpointer da gtk_misc_set_padding(GTK_MISC(label), 5, 10); gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label); - dialog_label = gtk_label_new(""); - gtk_misc_set_padding(GTK_MISC(dialog_label), 5, 10); - gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), dialog_label); + kbdata->dialog_label = gtk_label_new(""); + gtk_misc_set_padding(GTK_MISC(kbdata->dialog_label), 5, 10); + gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), kbdata->dialog_label); g_signal_connect(dialog, "key-press-event", - G_CALLBACK(kb_grab_key_dialog_key_press_cb), NULL); - g_signal_connect(dialog, "response", G_CALLBACK(kb_grab_key_dialog_response_cb), NULL); + G_CALLBACK(kb_grab_key_dialog_key_press_cb), kbdata); + g_signal_connect(dialog, "response", G_CALLBACK(kb_grab_key_dialog_response_cb), kbdata); gtk_widget_show_all(dialog); g_free(str); @@ -200,16 +204,7 @@ static void kb_tree_view_change_button_clicked_cb(GtkWidget *button, gpointer da } -static void kb_expand_collapse_cb(GtkWidget *item, gpointer user_data) -{ - if (user_data != NULL) - gtk_tree_view_expand_all(tree); - else - gtk_tree_view_collapse_all(tree); -} - - -static void kb_show_popup_menu(GtkWidget *widget, GdkEventButton *event) +static void kb_show_popup_menu(KbData *kbdata, GtkWidget *widget, GdkEventButton *event) { GtkWidget *item; static GtkWidget *menu = NULL; @@ -223,12 +218,12 @@ static void kb_show_popup_menu(GtkWidget *widget, GdkEventButton *event) item = ui_image_menu_item_new(GTK_STOCK_ADD, _("_Expand All")); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(menu), item); - g_signal_connect(item, "activate", G_CALLBACK(kb_expand_collapse_cb), GINT_TO_POINTER(TRUE)); + g_signal_connect_swapped(item, "activate", G_CALLBACK(gtk_tree_view_expand_all), kbdata->tree); item = ui_image_menu_item_new(GTK_STOCK_REMOVE, _("_Collapse All")); gtk_widget_show(item); gtk_container_add(GTK_CONTAINER(menu), item); - g_signal_connect(item, "activate", G_CALLBACK(kb_expand_collapse_cb), NULL); + g_signal_connect_swapped(item, "activate", G_CALLBACK(gtk_tree_view_collapse_all), kbdata->tree); gtk_menu_attach_to_widget(GTK_MENU(menu), widget, NULL); } @@ -248,52 +243,52 @@ static void kb_show_popup_menu(GtkWidget *widget, GdkEventButton *event) } -static gboolean kb_popup_menu_cb(GtkWidget *widget, gpointer data) +static gboolean kb_popup_menu_cb(GtkWidget *widget, KbData *kbdata) { - kb_show_popup_menu(widget, NULL); + kb_show_popup_menu(kbdata, widget, NULL); return TRUE; } static gboolean kb_tree_view_button_press_event_cb(GtkWidget *widget, GdkEventButton *event, - gpointer user_data) + KbData *kbdata) { if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { - kb_show_popup_menu(widget, event); + kb_show_popup_menu(kbdata, widget, event); return TRUE; } else if (event->type == GDK_2BUTTON_PRESS) { - kb_tree_view_change_button_clicked_cb(NULL, NULL); + kb_tree_view_change_button_clicked_cb(NULL, kbdata); return TRUE; } return FALSE; } -static void kb_init_tree(void) +static void kb_init_tree(KbData *kbdata) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; - tree = GTK_TREE_VIEW(ui_lookup_widget(ui_widgets.prefs_dialog, "treeview7")); + kbdata->tree = GTK_TREE_VIEW(ui_lookup_widget(ui_widgets.prefs_dialog, "treeview7")); - store = gtk_tree_store_new(KB_TREE_COLUMNS, + kbdata->store = gtk_tree_store_new(KB_TREE_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN, G_TYPE_INT); - gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(store)); - g_object_unref(store); + gtk_tree_view_set_model(GTK_TREE_VIEW(kbdata->tree), GTK_TREE_MODEL(kbdata->store)); + g_object_unref(kbdata->store); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Action"), renderer, "text", KB_TREE_ACTION, "weight", KB_TREE_WEIGHT, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); + gtk_tree_view_append_column(GTK_TREE_VIEW(kbdata->tree), column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Shortcut"), renderer, "text", KB_TREE_SHORTCUT, "editable", KB_TREE_EDITABLE, "weight", KB_TREE_WEIGHT, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); + gtk_tree_view_append_column(GTK_TREE_VIEW(kbdata->tree), column); /* set policy settings for the scrolled window around the treeview again, because glade * doesn't keep the settings */ @@ -301,11 +296,11 @@ static void kb_init_tree(void) GTK_SCROLLED_WINDOW(ui_lookup_widget(ui_widgets.prefs_dialog, "scrolledwindow8")), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - g_signal_connect(renderer, "edited", G_CALLBACK(kb_cell_edited_cb), NULL); - g_signal_connect(tree, "button-press-event", G_CALLBACK(kb_tree_view_button_press_event_cb), NULL); - g_signal_connect(tree, "popup-menu", G_CALLBACK(kb_popup_menu_cb), NULL); + g_signal_connect(renderer, "edited", G_CALLBACK(kb_cell_edited_cb), kbdata); + g_signal_connect(kbdata->tree, "button-press-event", G_CALLBACK(kb_tree_view_button_press_event_cb), kbdata); + g_signal_connect(kbdata->tree, "popup-menu", G_CALLBACK(kb_popup_menu_cb), kbdata); g_signal_connect(ui_lookup_widget(ui_widgets.prefs_dialog, "button2"), "clicked", - G_CALLBACK(kb_tree_view_change_button_clicked_cb), NULL); + G_CALLBACK(kb_tree_view_change_button_clicked_cb), kbdata); } @@ -336,8 +331,9 @@ void prefs_kb_search_name(const gchar *search) GtkTreeIter iter; gboolean valid; GtkTreeModel *model; + KbData *kbdata = &global_kb_data; - model = gtk_tree_view_get_model(tree); + model = gtk_tree_view_get_model(kbdata->tree); valid = gtk_tree_model_get_iter_first(model, &iter); while (valid) { @@ -347,7 +343,7 @@ void prefs_kb_search_name(const gchar *search) if (g_strcmp0(name, search) == 0) { GtkTreePath *path = gtk_tree_model_get_path(model, &iter); - gtk_tree_view_scroll_to_cell(tree, path, NULL, TRUE, .0f, .0f); + gtk_tree_view_scroll_to_cell(kbdata->tree, path, NULL, TRUE, .0f, .0f); gtk_tree_path_free(path); g_free(name); break; @@ -358,7 +354,7 @@ void prefs_kb_search_name(const gchar *search) } -static void kb_init(void) +static void kb_init(KbData *kbdata) { GtkTreeIter parent, iter; gsize g, i; @@ -366,26 +362,26 @@ static void kb_init(void) GeanyKeyGroup *group; GeanyKeyBinding *kb; - if (store == NULL) - kb_init_tree(); + if (kbdata->store == NULL) + kb_init_tree(kbdata); foreach_ptr_array(group, g, keybinding_groups) { - gtk_tree_store_append(store, &parent, NULL); - gtk_tree_store_set(store, &parent, KB_TREE_ACTION, group->label, + gtk_tree_store_append(kbdata->store, &parent, NULL); + gtk_tree_store_set(kbdata->store, &parent, KB_TREE_ACTION, group->label, KB_TREE_INDEX, g, -1); foreach_ptr_array(kb, i, group->key_items) { label = keybindings_get_label(kb); - gtk_tree_store_append(store, &iter, &parent); - gtk_tree_store_set(store, &iter, KB_TREE_ACTION, label, + gtk_tree_store_append(kbdata->store, &iter, &parent); + gtk_tree_store_set(kbdata->store, &iter, KB_TREE_ACTION, label, KB_TREE_EDITABLE, TRUE, KB_TREE_INDEX, kb->id, -1); - kb_set_shortcut(store, &iter, kb->key, kb->mods); + kb_set_shortcut(kbdata->store, &iter, kb->key, kb->mods); g_free(label); } } - gtk_tree_view_expand_all(GTK_TREE_VIEW(tree)); + gtk_tree_view_expand_all(GTK_TREE_VIEW(kbdata->tree)); } @@ -704,7 +700,7 @@ static void prefs_init_dialog(void) /* Keybindings */ - kb_init(); + kb_init(&global_kb_data); /* Printing */ { @@ -813,9 +809,9 @@ static GeanyKeyBinding *kb_index(guint gidx, guint kid) /* read the treeview shortcut fields into keybindings */ -static void kb_update(void) +static void kb_update(KbData *kbdata) { - GtkTreeModel *model = GTK_TREE_MODEL(store); + GtkTreeModel *model = GTK_TREE_MODEL(kbdata->store); GtkTreeIter child, parent; guint gid = 0; @@ -1189,9 +1185,9 @@ on_prefs_dialog_response(GtkDialog *dialog, gint response, gpointer user_data) /* Keybindings */ - if (edited) + if (global_kb_data.edited) { - kb_update(); + kb_update(&global_kb_data); tools_create_insert_custom_command_menu_items(); keybindings_write_to_file(); } @@ -1309,7 +1305,7 @@ on_prefs_dialog_response(GtkDialog *dialog, gint response, gpointer user_data) } else if (response != GTK_RESPONSE_APPLY) { - gtk_tree_store_clear(store); + gtk_tree_store_clear(global_kb_data.store); gtk_widget_hide(GTK_WIDGET(dialog)); } } @@ -1370,41 +1366,41 @@ static void on_prefs_font_choosed(GtkFontButton *widget, gpointer user_data) } -static void kb_change_iter_shortcut(GtkTreeIter *iter, const gchar *new_text) +static void kb_change_iter_shortcut(KbData *kbdata, GtkTreeIter *iter, const gchar *new_text) { guint lkey; GdkModifierType lmods; gtk_accelerator_parse(new_text, &lkey, &lmods); - if (kb_find_duplicate(ui_widgets.prefs_dialog, iter, lkey, lmods, new_text)) + if (kb_find_duplicate(kbdata->store, ui_widgets.prefs_dialog, iter, lkey, lmods, new_text)) return; /* set the values here, because of the above check, setting it in * gtk_accelerator_parse would return a wrong key combination if it is duplicate */ - kb_set_shortcut(store, iter, lkey, lmods); + kb_set_shortcut(kbdata->store, iter, lkey, lmods); - edited = TRUE; + kbdata->edited = TRUE; } static void kb_cell_edited_cb(GtkCellRendererText *cellrenderertext, - gchar *path, gchar *new_text, gpointer user_data) + gchar *path, gchar *new_text, KbData *kbdata) { if (path != NULL && new_text != NULL) { GtkTreeIter iter; - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, path); - if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter)) + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(kbdata->store), &iter, path); + if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(kbdata->store), &iter)) return; /* ignore group items */ - kb_change_iter_shortcut(&iter, new_text); + kb_change_iter_shortcut(kbdata, &iter, new_text); } } -static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, gpointer user_data) +static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey *event, KbData *kbdata) { gchar *str; guint state; @@ -1416,20 +1412,20 @@ static gboolean kb_grab_key_dialog_key_press_cb(GtkWidget *dialog, GdkEventKey * str = gtk_accelerator_name(event->keyval, state); - gtk_label_set_text(GTK_LABEL(dialog_label), str); + gtk_label_set_text(GTK_LABEL(kbdata->dialog_label), str); g_free(str); return TRUE; } -static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, G_GNUC_UNUSED gpointer iter) +static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, KbData *kbdata) { if (response == GTK_RESPONSE_ACCEPT) { - const gchar *new_text = gtk_label_get_text(GTK_LABEL(dialog_label)); + const gchar *new_text = gtk_label_get_text(GTK_LABEL(kbdata->dialog_label)); - kb_change_iter_shortcut(&g_iter, new_text); + kb_change_iter_shortcut(kbdata, &kbdata->iter, new_text); } gtk_widget_destroy(dialog); } @@ -1437,7 +1433,7 @@ static void kb_grab_key_dialog_response_cb(GtkWidget *dialog, gint response, G_G /* test if the entered key combination is already used * returns true if cancelling duplicate */ -static gboolean kb_find_duplicate(GtkWidget *parent, GtkTreeIter *old_iter, +static gboolean kb_find_duplicate(GtkTreeStore *store, GtkWidget *parent, GtkTreeIter *old_iter, guint key, GdkModifierType mods, const gchar *shortcut) { GtkTreeModel *model = GTK_TREE_MODEL(store); -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] a8a6ef: Merge branch 'scintilla-update-350-pre'
by Colomban Wendling
10 Aug '14
10 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Sun, 10 Aug 2014 00:23:21 UTC Commit: a8a6ef7d131e49e1cc5ed843ebec3167fd7b018b
https://github.com/geany/geany/commit/a8a6ef7d131e49e1cc5ed843ebec3167fd7b0…
Log Message: ----------- Merge branch 'scintilla-update-350-pre' Modified Paths: -------------- data/filetypes.rust scintilla/Makefile.am scintilla/gtk/PlatGTK.cxx scintilla/gtk/ScintillaGTK.cxx scintilla/include/SciLexer.h scintilla/include/Scintilla.h scintilla/include/Scintilla.iface scintilla/lexers/LexHTML.cxx scintilla/lexers/LexMatlab.cxx scintilla/lexers/LexRuby.cxx scintilla/lexers/LexRust.cxx scintilla/lexlib/LexerModule.h scintilla/makefile.win32 scintilla/scintilla_changes.patch scintilla/src/CellBuffer.cxx scintilla/src/CellBuffer.h scintilla/src/ContractionState.cxx scintilla/src/ContractionState.h scintilla/src/Document.cxx scintilla/src/Document.h scintilla/src/EditModel.cxx scintilla/src/EditModel.h scintilla/src/EditView.cxx scintilla/src/EditView.h scintilla/src/Editor.cxx scintilla/src/Editor.h scintilla/src/LineMarker.cxx scintilla/src/MarginView.cxx scintilla/src/MarginView.h scintilla/src/PerLine.cxx scintilla/src/PerLine.h scintilla/src/PositionCache.cxx scintilla/src/PositionCache.h scintilla/src/RESearch.cxx scintilla/src/RESearch.h scintilla/src/ScintillaBase.cxx scintilla/src/ScintillaBase.h scintilla/src/Selection.cxx scintilla/src/Selection.h scintilla/src/ViewStyle.cxx scintilla/src/ViewStyle.h scintilla/version.txt src/highlighting.c src/highlightingmappings.h Modified: data/filetypes.rust 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -14,6 +14,9 @@ word4=type string=string_1 stringraw=string_2 character=character +bytestring=string_1 +bytestringraw=string_2 +bytecharacter=character operator=operator identifier=identifier_1 lifetime=parameter Modified: scintilla/Makefile.am 6 lines changed, 6 insertions(+), 0 deletions(-) =================================================================== @@ -97,6 +97,10 @@ src/Document.cxx \ src/Document.h \ src/Editor.cxx \ src/Editor.h \ +src/EditModel.cxx \ +src/EditModel.h \ +src/EditView.cxx \ +src/EditView.h \ src/ExternalLexer.cxx \ src/ExternalLexer.h \ src/FontQuality.h \ @@ -106,6 +110,8 @@ src/KeyMap.cxx \ src/KeyMap.h \ src/LineMarker.cxx \ src/LineMarker.h \ +src/MarginView.cxx \ +src/MarginView.h \ src/Partitioning.h \ src/PerLine.cxx \ src/PerLine.h \ Modified: scintilla/gtk/PlatGTK.cxx 12 lines changed, 10 insertions(+), 2 deletions(-) =================================================================== @@ -527,6 +527,7 @@ void SurfaceImpl::Release() { } bool SurfaceImpl::Initialised() { +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 8, 0) if (inited && context) { if (cairo_status(context) == CAIRO_STATUS_SUCCESS) { // Even when status is success, the target surface may have been @@ -543,6 +544,7 @@ bool SurfaceImpl::Initialised() { } return cairo_status(context) == CAIRO_STATUS_SUCCESS; } +#endif return inited; } @@ -1086,6 +1088,10 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION } clusterStart = clusterEnd; } + while (i < lenPositions) { + // If something failed, fill in rest of the positions + positions[i++] = clusterStart; + } PLATFORM_ASSERT(i == lenPositions); } } @@ -1799,6 +1805,7 @@ void ListBoxX::Select(int n) { } int ListBoxX::GetSelection() { + int index = -1; GtkTreeIter iter; GtkTreeModel *model; GtkTreeSelection *selection; @@ -1808,9 +1815,10 @@ int ListBoxX::GetSelection() { int *indices = gtk_tree_path_get_indices(path); // Don't free indices. if (indices) - return indices[0]; + index = indices[0]; + gtk_tree_path_free(path); } - return -1; + return index; } int ListBoxX::Find(const char *prefix) { Modified: scintilla/gtk/ScintillaGTK.cxx 284 lines changed, 208 insertions(+), 76 deletions(-) =================================================================== @@ -57,9 +57,13 @@ #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" +#include "EditModel.h" +#include "MarginView.h" +#include "EditView.h" #include "Editor.h" #include "AutoComplete.h" #include "ScintillaBase.h" +#include "UnicodeFromUTF8.h" #ifdef SCI_LEXER #include "ExternalLexer.h" @@ -186,13 +190,23 @@ class ScintillaGTK : public ScintillaBase { virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); private: virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); - virtual void SetTicking(bool on); + struct TimeThunk { + TickReason reason; + ScintillaGTK *scintilla; + guint timer; + TimeThunk() : reason(tickCaret), scintilla(NULL), timer(0) {} + }; + TimeThunk timers[tickDwell+1]; + virtual bool FineTickerAvailable(); + virtual bool FineTickerRunning(TickReason reason); + virtual void FineTickerStart(TickReason reason, int millis, int tolerance); + virtual void FineTickerCancel(TickReason reason); virtual bool SetIdle(bool on); virtual void SetMouseCapture(bool on); virtual bool HaveMouseCapture(); virtual bool PaintContains(PRectangle rc); void FullPaint(); - virtual PRectangle GetClientRectangle(); + virtual PRectangle GetClientRectangle() const; virtual void ScrollText(int linesToMove); virtual void SetVerticalScrollPos(); virtual void SetHorizontalScrollPos(); @@ -280,6 +294,9 @@ class ScintillaGTK : public ScintillaBase { static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis); void PreeditChangedThis(); static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis); + + bool KoreanIME(); + static void StyleSetText(GtkWidget *widget, GtkStyle *previous, void*); static void RealizeText(GtkWidget *widget, void*); static void Destroy(GObject *object); @@ -300,7 +317,7 @@ class ScintillaGTK : public ScintillaBase { gint x, gint y, GtkSelectionData *selection_data, guint info, guint time); static void DragDataGet(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time); - static gboolean TimeOut(ScintillaGTK *sciThis); + static gboolean TimeOut(TimeThunk *tt); static gboolean IdleCallback(ScintillaGTK *sciThis); static gboolean StyleIdle(ScintillaGTK *sciThis); virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo); @@ -624,22 +641,37 @@ void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internal } } +namespace { + +class PreEditString { +public: + gchar *str; + gint cursor_pos; + PangoAttrList *attrs; + + PreEditString(GtkIMContext *im_context) { + gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); + } + ~PreEditString() { + g_free(str); + pango_attr_list_unref(attrs); + } +}; + +} + gint ScintillaGTK::FocusInThis(GtkWidget *widget) { try { SetFocusState(true); if (im_context != NULL) { - gchar *str = NULL; - gint cursor_pos; - - gtk_im_context_get_preedit_string(im_context, &str, NULL, &cursor_pos); + PreEditString pes(im_context); if (PWidget(wPreedit) != NULL) { - if (strlen(str) > 0) { + if (strlen(pes.str) > 0) { gtk_widget_show(PWidget(wPreedit)); } else { gtk_widget_hide(PWidget(wPreedit)); } } - g_free(str); gtk_im_context_focus_in(im_context); } @@ -829,11 +861,16 @@ void ScintillaGTK::Initialise() { caret.period = 0; } - SetTicking(true); + for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) { + timers[tr].reason = tr; + timers[tr].scintilla = this; + } } void ScintillaGTK::Finalise() { - SetTicking(false); + for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) { + FineTickerCancel(tr); + } ScintillaBase::Finalise(); } @@ -1024,17 +1061,27 @@ sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) { return 0; } -void ScintillaGTK::SetTicking(bool on) { - if (timer.ticking != on) { - timer.ticking = on; - if (timer.ticking) { - timer.tickerID = reinterpret_cast<TickerID>(g_timeout_add(timer.tickSize, - reinterpret_cast<GSourceFunc>(TimeOut), this)); - } else { - g_source_remove(GPOINTER_TO_UINT(timer.tickerID)); - } +/** +* Report that this Editor subclass has a working implementation of FineTickerStart. +*/ +bool ScintillaGTK::FineTickerAvailable() { + return true; +} + +bool ScintillaGTK::FineTickerRunning(TickReason reason) { + return timers[reason].timer != 0; +} + +void ScintillaGTK::FineTickerStart(TickReason reason, int millis, int /* tolerance */) { + FineTickerCancel(reason); + timers[reason].timer = g_timeout_add(millis, reinterpret_cast<GSourceFunc>(TimeOut), &timers[reason]); +} + +void ScintillaGTK::FineTickerCancel(TickReason reason) { + if (timers[reason].timer) { + g_source_remove(timers[reason].timer); + timers[reason].timer = 0; } - timer.ticksToWait = caret.period; } bool ScintillaGTK::SetIdle(bool on) { @@ -1121,8 +1168,9 @@ void ScintillaGTK::FullPaint() { wText.InvalidateAll(); } -PRectangle ScintillaGTK::GetClientRectangle() { - PRectangle rc = wMain.GetClientPosition(); +PRectangle ScintillaGTK::GetClientRectangle() const { + Window &win = const_cast<Window &>(wMain); + PRectangle rc = win.GetClientPosition(); if (verticalScrollBarVisible) rc.right -= verticalScrollBarWidth; if (horizontalScrollBarVisible && !Wrapping()) @@ -2220,19 +2268,13 @@ gboolean ScintillaGTK::KeyRelease(GtkWidget *widget, GdkEventKey *event) { gboolean ScintillaGTK::DrawPreeditThis(GtkWidget *widget, cairo_t *cr) { try { - gchar *str; - gint cursor_pos; - PangoAttrList *attrs; - - gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); - PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); - pango_layout_set_attributes(layout, attrs); + PreEditString pes(im_context); + PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); + pango_layout_set_attributes(layout, pes.attrs); cairo_move_to(cr, 0, 0); pango_cairo_show_layout(cr, layout); - g_free(str); - pango_attr_list_unref(attrs); g_object_unref(layout); } catch (...) { errorStatus = SC_STATUS_FAILURE; @@ -2248,20 +2290,14 @@ gboolean ScintillaGTK::DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) { try { - gchar *str; - gint cursor_pos; - PangoAttrList *attrs; - - gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); - PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); - pango_layout_set_attributes(layout, attrs); + PreEditString pes(im_context); + PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); + pango_layout_set_attributes(layout, pes.attrs); cairo_t *context = gdk_cairo_create(reinterpret_cast<GdkDrawable *>(WindowFromWidget(widget))); cairo_move_to(context, 0, 0); pango_cairo_show_layout(context, layout); cairo_destroy(context); - g_free(str); - pango_attr_list_unref(attrs); g_object_unref(layout); } catch (...) { errorStatus = SC_STATUS_FAILURE; @@ -2275,9 +2311,43 @@ gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, Sci #endif +bool ScintillaGTK::KoreanIME() { + // Warn : for KoreanIME use only. + if (pdoc->TentativeActive()) { + return true; + } + + bool koreanIME = false; + PreEditString utfval(im_context); + + // Only need to check if the first preedit char is Korean. + // The rest will be handled in TentativeActive() + // which can handle backspace and CJK commons and so forth. + + if (strlen(utfval.str) == 3) { // One hangul char has 3byte. + int unicode = UnicodeFromUTF8(reinterpret_cast<unsigned char *>(utfval.str)); + // Korean character ranges which are used for the first preedit chars. + //
http://www.programminginkorean.com/programming/hangul-in-unicode/
+ bool HangulJamo = (0x1100 <= unicode && unicode <= 0x11FF); + bool HangulCompatibleJamo = (0x3130 <= unicode && unicode <= 0x318F); + bool HangulJamoExtendedA = (0xA960 <= unicode && unicode <= 0xA97F); + bool HangulJamoExtendedB = (0xD7B0 <= unicode && unicode <= 0xD7FF); + bool HangulSyllable = (0xAC00 <= unicode && unicode <= 0xD7A3); + koreanIME = (HangulJamo | HangulCompatibleJamo | HangulSyllable + | HangulJamoExtendedA | HangulJamoExtendedB); + } + return koreanIME; +} + void ScintillaGTK::CommitThis(char *utfVal) { try { //~ fprintf(stderr, "Commit '%s'\n", utfVal); + if (pdoc->TentativeActive()) { + pdoc->TentativeUndo(); + } + + view.imeCaretBlockOverride = false; + if (IsUnicodeMode()) { AddCharUTF(utfVal, strlen(utfVal)); } else { @@ -2285,7 +2355,7 @@ void ScintillaGTK::CommitThis(char *utfVal) { if (*source) { Converter conv(source, "UTF-8", true); if (conv) { - char localeVal[4] = "\0\0\0"; + char localeVal[maxLenInputIME * 2]; char *pin = utfVal; size_t inLeft = strlen(utfVal); char *pout = localeVal; @@ -2293,15 +2363,14 @@ void ScintillaGTK::CommitThis(char *utfVal) { size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft); if (conversions != ((size_t)(-1))) { *pout = '\0'; - for (int i = 0; localeVal[i]; i++) { - AddChar(localeVal[i]); - } + AddCharUTF(localeVal, strlen(localeVal)); } else { fprintf(stderr, "Conversion failed '%s'\n", utfVal); } } } } + ShowCaretAtCurrentPosition(); } catch (...) { errorStatus = SC_STATUS_FAILURE; } @@ -2313,36 +2382,99 @@ void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) { void ScintillaGTK::PreeditChangedThis() { try { - gchar *str; - PangoAttrList *attrs; - gint cursor_pos; - gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); - if (strlen(str) > 0) { - PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); - pango_layout_set_attributes(layout, attrs); - - gint w, h; - pango_layout_get_pixel_size(layout, &w, &h); - g_object_unref(layout); - - gint x, y; - gdk_window_get_origin(PWindow(wText), &x, &y); - - Point pt = PointMainCaret(); - if (pt.x < 0) - pt.x = 0; - if (pt.y < 0) - pt.y = 0; - - gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y); - gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h); - gtk_widget_show(PWidget(wPreedit)); - gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h); - } else { - gtk_widget_hide(PWidget(wPreedit)); + if (KoreanIME()) { + // Copy & paste by johnsonj. + // Great thanks to + // jiniya from
http://www.jiniya.net/tt/494
for DBCS input with AddCharUTF(). + // BLUEnLIVE from
http://zockr.tistory.com/1118
for UNDO and inOverstrike. + view.imeCaretBlockOverride = false; // If backspace. + + if (pdoc->TentativeActive()) { + pdoc->TentativeUndo(); + } else { + // No tentative undo means start of this composition so + // fill in any virtual spaces. + bool tmpOverstrike = inOverstrike; + inOverstrike = false; // Not allowed to be deleted twice. + AddCharUTF("", 0); + inOverstrike = tmpOverstrike; + } + + PreEditString utfval(im_context); + + if (strlen(utfval.str) > maxLenInputIME * 3) { + return; // Do not allow over 200 chars. + } + + char localeVal[maxLenInputIME * 2]; + char *hanval = (char *)""; + + if (IsUnicodeMode()) { + hanval = utfval.str; + } else { + const char *source = CharacterSetID(); + if (*source) { + Converter conv(source, "UTF-8", true); + if (conv) { + char *pin = utfval.str; + size_t inLeft = strlen(utfval.str); + char *pout = localeVal; + size_t outLeft = sizeof(localeVal); + size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft); + if (conversions != ((size_t)(-1))) { + *pout = '\0'; + hanval = localeVal; + } else { + fprintf(stderr, "Conversion failed '%s'\n", utfval.str); + } + } + } + } + + if (!pdoc->TentativeActive()) { + pdoc->TentativeStart(); + } + + bool tmpRecordingMacro = recordingMacro; + recordingMacro = false; + int hanlen = strlen(hanval); + AddCharUTF(hanval, hanlen); + recordingMacro = tmpRecordingMacro; + + // For block caret which means KoreanIME is in composition. + view.imeCaretBlockOverride = true; + for (size_t r = 0; r < sel.Count(); r++) { + int positionInsert = sel.Range(r).Start().Position(); + sel.Range(r).caret.SetPosition(positionInsert - hanlen); + sel.Range(r).anchor.SetPosition(positionInsert - hanlen); + } + } else { // Original code follows for other IMEs. + PreEditString pes(im_context); + if (strlen(pes.str) > 0) { + PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); + pango_layout_set_attributes(layout, pes.attrs); + + gint w, h; + pango_layout_get_pixel_size(layout, &w, &h); + g_object_unref(layout); + + gint x, y; + gdk_window_get_origin(PWindow(wText), &x, &y); + + Point pt = PointMainCaret(); + if (pt.x < 0) + pt.x = 0; + if (pt.y < 0) + pt.y = 0; + + gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y); + gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h); + gtk_widget_show(PWidget(wPreedit)); + gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h); + } else { + gtk_widget_hide(PWidget(wPreedit)); + } } - g_free(str); - pango_attr_list_unref(attrs); } catch (...) { errorStatus = SC_STATUS_FAILURE; } @@ -2711,8 +2843,8 @@ void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context, } } -int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) { - sciThis->Tick(); +int ScintillaGTK::TimeOut(TimeThunk *tt) { + tt->scintilla->TickFor(tt->reason); return 1; } Modified: scintilla/include/SciLexer.h 18 lines changed, 18 insertions(+), 0 deletions(-) =================================================================== @@ -127,6 +127,7 @@ #define SCLEX_DMAP 112 #define SCLEX_AS 113 #define SCLEX_DMIS 114 +#define SCLEX_REGISTRY 115 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 @@ -906,6 +907,7 @@ #define SCE_KIX_KEYWORD 7 #define SCE_KIX_FUNCTIONS 8 #define SCE_KIX_OPERATOR 9 +#define SCE_KIX_COMMENTSTREAM 10 #define SCE_KIX_IDENTIFIER 31 #define SCE_GC_DEFAULT 0 #define SCE_GC_COMMENTLINE 1 @@ -1692,6 +1694,9 @@ #define SCE_RUST_LIFETIME 18 #define SCE_RUST_MACRO 19 #define SCE_RUST_LEXERROR 20 +#define SCE_RUST_BYTESTRING 21 +#define SCE_RUST_BYTESTRINGR 22 +#define SCE_RUST_BYTECHARACTER 23 #define SCE_DMAP_DEFAULT 0 #define SCE_DMAP_COMMENT 1 #define SCE_DMAP_NUMBER 2 @@ -1713,6 +1718,19 @@ #define SCE_DMIS_UNSUPPORTED_MAJOR 7 #define SCE_DMIS_UNSUPPORTED_MINOR 8 #define SCE_DMIS_LABEL 9 +#define SCE_REG_DEFAULT 0 +#define SCE_REG_COMMENT 1 +#define SCE_REG_VALUENAME 2 +#define SCE_REG_STRING 3 +#define SCE_REG_HEXDIGIT 4 +#define SCE_REG_VALUETYPE 5 +#define SCE_REG_ADDEDKEY 6 +#define SCE_REG_DELETEDKEY 7 +#define SCE_REG_ESCAPED 8 +#define SCE_REG_KEYPATH_GUID 9 +#define SCE_REG_STRING_GUID 10 +#define SCE_REG_PARAMETER 11 +#define SCE_REG_OPERATOR 12 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ #endif Modified: scintilla/include/Scintilla.h 15 lines changed, 12 insertions(+), 3 deletions(-) =================================================================== @@ -18,9 +18,9 @@ extern "C" { #if defined(_WIN32) /* Return false on failure: */ int Scintilla_RegisterClasses(void *hInstance); -int Scintilla_ReleaseResources(); +int Scintilla_ReleaseResources(void); #endif -int Scintilla_LinkLexers(); +int Scintilla_LinkLexers(void); #ifdef __cplusplus } @@ -92,6 +92,9 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_SETBUFFEREDDRAW 2035 #define SCI_SETTABWIDTH 2036 #define SCI_GETTABWIDTH 2121 +#define SCI_CLEARTABSTOPS 2675 +#define SCI_ADDTABSTOP 2676 +#define SCI_GETNEXTTABSTOP 2677 #define SC_CP_UTF8 65001 #define SCI_SETCODEPAGE 2037 #define MARKER_MAX 31 @@ -517,6 +520,11 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_APPENDTEXT 2282 #define SCI_GETTWOPHASEDRAW 2283 #define SCI_SETTWOPHASEDRAW 2284 +#define SC_PHASES_ONE 0 +#define SC_PHASES_TWO 1 +#define SC_PHASES_MULTIPLE 2 +#define SCI_GETPHASESDRAW 2673 +#define SCI_SETPHASESDRAW 2674 #define SC_EFF_QUALITY_MASK 0xF #define SC_EFF_QUALITY_DEFAULT 0 #define SC_EFF_QUALITY_NON_ANTIALIASED 1 @@ -952,7 +960,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_MOD_CONTAINER 0x40000 #define SC_MOD_LEXERSTATE 0x80000 #define SC_MOD_INSERTCHECK 0x100000 -#define SC_MODEVENTMASKALL 0x1FFFFF +#define SC_MOD_CHANGETABSTOPS 0x200000 +#define SC_MODEVENTMASKALL 0x3FFFFF #define SC_UPDATE_CONTENT 0x1 #define SC_UPDATE_SELECTION 0x2 #define SC_UPDATE_V_SCROLL 0x4 Modified: scintilla/include/Scintilla.iface 48 lines changed, 46 insertions(+), 2 deletions(-) =================================================================== @@ -226,6 +226,15 @@ set void SetTabWidth=2036(int tabWidth,) # Retrieve the visible size of a tab. get int GetTabWidth=2121(,) +# Clear explicit tabstops on a line. +fun void ClearTabStops=2675(int line,) + +# Add an explicit tab stop for a line. +fun void AddTabStop=2676(int line, int x) + +# Find the next explicit tab stop position on a line after a position. +fun int GetNextTabStop=2677(int line, int x) + # The SC_CP_UTF8 value can be used to enter Unicode mode. # This is the same value as CP_UTF8 in Windows val SC_CP_UTF8=65001 @@ -1291,13 +1300,27 @@ get bool GetVScrollBar=2281(,) # Append a string to the end of the document without changing the selection. fun void AppendText=2282(int length, string text) -# Is drawing done in two phases with backgrounds drawn before faoregrounds? +# Is drawing done in two phases with backgrounds drawn before foregrounds? get bool GetTwoPhaseDraw=2283(,) # In twoPhaseDraw mode, drawing is performed in two phases, first the background # and then the foreground. This avoids chopping off characters that overlap the next run. set void SetTwoPhaseDraw=2284(bool twoPhase,) +enu FontQuality=SC_PHASES_ +val SC_PHASES_ONE=0 +val SC_PHASES_TWO=1 +val SC_PHASES_MULTIPLE=2 + +# How many phases is drawing done in? +get int GetPhasesDraw=2673(,) + +# In one phase draw, text is drawn in a series of rectangular blocks with no overlap. +# In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally. +# In multiple phase draw, each element is drawn over the whole drawing area, allowing text +# to overlap from one line to the next. +set void SetPhasesDraw=2674(int phases,) + # Control font anti-aliasing. enu FontQuality=SC_EFF_ @@ -2509,7 +2532,8 @@ val SC_MOD_CHANGEANNOTATION=0x20000 val SC_MOD_CONTAINER=0x40000 val SC_MOD_LEXERSTATE=0x80000 val SC_MOD_INSERTCHECK=0x100000 -val SC_MODEVENTMASKALL=0x1FFFFF +val SC_MOD_CHANGETABSTOPS=0x200000 +val SC_MODEVENTMASKALL=0x3FFFFF enu Update=SC_UPDATE_ val SC_UPDATE_CONTENT=0x1 @@ -2675,6 +2699,7 @@ val SCLEX_RUST=111 val SCLEX_DMAP=112 val SCLEX_AS=113 val SCLEX_DMIS=114 +val SCLEX_REGISTRY=115 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -3567,6 +3592,7 @@ val SCE_KIX_MACRO=6 val SCE_KIX_KEYWORD=7 val SCE_KIX_FUNCTIONS=8 val SCE_KIX_OPERATOR=9 +val SCE_KIX_COMMENTSTREAM=10 val SCE_KIX_IDENTIFIER=31 # Lexical states for SCLEX_GUI4CLI lex Gui4Cli=SCLEX_GUI4CLI SCE_GC_ @@ -4443,6 +4469,9 @@ val SCE_RUST_IDENTIFIER=17 val SCE_RUST_LIFETIME=18 val SCE_RUST_MACRO=19 val SCE_RUST_LEXERROR=20 +val SCE_RUST_BYTESTRING=21 +val SCE_RUST_BYTESTRINGR=22 +val SCE_RUST_BYTECHARACTER=23 # Lexical states for SCLEX_DMAP lex DMAP=SCLEX_DMAP SCE_DMAP_ val SCE_DMAP_DEFAULT=0 @@ -4468,6 +4497,21 @@ val SCE_DMIS_MINORWORD=6 val SCE_DMIS_UNSUPPORTED_MAJOR=7 val SCE_DMIS_UNSUPPORTED_MINOR=8 val SCE_DMIS_LABEL=9 +# Lexical states for SCLEX_REGISTRY +lex REG=SCLEX_REGISTRY SCE_REG_ +val SCE_REG_DEFAULT=0 +val SCE_REG_COMMENT=1 +val SCE_REG_VALUENAME=2 +val SCE_REG_STRING=3 +val SCE_REG_HEXDIGIT=4 +val SCE_REG_VALUETYPE=5 +val SCE_REG_ADDEDKEY=6 +val SCE_REG_DELETEDKEY=7 +val SCE_REG_ESCAPED=8 +val SCE_REG_KEYPATH_GUID=9 +val SCE_REG_STRING_GUID=10 +val SCE_REG_PARAMETER=11 +val SCE_REG_OPERATOR=12 # Events Modified: scintilla/lexers/LexHTML.cxx 12 lines changed, 10 insertions(+), 2 deletions(-) =================================================================== @@ -822,19 +822,27 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty // handle start of Mako comment line if (isMako && ch == '#' && chNext == '#') { makoComment = 1; + state = SCE_HP_COMMENTLINE; } // handle end of Mako comment line else if (isMako && makoComment && (ch == '\r' || ch == '\n')) { makoComment = 0; - styler.ColourTo(i, SCE_HP_COMMENTLINE); - state = SCE_HP_DEFAULT; + styler.ColourTo(i, StateToPrint); + if (scriptLanguage == eScriptPython) { + state = SCE_HP_DEFAULT; + } else { + state = SCE_H_DEFAULT; + } } // Allow falling through to mako handling code if newline is going to end a block if (((ch == '\r' && chNext != '\n') || (ch == '\n')) && (!isMako || (0 != strcmp(makoBlockType, "%")))) { } + // Ignore everything in mako comment until the line ends + else if (isMako && makoComment) { + } // generic end of script processing else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) { Modified: scintilla/lexers/LexMatlab.cxx 5 lines changed, 4 insertions(+), 1 deletions(-) =================================================================== @@ -12,6 +12,9 @@ ** - added ... displayed as a comment ** - removed unused IsAWord functions ** - added some comments + ** + ** Changes by John Donoghue 2014/08/01 + ** - fix allowed transpose ' after {} operator **/ // Copyright 1998-2001 by Neil Hodgson <neilh(a)scintilla.org> // The License.txt file describes the conditions under which this software may be distributed. @@ -218,7 +221,7 @@ static void ColouriseMatlabOctaveDoc( } else if (isalpha(sc.ch)) { sc.SetState(SCE_MATLAB_KEYWORD); } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '\\') { - if (sc.ch == ')' || sc.ch == ']') { + if (sc.ch == ')' || sc.ch == ']' || sc.ch == '}') { transpose = true; } else { transpose = false; Modified: scintilla/lexers/LexRuby.cxx 36 lines changed, 35 insertions(+), 1 deletions(-) =================================================================== @@ -882,6 +882,31 @@ static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle, preferRE = false; } else if (isSafeWordcharOrHigh(chNext)) { state = SCE_RB_SYMBOL; + } else if ((chNext == '@' || chNext == '$') && + isSafeWordcharOrHigh(chNext2)) { + // instance and global variable followed by an identifier + advance_char(i, ch, chNext, chNext2); + state = SCE_RB_SYMBOL; + } else if (((chNext == '@' && chNext2 == '@') || + (chNext == '$' && chNext2 == '-')) && + isSafeWordcharOrHigh(styler.SafeGetCharAt(i+3))) { + // class variables and special global variable "$-IDENTCHAR" + state = SCE_RB_SYMBOL; + // $-IDENTCHAR doesn't continue past the IDENTCHAR + if (chNext == '$') { + styler.ColourTo(i+3, SCE_RB_SYMBOL); + state = SCE_RB_DEFAULT; + } + i += 3; + ch = styler.SafeGetCharAt(i); + chNext = styler.SafeGetCharAt(i+1); + } else if (chNext == '$' && strchr("_~*$?!(a)/\\;,.=:<>\"&`'+", chNext2)) { + // single-character special global variables + i += 2; + ch = chNext2; + chNext = styler.SafeGetCharAt(i+1); + styler.ColourTo(i, SCE_RB_SYMBOL); + state = SCE_RB_DEFAULT; } else if (strchr("[*!~+-*/%=<>&^|", chNext)) { // Do the operator analysis in-line, looking ahead // Based on the table in pickaxe 2nd ed., page 339 @@ -1260,7 +1285,16 @@ static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle, } else if (state == SCE_RB_CLASS_VAR || state == SCE_RB_INSTANCE_VAR || state == SCE_RB_SYMBOL) { - if (!isSafeWordcharOrHigh(ch)) { + if (state == SCE_RB_SYMBOL && + // FIDs suffices '?' and '!' + (((ch == '!' || ch == '?') && chNext != '=') || + // identifier suffix '=' + (ch == '=' && (chNext != '~' && chNext != '>' && + (chNext != '=' || chNext2 == '>'))))) { + styler.ColourTo(i, state); + state = SCE_RB_DEFAULT; + preferRE = false; + } else if (!isSafeWordcharOrHigh(ch)) { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref preferRE = false; Modified: scintilla/lexers/LexRust.cxx 105 lines changed, 69 insertions(+), 36 deletions(-) =================================================================== @@ -230,7 +230,9 @@ static void ScanIdentifier(Accessor& styler, int& pos, WordList *keywords) { } } -static void ScanDigits(Accessor& styler, int& pos, int base) { +/* Scans a sequence of digits, returning true if it found any. */ +static bool ScanDigits(Accessor& styler, int& pos, int base) { + int old_pos = pos; for (;;) { int c = styler.SafeGetCharAt(pos, '\0'); if (IsADigit(c, base) || c == '_') @@ -238,13 +240,17 @@ static void ScanDigits(Accessor& styler, int& pos, int base) { else break; } + return old_pos != pos; } +/* Scans an integer and floating point literals. */ static void ScanNumber(Accessor& styler, int& pos) { int base = 10; int c = styler.SafeGetCharAt(pos, '\0'); int n = styler.SafeGetCharAt(pos + 1, '\0'); bool error = false; + /* Scan the prefix, thus determining the base. + * 10 is default if there's no prefix. */ if (c == '0' && n == 'x') { pos += 2; base = 16; @@ -255,8 +261,11 @@ static void ScanNumber(Accessor& styler, int& pos) { pos += 2; base = 8; } - int old_pos = pos; - ScanDigits(styler, pos, base); + + /* Scan initial digits. The literal is malformed if there are none. */ + error |= !ScanDigits(styler, pos, base); + /* See if there's an integer suffix. We mimic the Rust's lexer + * and munch it even if there was an error above. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'u' || c == 'i') { pos++; @@ -271,14 +280,22 @@ static void ScanNumber(Accessor& styler, int& pos) { } else if (c == '6' && n == '4') { pos += 2; } - } else { + /* See if it's a floating point literal. These literals have to be base 10. + */ + } else if (!error) { + /* If there's a period, it's a floating point literal unless it's + * followed by an identifier (meaning this is a method call, e.g. + * `1.foo()`) or another period, in which case it's a range (e.g. 1..2) + */ n = styler.SafeGetCharAt(pos + 1, '\0'); if (c == '.' && !(IsIdentifierStart(n) || n == '.')) { error |= base != 10; pos++; + /* It's ok to have no digits after the period. */ ScanDigits(styler, pos, 10); } + /* Look for the exponentiation. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'e' || c == 'E') { error |= base != 10; @@ -286,13 +303,11 @@ static void ScanNumber(Accessor& styler, int& pos) { c = styler.SafeGetCharAt(pos, '\0'); if (c == '-' || c == '+') pos++; - int old_pos = pos; - ScanDigits(styler, pos, 10); - if (old_pos == pos) { - error = true; - } + /* It is invalid to have no digits in the exponent. */ + error |= !ScanDigits(styler, pos, 10); } + /* Scan the floating point suffix. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'f') { error |= base != 10; @@ -308,9 +323,7 @@ static void ScanNumber(Accessor& styler, int& pos) { } } } - if (old_pos == pos) { - error = true; - } + if (error) styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); else @@ -351,7 +364,7 @@ static bool IsValidCharacterEscape(int c) { } static bool IsValidStringEscape(int c) { - return IsValidCharacterEscape(c) || c == '\n'; + return IsValidCharacterEscape(c) || c == '\n' || c == '\r'; } static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool stop_asap) { @@ -373,12 +386,12 @@ static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool s /* This is overly permissive for character literals in order to accept UTF-8 encoded * character literals. */ -static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { +static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos, bool ascii_only) { pos++; int c = styler.SafeGetCharAt(pos, '\0'); int n = styler.SafeGetCharAt(pos + 1, '\0'); bool done = false; - bool valid_lifetime = IsIdentifierStart(c); + bool valid_lifetime = !ascii_only && IsIdentifierStart(c); bool valid_char = true; bool first = true; while (!done) { @@ -390,10 +403,10 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { } else if (n == 'x') { pos += 2; valid_char = ScanNumericEscape(styler, pos, 2, false); - } else if (n == 'u') { + } else if (n == 'u' && !ascii_only) { pos += 2; valid_char = ScanNumericEscape(styler, pos, 4, false); - } else if (n == 'U') { + } else if (n == 'U' && !ascii_only) { pos += 2; valid_char = ScanNumericEscape(styler, pos, 8, false); } else { @@ -412,7 +425,10 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { done = true; break; default: - if (!IsIdentifierContinue(c) && !first) { + if (ascii_only && !IsASCII((char)c)) { + done = true; + valid_char = false; + } else if (!IsIdentifierContinue(c) && !first) { done = true; } else { pos++; @@ -433,7 +449,7 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { styler.ColourTo(pos - 1, SCE_RUST_LIFETIME); } else if (valid_char) { pos++; - styler.ColourTo(pos - 1, SCE_RUST_CHARACTER); + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTECHARACTER : SCE_RUST_CHARACTER); } else { styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); } @@ -542,7 +558,7 @@ static void ScanComments(Accessor &styler, int& pos, int max) { ResumeBlockComment(styler, pos, max, UnknownComment, 1); } -static void ResumeString(Accessor &styler, int& pos, int max) { +static void ResumeString(Accessor &styler, int& pos, int max, bool ascii_only) { int c = styler.SafeGetCharAt(pos, '\0'); bool error = false; while (c != '"' && !error) { @@ -559,10 +575,10 @@ static void ResumeString(Accessor &styler, int& pos, int max) { } else if (n == 'x') { pos += 2; error = !ScanNumericEscape(styler, pos, 2, true); - } else if (n == 'u') { + } else if (n == 'u' && !ascii_only) { pos += 2; error = !ScanNumericEscape(styler, pos, 4, true); - } else if (n == 'U') { + } else if (n == 'U' && !ascii_only) { pos += 2; error = !ScanNumericEscape(styler, pos, 8, true); } else { @@ -570,16 +586,19 @@ static void ResumeString(Accessor &styler, int& pos, int max) { error = true; } } else { - pos++; + if (ascii_only && !IsASCII((char)c)) + error = true; + else + pos++; } c = styler.SafeGetCharAt(pos, '\0'); } if (!error) pos++; - styler.ColourTo(pos - 1, SCE_RUST_STRING); + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRING : SCE_RUST_STRING); } -static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes) { +static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes, bool ascii_only) { for (;;) { if (pos == styler.LineEnd(styler.GetLine(pos))) styler.SetLineState(styler.GetLine(pos), num_hashes); @@ -594,19 +613,20 @@ static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes) } if (trailing_num_hashes == num_hashes) { styler.SetLineState(styler.GetLine(pos), 0); - styler.ColourTo(pos - 1, SCE_RUST_STRINGR); break; } } else if (pos >= max) { - styler.ColourTo(pos - 1, SCE_RUST_STRINGR); break; - } else { + } else { + if (ascii_only && !IsASCII((char)c)) + break; pos++; } } + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRINGR : SCE_RUST_STRINGR); } -static void ScanRawString(Accessor &styler, int& pos, int max) { +static void ScanRawString(Accessor &styler, int& pos, int max, bool ascii_only) { pos++; int num_hashes = 0; while (styler.SafeGetCharAt(pos, '\0') == '#') { @@ -617,7 +637,7 @@ static void ScanRawString(Accessor &styler, int& pos, int max) { styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); } else { pos++; - ResumeRawString(styler, pos, max, num_hashes); + ResumeRawString(styler, pos, max, num_hashes, ascii_only); } } @@ -635,9 +655,13 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, } else if (initStyle == SCE_RUST_COMMENTLINE || initStyle == SCE_RUST_COMMENTLINEDOC) { ResumeLineComment(styler, pos, max, initStyle == SCE_RUST_COMMENTLINEDOC ? DocComment : NotDocComment); } else if (initStyle == SCE_RUST_STRING) { - ResumeString(styler, pos, max); + ResumeString(styler, pos, max, false); + } else if (initStyle == SCE_RUST_BYTESTRING) { + ResumeString(styler, pos, max, true); } else if (initStyle == SCE_RUST_STRINGR) { - ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1)); + ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), false); + } else if (initStyle == SCE_RUST_BYTESTRINGR) { + ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), true); } while (pos < max) { @@ -645,7 +669,7 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, int n = styler.SafeGetCharAt(pos + 1, '\0'); int n2 = styler.SafeGetCharAt(pos + 2, '\0'); - if (pos == 0 && c == '#' && n == '!') { + if (pos == 0 && c == '#' && n == '!' && n2 != '[') { pos += 2; ResumeLineComment(styler, pos, max, NotDocComment); } else if (IsWhitespace(c)) { @@ -653,7 +677,16 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, } else if (c == '/' && (n == '/' || n == '*')) { ScanComments(styler, pos, max); } else if (c == 'r' && (n == '#' || n == '"')) { - ScanRawString(styler, pos, max); + ScanRawString(styler, pos, max, false); + } else if (c == 'b' && n == 'r' && (n2 == '#' || n2 == '"')) { + pos++; + ScanRawString(styler, pos, max, true); + } else if (c == 'b' && n == '"') { + pos += 2; + ResumeString(styler, pos, max, true); + } else if (c == 'b' && n == '\'') { + pos++; + ScanCharacterLiteralOrLifetime(styler, pos, true); } else if (IsIdentifierStart(c)) { ScanIdentifier(styler, pos, keywords); } else if (IsADigit(c)) { @@ -668,10 +701,10 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, pos++; styler.ColourTo(pos - 1, SCE_RUST_OPERATOR); } else if (c == '\'') { - ScanCharacterLiteralOrLifetime(styler, pos); + ScanCharacterLiteralOrLifetime(styler, pos, false); } else if (c == '"') { pos++; - ResumeString(styler, pos, max); + ResumeString(styler, pos, max, false); } else { pos++; styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); Modified: scintilla/lexlib/LexerModule.h 7 lines changed, 6 insertions(+), 1 deletions(-) =================================================================== @@ -67,7 +67,12 @@ inline int Maximum(int a, int b) { // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER -#pragma warning(disable: 4244 4309) +#pragma warning(disable: 4244 4309 4456 4457) +#endif + +// Turn off shadow warnings for lexers as may be maintained by others +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wshadow" #endif #ifdef SCI_NAMESPACE Modified: scintilla/makefile.win32 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -130,10 +130,13 @@ SRCOBJS=\ Decoration.o \ Document.o \ Editor.o \ + EditModel.o \ + EditView.o \ ExternalLexer.o \ Indicator.o \ KeyMap.o \ LineMarker.o \ + MarginView.o \ PerLine.o \ PositionCache.o \ RESearch.o \ Modified: scintilla/scintilla_changes.patch 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -31,7 +31,7 @@ diff --git b/scintilla/src/Catalogue.cxx a/scintilla/src/Catalogue.cxx index 41d5d54..70ce3bc 100644 --- scintilla/src/Catalogue.cxx +++ scintilla/src/Catalogue.cxx -@@ -76,115 +76,48 @@ int Scintilla_LinkLexers() { +@@ -76,116 +76,48 @@ int Scintilla_LinkLexers() { //++Autogenerated -- run scripts/LexGen.py to regenerate //**\(\tLINK_LEXER(\*);\n\) @@ -123,6 +123,7 @@ index 41d5d54..70ce3bc 100644 LINK_LEXER(lmPython); LINK_LEXER(lmR); - LINK_LEXER(lmREBOL); +- LINK_LEXER(lmRegistry); LINK_LEXER(lmRuby); LINK_LEXER(lmRust); - LINK_LEXER(lmScriptol); Modified: scintilla/src/CellBuffer.cxx 40 lines changed, 39 insertions(+), 1 deletions(-) =================================================================== @@ -144,6 +144,7 @@ UndoHistory::UndoHistory() { currentAction = 0; undoSequenceDepth = 0; savePoint = 0; + tentativePoint = -1; actions[currentAction].Create(startAction); } @@ -194,7 +195,7 @@ const char *UndoHistory::AppendAction(actionType at, int position, const char *d // Visual Studio 2013 Code Analysis wrongly believes actions can be NULL at its next reference __analysis_assume(actions); #endif - if (currentAction == savePoint) { + if ((currentAction == savePoint) || (currentAction == tentativePoint)) { currentAction++; } else if (!actions[currentAction].mayCoalesce) { // Not allowed to coalesce if this set @@ -282,6 +283,7 @@ void UndoHistory::DeleteUndoHistory() { currentAction = 0; actions[currentAction].Create(startAction); savePoint = 0; + tentativePoint = -1; } void UndoHistory::SetSavePoint() { @@ -292,6 +294,26 @@ bool UndoHistory::IsSavePoint() const { return savePoint == currentAction; } +void UndoHistory::TentativeStart() { + tentativePoint = currentAction; +} + +void UndoHistory::TentativeCommit() { + tentativePoint = -1; + // Truncate undo history + maxAction = currentAction; +} + +int UndoHistory::TentativeSteps() { + // Drop any trailing startAction + if (actions[currentAction].at == startAction && currentAction > 0) + currentAction--; + if (tentativePoint >= 0) + return currentAction - tentativePoint; + else + return -1; +} + bool UndoHistory::CanUndo() const { return (currentAction > 0) && (maxAction > 0); } @@ -505,6 +527,22 @@ bool CellBuffer::IsSavePoint() const { return uh.IsSavePoint(); } +void CellBuffer::TentativeStart() { + uh.TentativeStart(); +} + +void CellBuffer::TentativeCommit() { + uh.TentativeCommit(); +} + +int CellBuffer::TentativeSteps() { + return uh.TentativeSteps(); +} + +bool CellBuffer::TentativeActive() const { + return uh.TentativeActive(); +} + // Without undo void CellBuffer::InsertLine(int line, int position, bool lineStart) { Modified: scintilla/src/CellBuffer.h 12 lines changed, 12 insertions(+), 0 deletions(-) =================================================================== @@ -95,6 +95,7 @@ class UndoHistory { int currentAction; int undoSequenceDepth; int savePoint; + int tentativePoint; void EnsureUndoRoom(); @@ -117,6 +118,12 @@ class UndoHistory { void SetSavePoint(); bool IsSavePoint() const; + // Tentative actions are used for input composition so that it can be undone cleanly + void TentativeStart(); + void TentativeCommit(); + bool TentativeActive() const { return tentativePoint >= 0; } + int TentativeSteps(); + /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is /// called that many times. Similarly for redo. bool CanUndo() const; @@ -193,6 +200,11 @@ class CellBuffer { void SetSavePoint(); bool IsSavePoint() const; + void TentativeStart(); + void TentativeCommit(); + bool TentativeActive() const; + int TentativeSteps(); + bool SetUndoCollection(bool collectUndo); bool IsCollectingUndo() const; void BeginUndoAction(); Modified: scintilla/src/ContractionState.cxx 18 lines changed, 9 insertions(+), 9 deletions(-) =================================================================== @@ -150,8 +150,8 @@ bool ContractionState::GetVisible(int lineDoc) const { } } -bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) { - if (OneToOne() && visible_) { +bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool isVisible) { + if (OneToOne() && isVisible) { return false; } else { EnsureData(); @@ -159,9 +159,9 @@ bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible Check(); if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) { for (int line = lineDocStart; line <= lineDocEnd; line++) { - if (GetVisible(line) != visible_) { - int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line); - visible->SetValueAt(line, visible_ ? 1 : 0); + if (GetVisible(line) != isVisible) { + int difference = isVisible ? heights->ValueAt(line) : -heights->ValueAt(line); + visible->SetValueAt(line, isVisible ? 1 : 0); displayLines->InsertText(line, difference); delta += difference; } @@ -191,13 +191,13 @@ bool ContractionState::GetExpanded(int lineDoc) const { } } -bool ContractionState::SetExpanded(int lineDoc, bool expanded_) { - if (OneToOne() && expanded_) { +bool ContractionState::SetExpanded(int lineDoc, bool isExpanded) { + if (OneToOne() && isExpanded) { return false; } else { EnsureData(); - if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) { - expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0); + if (isExpanded != (expanded->ValueAt(lineDoc) == 1)) { + expanded->SetValueAt(lineDoc, isExpanded ? 1 : 0); Check(); return true; } else { Modified: scintilla/src/ContractionState.h 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -48,11 +48,11 @@ class ContractionState { void DeleteLines(int lineDoc, int lineCount); bool GetVisible(int lineDoc) const; - bool SetVisible(int lineDocStart, int lineDocEnd, bool visible); + bool SetVisible(int lineDocStart, int lineDocEnd, bool isVisible); bool HiddenLines() const; bool GetExpanded(int lineDoc) const; - bool SetExpanded(int lineDoc, bool expanded); + bool SetExpanded(int lineDoc, bool isExpanded); int ContractedNext(int lineDocStart) const; int GetHeight(int lineDoc) const; Modified: scintilla/src/Document.cxx 59 lines changed, 59 insertions(+), 0 deletions(-) =================================================================== @@ -209,6 +209,65 @@ void Document::SetSavePoint() { NotifySavePoint(true); } +void Document::TentativeUndo() { + CheckReadOnly(); + if (enteredModification == 0) { + enteredModification++; + if (!cb.IsReadOnly()) { + bool startSavePoint = cb.IsSavePoint(); + bool multiLine = false; + int steps = cb.TentativeSteps(); + //Platform::DebugPrintf("Steps=%d\n", steps); + for (int step = 0; step < steps; step++) { + const int prevLinesTotal = LinesTotal(); + const Action &action = cb.GetUndoStep(); + if (action.at == removeAction) { + NotifyModified(DocModification( + SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action)); + } else if (action.at == containerAction) { + DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO); + dm.token = action.position; + NotifyModified(dm); + } else { + NotifyModified(DocModification( + SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action)); + } + cb.PerformUndoStep(); + if (action.at != containerAction) { + ModifiedAt(action.position); + } + + int modFlags = SC_PERFORMED_UNDO; + // With undo, an insertion action becomes a deletion notification + if (action.at == removeAction) { + modFlags |= SC_MOD_INSERTTEXT; + } else if (action.at == insertAction) { + modFlags |= SC_MOD_DELETETEXT; + } + if (steps > 1) + modFlags |= SC_MULTISTEPUNDOREDO; + const int linesAdded = LinesTotal() - prevLinesTotal; + if (linesAdded != 0) + multiLine = true; + if (step == steps - 1) { + modFlags |= SC_LASTSTEPINUNDOREDO; + if (multiLine) + modFlags |= SC_MULTILINEUNDOREDO; + } + NotifyModified(DocModification(modFlags, action.position, action.lenData, + linesAdded, action.data)); + } + + bool endSavePoint = cb.IsSavePoint(); + if (startSavePoint != endSavePoint) + NotifySavePoint(endSavePoint); + + cb.TentativeCommit(); + } + enteredModification--; + } +} + int Document::GetMark(int line) { return static_cast<LineMarkers *>(perLineData[ldMarkers])->MarkValue(line); } Modified: scintilla/src/Document.h 8 lines changed, 7 insertions(+), 1 deletions(-) =================================================================== @@ -303,6 +303,12 @@ class Document : PerLine, public IDocumentWithLineEnd, public ILoader { void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); } void SetSavePoint(); bool IsSavePoint() const { return cb.IsSavePoint(); } + + void TentativeStart() { cb.TentativeStart(); } + void TentativeCommit() { cb.TentativeCommit(); } + void TentativeUndo(); + bool TentativeActive() const { return cb.TentativeActive(); } + const char * SCI_METHOD BufferPointer() { return cb.BufferPointer(); } const char *RangePointer(int position, int rangeLength) { return cb.RangePointer(position, rangeLength); } int GapPosition() const { return cb.GapPosition(); } @@ -368,7 +374,7 @@ class Document : PerLine, public IDocumentWithLineEnd, public ILoader { void SetDefaultCharClasses(bool includeWordClass); void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass); - int GetCharsOfClass(CharClassify::cc charClass, unsigned char *buffer); + int GetCharsOfClass(CharClassify::cc characterClass, unsigned char *buffer); void SCI_METHOD StartStyling(int position, char mask); bool SCI_METHOD SetStyleFor(int length, char style); bool SCI_METHOD SetStyles(int length, const char *styles); Modified: scintilla/src/EditModel.cxx 74 lines changed, 74 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,74 @@ +// Scintilla source code edit control +/** @file EditModel.cxx + ** Defines the editor state that must be visible to EditorView. + **/ +// Copyright 1998-2014 by Neil Hodgson <neilh(a)scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> +#include <ctype.h> + +#include <string> +#include <vector> +#include <map> +#include <algorithm> +#include <memory> + +#include "Platform.h" + +#include "ILexer.h" +#include "Scintilla.h" + +#include "StringCopy.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "CaseFolder.h" +#include "Document.h" +#include "UniConversion.h" +#include "Selection.h" +#include "PositionCache.h" +#include "EditModel.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +Caret::Caret() : + active(false), on(false), period(500) {} + +EditModel::EditModel() { + inOverstrike = false; + xOffset = 0; + trackLineWidth = false; + posDrag = SelectionPosition(invalidPosition); + braces[0] = invalidPosition; + braces[1] = invalidPosition; + bracesMatchStyle = STYLE_BRACEBAD; + highlightGuideColumn = 0; + primarySelection = true; + foldFlags = 0; + hotspot = Range(invalidPosition); + wrapWidth = LineLayout::wrapWidthInfinite; + pdoc = new Document(); + pdoc->AddRef(); +} + +EditModel::~EditModel() { + pdoc->Release(); + pdoc = 0; +} Modified: scintilla/src/EditModel.h 67 lines changed, 67 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,67 @@ +// Scintilla source code edit control +/** @file EditModel.h + ** Defines the editor state that must be visible to EditorView. + **/ +// Copyright 1998-2014 by Neil Hodgson <neilh(a)scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef EDITMODEL_H +#define EDITMODEL_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** +*/ +class Caret { +public: + bool active; + bool on; + int period; + + Caret(); +}; + +class EditModel { + // Private so EditModel objects can not be copied + EditModel(const EditModel &); + EditModel &operator=(const EditModel &); + +public: + bool inOverstrike; + int xOffset; ///< Horizontal scrolled amount in pixels + bool trackLineWidth; + + SpecialRepresentations reprs; + Caret caret; + SelectionPosition posDrag; + Position braces[2]; + int bracesMatchStyle; + int highlightGuideColumn; + Selection sel; + bool primarySelection; + + int foldFlags; + ContractionState cs; + // Hotspot support + Range hotspot; + + // Wrapping support + int wrapWidth; + + Document *pdoc; + + EditModel(); + virtual ~EditModel(); + virtual int TopLineOfMain() const = 0; + virtual Point GetVisibleOriginInMain() const = 0; + virtual int LinesOnScreen() const = 0; + virtual Range GetHotSpotRange() const = 0; +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif Modified: scintilla/src/EditView.cxx 2072 lines changed, 2072 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,2072 @@ +// Scintilla source code edit control +/** @file Editor.cxx + ** Defines the appearance of the main text area of the editor window. + **/ +// Copyright 1998-2014 by Neil Hodgson <neilh(a)scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> +#include <ctype.h> + +#include <string> +#include <vector> +#include <map> +#include <algorithm> +#include <memory> + +#include "Platform.h" + +#include "ILexer.h" +#include "Scintilla.h" + +#include "StringCopy.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "PerLine.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "CaseFolder.h" +#include "Document.h" +#include "UniConversion.h" +#include "Selection.h" +#include "PositionCache.h" +#include "EditModel.h" +#include "MarginView.h" +#include "EditView.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static inline bool IsControlCharacter(int ch) { + // iscntrl returns true for lots of chars > 127 which are displayable + return ch >= 0 && ch < ' '; +} + +PrintParameters::PrintParameters() { + magnification = 0; + colourMode = SC_PRINT_NORMAL; + wrapState = eWrapWord; +} + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) { + if (st.multipleStyles) { + for (size_t iStyle = 0; iStyle<st.length; iStyle++) { + if (!vs.ValidStyle(styleOffset + st.styles[iStyle])) + return false; + } + } else { + if (!vs.ValidStyle(styleOffset + st.style)) + return false; + } + return true; +} + +static int WidthStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, + const char *text, const unsigned char *styles, size_t len) { + int width = 0; + size_t start = 0; + while (start < len) { + size_t style = styles[start]; + size_t endSegment = start; + while ((endSegment + 1 < len) && (static_cast<size_t>(styles[endSegment + 1]) == style)) + endSegment++; + FontAlias fontText = vs.styles[style + styleOffset].font; + width += static_cast<int>(surface->WidthText(fontText, text + start, + static_cast<int>(endSegment - start + 1))); + start = endSegment + 1; + } + return width; +} + +int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) { + int widthMax = 0; + size_t start = 0; + while (start < st.length) { + size_t lenLine = st.LineLength(start); + int widthSubLine; + if (st.multipleStyles) { + widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); + } else { + FontAlias fontText = vs.styles[styleOffset + st.style].font; + widthSubLine = static_cast<int>(surface->WidthText(fontText, + st.text + start, static_cast<int>(lenLine))); + } + if (widthSubLine > widthMax) + widthMax = widthSubLine; + start += lenLine + 1; + } + return widthMax; +} + +void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, + const char *s, int len, DrawPhase phase) { + FontAlias fontText = style.font; + if (phase & drawBack) { + if (phase & drawText) { + // Drawing both + surface->DrawTextNoClip(rc, fontText, ybase, s, len, + style.fore, style.back); + } else { + surface->FillRectangle(rc, style.back); + } + } else if (phase & drawText) { + surface->DrawTextTransparent(rc, fontText, ybase, s, len, style.fore); + } +} + +void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, + const StyledText &st, size_t start, size_t length, DrawPhase phase) { + + if (st.multipleStyles) { + int x = static_cast<int>(rcText.left); + size_t i = 0; + while (i < length) { + size_t end = i; + size_t style = st.styles[i + start]; + while (end < length - 1 && st.styles[start + end + 1] == style) + end++; + style += styleOffset; + FontAlias fontText = vs.styles[style].font; + const int width = static_cast<int>(surface->WidthText(fontText, + st.text + start + i, static_cast<int>(end - i + 1))); + PRectangle rcSegment = rcText; + rcSegment.left = static_cast<XYPOSITION>(x); + rcSegment.right = static_cast<XYPOSITION>(x + width + 1); + DrawTextNoClipPhase(surface, rcSegment, vs.styles[style], + rcText.top + vs.maxAscent, st.text + start + i, + static_cast<int>(end - i + 1), phase); + x += width; + i = end + 1; + } + } else { + const size_t style = st.style + styleOffset; + DrawTextNoClipPhase(surface, rcText, vs.styles[style], + rcText.top + vs.maxAscent, st.text + start, + static_cast<int>(length), phase); + } +} + +#ifdef SCI_NAMESPACE +} +#endif + +const XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues + +EditView::EditView() { + ldTabstops = NULL; + hideSelection = false; + drawOverstrikeCaret = true; + bufferedDraw = true; + phasesDraw = phasesTwo; + lineWidthMaxSeen = 0; + additionalCaretsBlink = true; + additionalCaretsVisible = true; + imeCaretBlockOverride = false; + pixmapLine = 0; + pixmapIndentGuide = 0; + pixmapIndentGuideHighlight = 0; + llc.SetLevel(LineLayoutCache::llcCaret); + posCache.SetSize(0x400); +} + +EditView::~EditView() { + delete ldTabstops; + ldTabstops = NULL; +} + +bool EditView::SetTwoPhaseDraw(bool twoPhaseDraw) { + const PhasesDraw phasesDrawNew = twoPhaseDraw ? phasesTwo : phasesOne; + const bool redraw = phasesDraw != phasesDrawNew; + phasesDraw = phasesDrawNew; + return redraw; +} + +bool EditView::SetPhasesDraw(int phases) { + const PhasesDraw phasesDrawNew = static_cast<PhasesDraw>(phases); + const bool redraw = phasesDraw != phasesDrawNew; + phasesDraw = phasesDrawNew; + return redraw; +} + +bool EditView::LinesOverlap() const { + return phasesDraw == phasesMultiple; +} + +void EditView::ClearAllTabstops() { + delete ldTabstops; + ldTabstops = 0; +} + +int EditView::NextTabstopPos(int line, int x, int tabWidth) const { + int next = GetNextTabstop(line, x); + if (next > 0) + return next; + return ((((x + 2) / tabWidth) + 1) * tabWidth); +} + +bool EditView::ClearTabstops(int line) { + LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops); + return lt && lt->ClearTabstops(line); +} + +bool EditView::AddTabstop(int line, int x) { + if (!ldTabstops) { + ldTabstops = new LineTabstops(); + } + LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops); + return lt && lt->AddTabstop(line, x); +} + +int EditView::GetNextTabstop(int line, int x) const { + LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops); + if (lt) { + return lt->GetNextTabstop(line, x); + } else { + return 0; + } +} + +void EditView::LinesAddedOrRemoved(int lineOfPos, int linesAdded) { + if (ldTabstops) { + if (linesAdded > 0) { + for (int line = lineOfPos; line < lineOfPos + linesAdded; line++) { + ldTabstops->InsertLine(line); + } + } else { + for (int line = (lineOfPos + -linesAdded) - 1; line >= lineOfPos; line--) { + ldTabstops->RemoveLine(line); + } + } + } +} + +void EditView::DropGraphics(bool freeObjects) { + if (freeObjects) { + delete pixmapLine; + pixmapLine = 0; + delete pixmapIndentGuide; + pixmapIndentGuide = 0; + delete pixmapIndentGuideHighlight; + pixmapIndentGuideHighlight = 0; + } else { + if (pixmapLine) + pixmapLine->Release(); + if (pixmapIndentGuide) + pixmapIndentGuide->Release(); + if (pixmapIndentGuideHighlight) + pixmapIndentGuideHighlight->Release(); + } +} + +void EditView::AllocateGraphics(const ViewStyle &vsDraw) { + if (!pixmapLine) + pixmapLine = Surface::Allocate(vsDraw.technology); + if (!pixmapIndentGuide) + pixmapIndentGuide = Surface::Allocate(vsDraw.technology); + if (!pixmapIndentGuideHighlight) + pixmapIndentGuideHighlight = Surface::Allocate(vsDraw.technology); +} + +const char *ControlCharacterString(unsigned char ch) { + const char *reps[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", + "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", + "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" + }; + if (ch < ELEMENTS(reps)) { + return reps[ch]; + } else { + return "BAD"; + } +} + +void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) { + int ydiff = static_cast<int>(rcTab.bottom - rcTab.top) / 2; + int xhead = static_cast<int>(rcTab.right) - 1 - ydiff; + if (xhead <= rcTab.left) { + ydiff -= static_cast<int>(rcTab.left) - xhead - 1; + xhead = static_cast<int>(rcTab.left) - 1; + } + if ((rcTab.left + 2) < (rcTab.right - 1)) + surface->MoveTo(static_cast<int>(rcTab.left) + 2, ymid); + else + surface->MoveTo(static_cast<int>(rcTab.right) - 1, ymid); + surface->LineTo(static_cast<int>(rcTab.right) - 1, ymid); + surface->LineTo(xhead, ymid - ydiff); + surface->MoveTo(static_cast<int>(rcTab.right) - 1, ymid); + surface->LineTo(xhead, ymid + ydiff); +} + +void EditView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) { + if (!pixmapIndentGuide->Initialised()) { + // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line + pixmapIndentGuide->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid); + pixmapIndentGuideHighlight->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid); + PRectangle rcIG = PRectangle::FromInts(0, 0, 1, vsDraw.lineHeight); + pixmapIndentGuide->FillRectangle(rcIG, vsDraw.styles[STYLE_INDENTGUIDE].back); + pixmapIndentGuide->PenColour(vsDraw.styles[STYLE_INDENTGUIDE].fore); + pixmapIndentGuideHighlight->FillRectangle(rcIG, vsDraw.styles[STYLE_BRACELIGHT].back); + pixmapIndentGuideHighlight->PenColour(vsDraw.styles[STYLE_BRACELIGHT].fore); + for (int stripe = 1; stripe < vsDraw.lineHeight + 1; stripe += 2) { + PRectangle rcPixel = PRectangle::FromInts(0, stripe, 1, stripe + 1); + pixmapIndentGuide->FillRectangle(rcPixel, vsDraw.styles[STYLE_INDENTGUIDE].fore); + pixmapIndentGuideHighlight->FillRectangle(rcPixel, vsDraw.styles[STYLE_BRACELIGHT].fore); + } + } +} + +LineLayout *EditView::RetrieveLineLayout(int lineNumber, const EditModel &model) { + int posLineStart = model.pdoc->LineStart(lineNumber); + int posLineEnd = model.pdoc->LineStart(lineNumber + 1); + PLATFORM_ASSERT(posLineEnd >= posLineStart); + int lineCaret = model.pdoc->LineFromPosition(model.sel.MainCaret()); + return llc.Retrieve(lineNumber, lineCaret, + posLineEnd - posLineStart, model.pdoc->GetStyleClock(), + model.LinesOnScreen() + 1, model.pdoc->LinesTotal()); +} + +/** +* Fill in the LineLayout data for the given line. +* Copy the given @a line and its styles from the document into local arrays. +* Also determine the x position at which each character starts. +*/ +void EditView::LayoutLine(const EditModel &model, int line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width) { + if (!ll) + return; + + PLATFORM_ASSERT(line < model.pdoc->LinesTotal()); + PLATFORM_ASSERT(ll->chars != NULL); + int posLineStart = model.pdoc->LineStart(line); + int posLineEnd = model.pdoc->LineStart(line + 1); + // If the line is very long, limit the treatment to a length that should fit in the viewport + if (posLineEnd >(posLineStart + ll->maxLineLength)) { + posLineEnd = posLineStart + ll->maxLineLength; + } + if (ll->validity == LineLayout::llCheckTextAndStyle) { + int lineLength = posLineEnd - posLineStart; + if (!vstyle.viewEOL) { + lineLength = model.pdoc->LineEnd(line) - posLineStart; + } + if (lineLength == ll->numCharsInLine) { + // See if chars, styles, indicators, are all the same + bool allSame = true; + // Check base line layout + char styleByte = 0; + int numCharsInLine = 0; + while (numCharsInLine < lineLength) { + int charInDoc = numCharsInLine + posLineStart; + char chDoc = model.pdoc->CharAt(charInDoc); + styleByte = model.pdoc->StyleAt(charInDoc); + allSame = allSame && + (ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte)); + if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed) + allSame = allSame && + (ll->chars[numCharsInLine] == chDoc); + else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc))); + else // Style::caseUpper + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc))); + numCharsInLine++; + } + allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled + if (allSame) { + ll->validity = LineLayout::llPositions; + } else { + ll->validity = LineLayout::llInvalid; + } + } else { + ll->validity = LineLayout::llInvalid; + } + } + if (ll->validity == LineLayout::llInvalid) { + ll->widthLine = LineLayout::wrapWidthInfinite; + ll->lines = 1; + if (vstyle.edgeState == EDGE_BACKGROUND) { + ll->edgeColumn = model.pdoc->FindColumn(line, vstyle.theEdge); + if (ll->edgeColumn >= posLineStart) { + ll->edgeColumn -= posLineStart; + } + } else { + ll->edgeColumn = -1; + } + + // Fill base line layout + const int lineLength = posLineEnd - posLineStart; + model.pdoc->GetCharRange(ll->chars, posLineStart, lineLength); + model.pdoc->GetStyleRange(ll->styles, posLineStart, lineLength); + int numCharsBeforeEOL = model.pdoc->LineEnd(line) - posLineStart; + const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL; + for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) { + const unsigned char styleByte = ll->styles[styleInLine]; + ll->styles[styleInLine] = styleByte; + } + const unsigned char styleByteLast = (lineLength > 0) ? ll->styles[lineLength - 1] : 0; + if (vstyle.someStylesForceCase) { + for (int charInLine = 0; charInLine<lineLength; charInLine++) { + char chDoc = ll->chars[charInLine]; + if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper) + ll->chars[charInLine] = static_cast<char>(toupper(chDoc)); + else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower) + ll->chars[charInLine] = static_cast<char>(tolower(chDoc)); + } + } + ll->xHighlightGuide = 0; + // Extra element at the end of the line to hold end x position and act as + ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character + ll->styles[numCharsInLine] = styleByteLast; // For eolFilled + + // Layout the line, determining the position of each character, + // with an extra element at the end for the end of the line. + ll->positions[0] = 0; + bool lastSegItalics = false; + + BreakFinder bfLayout(ll, NULL, Range(0, numCharsInLine), posLineStart, 0, false, model.pdoc, &model.reprs); + while (bfLayout.More()) { + + const TextSegment ts = bfLayout.Next(); + + std::fill(&ll->positions[ts.start + 1], &ll->positions[ts.end() + 1], 0.0f); + if (vstyle.styles[ll->styles[ts.start]].visible) { + if (ts.representation) { + XYPOSITION representationWidth = vstyle.controlCharWidth; + if (ll->chars[ts.start] == '\t') { + // Tab is a special case of representation, taking a variable amount of space + const int x = static_cast<int>(ll->positions[ts.start]); + const int tabWidth = static_cast<int>(vstyle.tabWidth); + representationWidth = static_cast<XYPOSITION>(NextTabstopPos(line, x, tabWidth) - ll->positions[ts.start]); + } else { + if (representationWidth <= 0.0) { + XYPOSITION positionsRepr[256]; // Should expand when needed + posCache.MeasureWidths(surface, vstyle, STYLE_CONTROLCHAR, ts.representation->stringRep.c_str(), + static_cast<unsigned int>(ts.representation->stringRep.length()), positionsRepr, model.pdoc); + representationWidth = positionsRepr[ts.representation->stringRep.length() - 1] + vstyle.ctrlCharPadding; + } + } + for (int ii = 0; ii < ts.length; ii++) + ll->positions[ts.start + 1 + ii] = representationWidth; + } else { + if ((ts.length == 1) && (' ' == ll->chars[ts.start])) { + // Over half the segments are single characters and of these about half are space characters. + ll->positions[ts.start + 1] = vstyle.styles[ll->styles[ts.start]].spaceWidth; + } else { + posCache.MeasureWidths(surface, vstyle, ll->styles[ts.start], ll->chars + ts.start, + ts.length, ll->positions + ts.start + 1, model.pdoc); + } + } + lastSegItalics = (!ts.representation) && ((ll->chars[ts.end() - 1] != ' ') && vstyle.styles[ll->styles[ts.start]].italic); + } + + for (int posToIncrease = ts.start + 1; posToIncrease <= ts.end(); posToIncrease++) { + ll->positions[posToIncrease] += ll->positions[ts.start]; + } + } + + // Small hack to make lines that end with italics not cut off the edge of the last character + if (lastSegItalics) { + ll->positions[numCharsInLine] += vstyle.lastSegItalicsOffset; + } + ll->numCharsInLine = numCharsInLine; + ll->numCharsBeforeEOL = numCharsBeforeEOL; + ll->validity = LineLayout::llPositions; + } + // Hard to cope when too narrow, so just assume there is space + if (width < 20) { + width = 20; + } + if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) { + ll->widthLine = width; + if (width == LineLayout::wrapWidthInfinite) { + ll->lines = 1; + } else if (width > ll->positions[ll->numCharsInLine]) { + // Simple common case where line does not need wrapping. + ll->lines = 1; + } else { + if (vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { + width -= static_cast<int>(vstyle.aveCharWidth); // take into account the space for end wrap mark + } + XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line + if (vstyle.wrapIndentMode == SC_WRAPINDENT_INDENT) { + wrapAddIndent = model.pdoc->IndentSize() * vstyle.spaceWidth; + } else if (vstyle.wrapIndentMode == SC_WRAPINDENT_FIXED) { + wrapAddIndent = vstyle.wrapVisualStartIndent * vstyle.aveCharWidth; + } + ll->wrapIndent = wrapAddIndent; + if (vstyle.wrapIndentMode != SC_WRAPINDENT_FIXED) + for (int i = 0; i < ll->numCharsInLine; i++) { + if (!IsSpaceOrTab(ll->chars[i])) { + ll->wrapIndent += ll->positions[i]; // Add line indent + break; + } + } + // Check for text width minimum + if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15) + ll->wrapIndent = wrapAddIndent; + // Check for wrapIndent minimum + if ((vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < vstyle.aveCharWidth)) + ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual + ll->lines = 0; + // Calculate line start positions based upon width. + int lastGoodBreak = 0; + int lastLineStart = 0; + XYACCUMULATOR startOffset = 0; + int p = 0; + while (p < ll->numCharsInLine) { + if ((ll->positions[p + 1] - startOffset) >= width) { + if (lastGoodBreak == lastLineStart) { + // Try moving to start of last character + if (p > 0) { + lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) + - posLineStart; + } + if (lastGoodBreak == lastLineStart) { + // Ensure at least one character on line. + lastGoodBreak = model.pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) + - posLineStart; + } + } + lastLineStart = lastGoodBreak; + ll->lines++; + ll->SetLineStart(ll->lines, lastGoodBreak); + startOffset = ll->positions[lastGoodBreak]; + // take into account the space for start wrap mark and indent + startOffset -= ll->wrapIndent; + p = lastGoodBreak + 1; + continue; + } + if (p > 0) { + if (vstyle.wrapState == eWrapChar) { + lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) + - posLineStart; + p = model.pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; + continue; + } else if ((vstyle.wrapState == eWrapWord) && (ll->styles[p] != ll->styles[p - 1])) { + lastGoodBreak = p; + } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { + lastGoodBreak = p; + } + } + p++; + } + ll->lines++; + } + ll->validity = LineLayout::llLines; + } +} + +Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, int topLine, const ViewStyle &vs) { + Point pt; + if (pos.Position() == INVALID_POSITION) + return pt; + const int line = model.pdoc->LineFromPosition(pos.Position()); + const int lineVisible = model.cs.DisplayFromDoc(line); + //Platform::DebugPrintf("line=%d\n", line); + AutoLineLayout ll(llc, RetrieveLineLayout(line, model)); + if (surface && ll) { + const int posLineStart = model.pdoc->LineStart(line); + LayoutLine(model, line, surface, vs, ll, model.wrapWidth); + const int posInLine = pos.Position() - posLineStart; + pt = ll->PointFromPosition(posInLine, vs.lineHeight); + pt.y += (lineVisible - topLine) * vs.lineHeight; + pt.x += vs.textStart - model.xOffset; + } + pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth; + return pt; +} + +SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditModel &model, Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs) { + pt.x = pt.x - vs.textStart; + int visibleLine = static_cast<int>(floor(pt.y / vs.lineHeight)); + if (!canReturnInvalid && (visibleLine < 0)) + visibleLine = 0; + const int lineDoc = model.cs.DocFromDisplay(visibleLine); + if (canReturnInvalid && (lineDoc < 0)) + return SelectionPosition(INVALID_POSITION); + if (lineDoc >= model.pdoc->LinesTotal()) + return SelectionPosition(canReturnInvalid ? INVALID_POSITION : model.pdoc->Length()); + const int posLineStart = model.pdoc->LineStart(lineDoc); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + const int lineStartSet = model.cs.DisplayFromDoc(lineDoc); + const int subLine = visibleLine - lineStartSet; + if (subLine < ll->lines) { + const Range rangeSubLine = ll->SubLineRange(subLine); + const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; + if (subLine > 0) // Wrapped + pt.x -= ll->wrapIndent; + const int positionInLine = ll->FindPositionFromX(pt.x + subLineStart, rangeSubLine, charPosition); + if (positionInLine < rangeSubLine.end) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); + } + if (virtualSpace) { + const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; + const int spaceOffset = static_cast<int>( + (pt.x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); + return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); + } else if (canReturnInvalid) { + if (pt.x < (ll->positions[rangeSubLine.end] - subLineStart)) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(rangeSubLine.end + posLineStart, 1)); + } + } else { + return SelectionPosition(rangeSubLine.end + posLineStart); + } + } + if (!canReturnInvalid) + return SelectionPosition(ll->numCharsInLine + posLineStart); + } + return SelectionPosition(canReturnInvalid ? INVALID_POSITION : posLineStart); +} + +/** +* Find the document position corresponding to an x coordinate on a particular document line. +* Ensure is between whole characters when document is in multi-byte or UTF-8 mode. +* This method is used for rectangular selections and does not work on wrapped lines. +*/ +SelectionPosition EditView::SPositionFromLineX(Surface *surface, const EditModel &model, int lineDoc, int x, const ViewStyle &vs) { + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + const int posLineStart = model.pdoc->LineStart(lineDoc); + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + const Range rangeSubLine = ll->SubLineRange(0); + const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; + const int positionInLine = ll->FindPositionFromX(x + subLineStart, rangeSubLine, false); + if (positionInLine < rangeSubLine.end) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); + } + const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; + const int spaceOffset = static_cast<int>( + (x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); + return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); + } + return SelectionPosition(0); +} + +int EditView::DisplayFromPosition(Surface *surface, const EditModel &model, int pos, const ViewStyle &vs) { + int lineDoc = model.pdoc->LineFromPosition(pos); + int lineDisplay = model.cs.DisplayFromDoc(lineDoc); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + unsigned int posLineStart = model.pdoc->LineStart(lineDoc); + int posInLine = pos - posLineStart; + lineDisplay--; // To make up for first increment ahead. + for (int subLine = 0; subLine < ll->lines; subLine++) { + if (posInLine >= ll->LineStart(subLine)) { + lineDisplay++; + } + } + } + return lineDisplay; +} + +int EditView::StartEndDisplayLine(Surface *surface, const EditModel &model, int pos, bool start, const ViewStyle &vs) { + int line = model.pdoc->LineFromPosition(pos); + AutoLineLayout ll(llc, RetrieveLineLayout(line, model)); + int posRet = INVALID_POSITION; + if (surface && ll) { + unsigned int posLineStart = model.pdoc->LineStart(line); + LayoutLine(model, line, surface, vs, ll, model.wrapWidth); + int posInLine = pos - posLineStart; + if (posInLine <= ll->maxLineLength) { + for (int subLine = 0; subLine < ll->lines; subLine++) { + if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { + if (start) { + posRet = ll->LineStart(subLine) + posLineStart; + } else { + if (subLine == ll->lines - 1) + posRet = ll->LineStart(subLine + 1) + posLineStart; + else + posRet = ll->LineStart(subLine + 1) + posLineStart - 1; + } + } + } + } + } + return posRet; +} + +static ColourDesired SelectionBackground(const ViewStyle &vsDraw, bool main, bool primarySelection) { + return main ? + (primarySelection ? vsDraw.selColours.back : vsDraw.selBackground2) : + vsDraw.selAdditionalBackground; +} + +static ColourDesired TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + ColourOptional background, int inSelection, bool inHotspot, int styleMain, int i) { + if (inSelection == 1) { + if (vsDraw.selColours.back.isSet && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { + return SelectionBackground(vsDraw, true, model.primarySelection); + } + } else if (inSelection == 2) { + if (vsDraw.selColours.back.isSet && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) { + return SelectionBackground(vsDraw, false, model.primarySelection); + } + } else { + if ((vsDraw.edgeState == EDGE_BACKGROUND) && + (i >= ll->edgeColumn) && + (i < ll->numCharsBeforeEOL)) + return vsDraw.edgecolour; + if (inHotspot && vsDraw.hotspotColours.back.isSet) + return vsDraw.hotspotColours.back; + } + if (background.isSet && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) { + return background; + } else { + return vsDraw.styles[styleMain].back; + } +} + +void EditView::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) { + Point from = Point::FromInts(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0); + PRectangle rcCopyArea = PRectangle::FromInts(start + 1, static_cast<int>(rcSegment.top), start + 2, static_cast<int>(rcSegment.bottom)); + surface->Copy(rcCopyArea, from, + highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide); +} + +static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) { + if (alpha != SC_ALPHA_NOALPHA) { + surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0); + } +} + +static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, + const char *s, ColourDesired textBack, ColourDesired textFore, bool fillBackground) { + if (fillBackground) { + surface->FillRectangle(rcSegment, textBack); + } + FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; + int normalCharHeight = static_cast<int>(surface->Ascent(ctrlCharsFont) - + surface->InternalLeading(ctrlCharsFont)); + PRectangle rcCChar = rcSegment; + rcCChar.left = rcCChar.left + 1; + rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; + rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; + PRectangle rcCentral = rcCChar; + rcCentral.top++; + rcCentral.bottom--; + surface->FillRectangle(rcCentral, textFore); + PRectangle rcChar = rcCChar; + rcChar.left++; + rcChar.right--; + surface->DrawTextClipped(rcChar, ctrlCharsFont, + rcSegment.top + vsDraw.maxAscent, s, static_cast<int>(s ? strlen(s) : 0), + textBack, textFore); +} + +void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + PRectangle rcLine, int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, + ColourOptional background) { + + const int posLineStart = model.pdoc->LineStart(line); + PRectangle rcSegment = rcLine; + + const bool lastSubLine = subLine == (ll->lines - 1); + XYPOSITION virtualSpace = 0; + if (lastSubLine) { + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + virtualSpace = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)) * spaceWidth; + } + XYPOSITION xEol = static_cast<XYPOSITION>(ll->positions[lineEnd] - subLineStart); + + // Fill the virtual space and show selections within it + if (virtualSpace) { + rcSegment.left = xEol + xStart; + rcSegment.right = xEol + xStart + virtualSpace; + surface->FillRectangle(rcSegment, background.isSet ? background : vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) { + SelectionSegment virtualSpaceRange(SelectionPosition(model.pdoc->LineEnd(line)), SelectionPosition(model.pdoc->LineEnd(line), model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)))); + for (size_t r = 0; r<model.sel.Count(); r++) { + int alpha = (r == model.sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + if (alpha == SC_ALPHA_NOALPHA) { + SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth; + rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; + rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection)); + } + } + } + } + } + + int eolInSelection = 0; + int alpha = SC_ALPHA_NOALPHA; + if (!hideSelection) { + int posAfterLineEnd = model.pdoc->LineStart(line + 1); + eolInSelection = (subLine == (ll->lines - 1)) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0; + alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + } + + // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on + XYPOSITION blobsWidth = 0; + if (lastSubLine) { + for (int eolPos = ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) { + rcSegment.left = xStart + ll->positions[eolPos] - static_cast<XYPOSITION>(subLineStart)+virtualSpace; + rcSegment.right = xStart + ll->positions[eolPos + 1] - static_cast<XYPOSITION>(subLineStart)+virtualSpace; + blobsWidth += rcSegment.Width(); + char hexits[4]; + const char *ctrlChar; + unsigned char chEOL = ll->chars[eolPos]; + int styleMain = ll->styles[eolPos]; + ColourDesired textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, styleMain, eolPos); + if (UTF8IsAscii(chEOL)) { + ctrlChar = ControlCharacterString(chEOL); + } else { + const Representation *repr = model.reprs.RepresentationFromCharacter(ll->chars + eolPos, ll->numCharsInLine - eolPos); + if (repr) { + ctrlChar = repr->stringRep.c_str(); + eolPos = ll->numCharsInLine; + } else { + sprintf(hexits, "x%2X", chEOL); + ctrlChar = hexits; + } + } + ColourDesired textFore = vsDraw.styles[styleMain].fore; + if (eolInSelection && vsDraw.selColours.fore.isSet) { + textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; + } + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1)) { + if (alpha == SC_ALPHA_NOALPHA) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + surface->FillRectangle(rcSegment, textBack); + } + } else { + surface->FillRectangle(rcSegment, textBack); + } + DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == phasesOne); + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + } + + // Draw the eol-is-selected rectangle + rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; + rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; + + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + if (background.isSet) { + surface->FillRectangle(rcSegment, background); + } else if (line < model.pdoc->LinesTotal() - 1) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); + } + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + + // Fill the remainder of the line + rcSegment.left = rcSegment.right; + if (rcSegment.left < rcLine.left) + rcSegment.left = rcLine.left; + rcSegment.right = rcLine.right; + + if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + if (background.isSet) { + surface->FillRectangle(rcSegment, background); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); + } + if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + + bool drawWrapMarkEnd = false; + + if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { + if (subLine + 1 < ll->lines) { + drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; + } + } + + if (drawWrapMarkEnd) { + PRectangle rcPlace = rcSegment; + + if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { + rcPlace.left = xEol + xStart + virtualSpace; + rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; + } else { + // rcLine is clipped to text area + rcPlace.right = rcLine.right; + rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; + } + DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour()); + } +} + +static void DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, const ViewStyle &vsDraw, + const LineLayout *ll, int xStart, PRectangle rcLine, int subLine) { + const XYPOSITION subLineStart = ll->positions[ll->LineStart(subLine)]; + PRectangle rcIndic( + ll->positions[startPos] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent, + ll->positions[endPos] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent + 3); + vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine); +} + +static void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int xStart, PRectangle rcLine, int subLine, int lineEnd, bool under) { + // Draw decorators + const int posLineStart = model.pdoc->LineStart(line); + const int lineStart = ll->LineStart(subLine); + const int posLineEnd = posLineStart + lineEnd; + + for (Decoration *deco = model.pdoc->decorations.root; deco; deco = deco->next) { + if (under == vsDraw.indicators[deco->indicator].under) { + int startPos = posLineStart + lineStart; + if (!deco->rs.ValueAt(startPos)) { + startPos = deco->rs.EndRun(startPos); + } + while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) { + int endPos = deco->rs.EndRun(startPos); + if (endPos > posLineEnd) + endPos = posLineEnd; + DrawIndicator(deco->indicator, startPos - posLineStart, endPos - posLineStart, + surface, vsDraw, ll, xStart, rcLine, subLine); + startPos = endPos; + if (!deco->rs.ValueAt(startPos)) { + startPos = deco->rs.EndRun(startPos); + } + } + } + } + + // Use indicators to highlight matching braces + if ((vsDraw.braceHighlightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACELIGHT)) || + (vsDraw.braceBadLightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACEBAD))) { + int braceIndicator = (model.bracesMatchStyle == STYLE_BRACELIGHT) ? vsDraw.braceHighlightIndicator : vsDraw.braceBadLightIndicator; + if (under == vsDraw.indicators[braceIndicator].under) { + Range rangeLine(posLineStart + lineStart, posLineEnd); + if (rangeLine.ContainsCharacter(model.braces[0])) { + int braceOffset = model.braces[0] - posLineStart; + if (braceOffset < ll->numCharsInLine) { + DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, subLine); + } + } + if (rangeLine.ContainsCharacter(model.braces[1])) { + int braceOffset = model.braces[1] - posLineStart; + if (braceOffset < ll->numCharsInLine) { + DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, subLine); + } + } + } + } +} + +void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { + int indent = static_cast<int>(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth); + PRectangle rcSegment = rcLine; + int annotationLine = subLine - ll->lines; + const StyledText stAnnotation = model.pdoc->AnnotationStyledText(line); + if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { + if (phase & drawBack) { + surface->FillRectangle(rcSegment, vsDraw.styles[0].back); + } + rcSegment.left = static_cast<XYPOSITION>(xStart); + if (model.trackLineWidth || (vsDraw.annotationVisible == ANNOTATION_BOXED)) { + // Only care about calculating width if tracking or need to draw box + int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); + if (vsDraw.annotationVisible == ANNOTATION_BOXED) { + widthAnnotation += static_cast<int>(vsDraw.spaceWidth * 2); // Margins + } + if (widthAnnotation > lineWidthMaxSeen) + lineWidthMaxSeen = widthAnnotation; + if (vsDraw.annotationVisible == ANNOTATION_BOXED) { + rcSegment.left = static_cast<XYPOSITION>(xStart + indent); + rcSegment.right = rcSegment.left + widthAnnotation; + } + } + const int annotationLines = model.pdoc->AnnotationLines(line); + size_t start = 0; + size_t lengthAnnotation = stAnnotation.LineLength(start); + int lineInAnnotation = 0; + while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) { + start += lengthAnnotation + 1; + lengthAnnotation = stAnnotation.LineLength(start); + lineInAnnotation++; + } + PRectangle rcText = rcSegment; + if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) { + surface->FillRectangle(rcText, + vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back); + rcText.left += vsDraw.spaceWidth; + } + DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, + stAnnotation, start, lengthAnnotation, phase); + if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) { + surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore); + surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.top)); + surface->LineTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.bottom)); + surface->MoveTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.top)); + surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.bottom)); + if (subLine == ll->lines) { + surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.top)); + surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.top)); + } + if (subLine == ll->lines + annotationLines - 1) { + surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.bottom - 1)); + surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.bottom - 1)); + } + } + } +} + +static void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour) { + + int lineStart = ll->LineStart(subLine); + int posBefore = posCaret; + int posAfter = model.pdoc->MovePositionOutsideChar(posCaret + 1, 1); + int numCharsToDraw = posAfter - posCaret; + + // Work out where the starting and ending offsets are. We need to + // see if the previous character shares horizontal space, such as a + // glyph / combining character. If so we'll need to draw that too. + int offsetFirstChar = offset; + int offsetLastChar = offset + (posAfter - posCaret); + while ((posBefore > 0) && ((offsetLastChar - numCharsToDraw) >= lineStart)) { + if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) { + // The char does not share horizontal space + break; + } + // Char shares horizontal space, update the numChars to draw + // Update posBefore to point to the prev char + posBefore = model.pdoc->MovePositionOutsideChar(posBefore - 1, -1); + numCharsToDraw = posAfter - posBefore; + offsetFirstChar = offset - (posCaret - posBefore); + } + + // See if the next character shares horizontal space, if so we'll + // need to draw that too. + if (offsetFirstChar < 0) + offsetFirstChar = 0; + numCharsToDraw = offsetLastChar - offsetFirstChar; + while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { + // Update posAfter to point to the 2nd next char, this is where + // the next character ends, and 2nd next begins. We'll need + // to compare these two + posBefore = posAfter; + posAfter = model.pdoc->MovePositionOutsideChar(posAfter + 1, 1); + offsetLastChar = offset + (posAfter - posCaret); + if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) { + // The char does not share horizontal space + break; + } + // Char shares horizontal space, update the numChars to draw + numCharsToDraw = offsetLastChar - offsetFirstChar; + } + + // We now know what to draw, update the caret drawing rectangle + rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; + rcCaret.right = ll->positions[offsetFirstChar + numCharsToDraw] - ll->positions[lineStart] + xStart; + + // Adjust caret position to take into account any word wrapping symbols. + if ((ll->wrapIndent != 0) && (lineStart != 0)) { + XYPOSITION wordWrapCharWidth = ll->wrapIndent; + rcCaret.left += wordWrapCharWidth; + rcCaret.right += wordWrapCharWidth; + } + + // This character is where the caret block is, we override the colours + // (inversed) for drawing the caret here. + int styleMain = ll->styles[offsetFirstChar]; + FontAlias fontText = vsDraw.styles[styleMain].font; + surface->DrawTextClipped(rcCaret, fontText, + rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar, + numCharsToDraw, vsDraw.styles[styleMain].back, + caretColour); +} + +void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int lineDoc, int xStart, PRectangle rcLine, int subLine) const { + // When drag is active it is the only caret drawn + bool drawDrag = model.posDrag.IsValid(); + if (hideSelection && !drawDrag) + return; + const int posLineStart = model.pdoc->LineStart(lineDoc); + // For each selection draw + for (size_t r = 0; (r<model.sel.Count()) || drawDrag; r++) { + const bool mainCaret = r == model.@@ Diff output truncated at 100000 characters. @@ -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] 74ef1b: Update for new Scintilla styles
by Colomban Wendling
10 Aug '14
10 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Sun, 10 Aug 2014 00:21:54 UTC Commit: 74ef1b8344a34810771f69ef7b82a8aeca57e894
https://github.com/geany/geany/commit/74ef1b8344a34810771f69ef7b82a8aeca57e…
Log Message: ----------- Update for new Scintilla styles Modified Paths: -------------- data/filetypes.rust src/highlighting.c src/highlightingmappings.h Modified: data/filetypes.rust 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -14,6 +14,9 @@ word4=type string=string_1 stringraw=string_2 character=character +bytestring=string_1 +bytestringraw=string_2 +bytecharacter=character operator=operator identifier=identifier_1 lifetime=parameter Modified: src/highlighting.c 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -1550,8 +1550,11 @@ gboolean highlighting_is_string_style(gint lexer, gint style) case SCLEX_RUST: return (style == SCE_RUST_CHARACTER || + style == SCE_RUST_BYTECHARACTER || style == SCE_RUST_STRING || style == SCE_RUST_STRINGR || + style == SCE_RUST_BYTESTRING || + style == SCE_RUST_BYTESTRINGR || style == SCE_RUST_LEXERROR); } return FALSE; Modified: src/highlightingmappings.h 5 lines changed, 4 insertions(+), 1 deletions(-) =================================================================== @@ -1326,7 +1326,10 @@ static const HLStyle highlighting_styles_RUST[] = { SCE_RUST_IDENTIFIER, "identifier", FALSE }, { SCE_RUST_LIFETIME, "lifetime", FALSE }, { SCE_RUST_MACRO, "macro", FALSE }, - { SCE_RUST_LEXERROR, "lexerror", FALSE } + { SCE_RUST_LEXERROR, "lexerror", FALSE }, + { SCE_RUST_BYTESTRING, "bytestring", FALSE }, + { SCE_RUST_BYTESTRINGR, "bytestringr", FALSE }, + { SCE_RUST_BYTECHARACTER, "bytecharacter", FALSE } }; static const HLKeyword highlighting_keywords_RUST[] = { -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
[geany/geany] d77fe4: Update Scintilla to 3.5.0 pre-release
by Colomban Wendling
10 Aug '14
10 Aug '14
Branch: refs/heads/master Author: Colomban Wendling <ban(a)herbesfolles.org> Committer: Colomban Wendling <ban(a)herbesfolles.org> Date: Sun, 10 Aug 2014 00:17:32 UTC Commit: d77fe4c6b78f1b3d6f7650370d2f46eaec0e6f8d
https://github.com/geany/geany/commit/d77fe4c6b78f1b3d6f7650370d2f46eaec0e6…
Log Message: ----------- Update Scintilla to 3.5.0 pre-release Modified Paths: -------------- scintilla/Makefile.am scintilla/gtk/PlatGTK.cxx scintilla/gtk/ScintillaGTK.cxx scintilla/include/SciLexer.h scintilla/include/Scintilla.h scintilla/include/Scintilla.iface scintilla/lexers/LexHTML.cxx scintilla/lexers/LexMatlab.cxx scintilla/lexers/LexRuby.cxx scintilla/lexers/LexRust.cxx scintilla/lexlib/LexerModule.h scintilla/makefile.win32 scintilla/scintilla_changes.patch scintilla/src/CellBuffer.cxx scintilla/src/CellBuffer.h scintilla/src/ContractionState.cxx scintilla/src/ContractionState.h scintilla/src/Document.cxx scintilla/src/Document.h scintilla/src/EditModel.cxx scintilla/src/EditModel.h scintilla/src/EditView.cxx scintilla/src/EditView.h scintilla/src/Editor.cxx scintilla/src/Editor.h scintilla/src/LineMarker.cxx scintilla/src/MarginView.cxx scintilla/src/MarginView.h scintilla/src/PerLine.cxx scintilla/src/PerLine.h scintilla/src/PositionCache.cxx scintilla/src/PositionCache.h scintilla/src/RESearch.cxx scintilla/src/RESearch.h scintilla/src/ScintillaBase.cxx scintilla/src/ScintillaBase.h scintilla/src/Selection.cxx scintilla/src/Selection.h scintilla/src/ViewStyle.cxx scintilla/src/ViewStyle.h scintilla/version.txt Modified: scintilla/Makefile.am 6 lines changed, 6 insertions(+), 0 deletions(-) =================================================================== @@ -97,6 +97,10 @@ src/Document.cxx \ src/Document.h \ src/Editor.cxx \ src/Editor.h \ +src/EditModel.cxx \ +src/EditModel.h \ +src/EditView.cxx \ +src/EditView.h \ src/ExternalLexer.cxx \ src/ExternalLexer.h \ src/FontQuality.h \ @@ -106,6 +110,8 @@ src/KeyMap.cxx \ src/KeyMap.h \ src/LineMarker.cxx \ src/LineMarker.h \ +src/MarginView.cxx \ +src/MarginView.h \ src/Partitioning.h \ src/PerLine.cxx \ src/PerLine.h \ Modified: scintilla/gtk/PlatGTK.cxx 12 lines changed, 10 insertions(+), 2 deletions(-) =================================================================== @@ -527,6 +527,7 @@ void SurfaceImpl::Release() { } bool SurfaceImpl::Initialised() { +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 8, 0) if (inited && context) { if (cairo_status(context) == CAIRO_STATUS_SUCCESS) { // Even when status is success, the target surface may have been @@ -543,6 +544,7 @@ bool SurfaceImpl::Initialised() { } return cairo_status(context) == CAIRO_STATUS_SUCCESS; } +#endif return inited; } @@ -1086,6 +1088,10 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, XYPOSITION } clusterStart = clusterEnd; } + while (i < lenPositions) { + // If something failed, fill in rest of the positions + positions[i++] = clusterStart; + } PLATFORM_ASSERT(i == lenPositions); } } @@ -1799,6 +1805,7 @@ void ListBoxX::Select(int n) { } int ListBoxX::GetSelection() { + int index = -1; GtkTreeIter iter; GtkTreeModel *model; GtkTreeSelection *selection; @@ -1808,9 +1815,10 @@ int ListBoxX::GetSelection() { int *indices = gtk_tree_path_get_indices(path); // Don't free indices. if (indices) - return indices[0]; + index = indices[0]; + gtk_tree_path_free(path); } - return -1; + return index; } int ListBoxX::Find(const char *prefix) { Modified: scintilla/gtk/ScintillaGTK.cxx 284 lines changed, 208 insertions(+), 76 deletions(-) =================================================================== @@ -57,9 +57,13 @@ #include "UniConversion.h" #include "Selection.h" #include "PositionCache.h" +#include "EditModel.h" +#include "MarginView.h" +#include "EditView.h" #include "Editor.h" #include "AutoComplete.h" #include "ScintillaBase.h" +#include "UnicodeFromUTF8.h" #ifdef SCI_LEXER #include "ExternalLexer.h" @@ -186,13 +190,23 @@ class ScintillaGTK : public ScintillaBase { virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); private: virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); - virtual void SetTicking(bool on); + struct TimeThunk { + TickReason reason; + ScintillaGTK *scintilla; + guint timer; + TimeThunk() : reason(tickCaret), scintilla(NULL), timer(0) {} + }; + TimeThunk timers[tickDwell+1]; + virtual bool FineTickerAvailable(); + virtual bool FineTickerRunning(TickReason reason); + virtual void FineTickerStart(TickReason reason, int millis, int tolerance); + virtual void FineTickerCancel(TickReason reason); virtual bool SetIdle(bool on); virtual void SetMouseCapture(bool on); virtual bool HaveMouseCapture(); virtual bool PaintContains(PRectangle rc); void FullPaint(); - virtual PRectangle GetClientRectangle(); + virtual PRectangle GetClientRectangle() const; virtual void ScrollText(int linesToMove); virtual void SetVerticalScrollPos(); virtual void SetHorizontalScrollPos(); @@ -280,6 +294,9 @@ class ScintillaGTK : public ScintillaBase { static void Commit(GtkIMContext *context, char *str, ScintillaGTK *sciThis); void PreeditChangedThis(); static void PreeditChanged(GtkIMContext *context, ScintillaGTK *sciThis); + + bool KoreanIME(); + static void StyleSetText(GtkWidget *widget, GtkStyle *previous, void*); static void RealizeText(GtkWidget *widget, void*); static void Destroy(GObject *object); @@ -300,7 +317,7 @@ class ScintillaGTK : public ScintillaBase { gint x, gint y, GtkSelectionData *selection_data, guint info, guint time); static void DragDataGet(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time); - static gboolean TimeOut(ScintillaGTK *sciThis); + static gboolean TimeOut(TimeThunk *tt); static gboolean IdleCallback(ScintillaGTK *sciThis); static gboolean StyleIdle(ScintillaGTK *sciThis); virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo); @@ -624,22 +641,37 @@ void ScintillaGTK::MainForAll(GtkContainer *container, gboolean include_internal } } +namespace { + +class PreEditString { +public: + gchar *str; + gint cursor_pos; + PangoAttrList *attrs; + + PreEditString(GtkIMContext *im_context) { + gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); + } + ~PreEditString() { + g_free(str); + pango_attr_list_unref(attrs); + } +}; + +} + gint ScintillaGTK::FocusInThis(GtkWidget *widget) { try { SetFocusState(true); if (im_context != NULL) { - gchar *str = NULL; - gint cursor_pos; - - gtk_im_context_get_preedit_string(im_context, &str, NULL, &cursor_pos); + PreEditString pes(im_context); if (PWidget(wPreedit) != NULL) { - if (strlen(str) > 0) { + if (strlen(pes.str) > 0) { gtk_widget_show(PWidget(wPreedit)); } else { gtk_widget_hide(PWidget(wPreedit)); } } - g_free(str); gtk_im_context_focus_in(im_context); } @@ -829,11 +861,16 @@ void ScintillaGTK::Initialise() { caret.period = 0; } - SetTicking(true); + for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) { + timers[tr].reason = tr; + timers[tr].scintilla = this; + } } void ScintillaGTK::Finalise() { - SetTicking(false); + for (TickReason tr = tickCaret; tr <= tickDwell; tr = static_cast<TickReason>(tr + 1)) { + FineTickerCancel(tr); + } ScintillaBase::Finalise(); } @@ -1024,17 +1061,27 @@ sptr_t ScintillaGTK::DefWndProc(unsigned int, uptr_t, sptr_t) { return 0; } -void ScintillaGTK::SetTicking(bool on) { - if (timer.ticking != on) { - timer.ticking = on; - if (timer.ticking) { - timer.tickerID = reinterpret_cast<TickerID>(g_timeout_add(timer.tickSize, - reinterpret_cast<GSourceFunc>(TimeOut), this)); - } else { - g_source_remove(GPOINTER_TO_UINT(timer.tickerID)); - } +/** +* Report that this Editor subclass has a working implementation of FineTickerStart. +*/ +bool ScintillaGTK::FineTickerAvailable() { + return true; +} + +bool ScintillaGTK::FineTickerRunning(TickReason reason) { + return timers[reason].timer != 0; +} + +void ScintillaGTK::FineTickerStart(TickReason reason, int millis, int /* tolerance */) { + FineTickerCancel(reason); + timers[reason].timer = g_timeout_add(millis, reinterpret_cast<GSourceFunc>(TimeOut), &timers[reason]); +} + +void ScintillaGTK::FineTickerCancel(TickReason reason) { + if (timers[reason].timer) { + g_source_remove(timers[reason].timer); + timers[reason].timer = 0; } - timer.ticksToWait = caret.period; } bool ScintillaGTK::SetIdle(bool on) { @@ -1121,8 +1168,9 @@ void ScintillaGTK::FullPaint() { wText.InvalidateAll(); } -PRectangle ScintillaGTK::GetClientRectangle() { - PRectangle rc = wMain.GetClientPosition(); +PRectangle ScintillaGTK::GetClientRectangle() const { + Window &win = const_cast<Window &>(wMain); + PRectangle rc = win.GetClientPosition(); if (verticalScrollBarVisible) rc.right -= verticalScrollBarWidth; if (horizontalScrollBarVisible && !Wrapping()) @@ -2220,19 +2268,13 @@ gboolean ScintillaGTK::KeyRelease(GtkWidget *widget, GdkEventKey *event) { gboolean ScintillaGTK::DrawPreeditThis(GtkWidget *widget, cairo_t *cr) { try { - gchar *str; - gint cursor_pos; - PangoAttrList *attrs; - - gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); - PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); - pango_layout_set_attributes(layout, attrs); + PreEditString pes(im_context); + PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); + pango_layout_set_attributes(layout, pes.attrs); cairo_move_to(cr, 0, 0); pango_cairo_show_layout(cr, layout); - g_free(str); - pango_attr_list_unref(attrs); g_object_unref(layout); } catch (...) { errorStatus = SC_STATUS_FAILURE; @@ -2248,20 +2290,14 @@ gboolean ScintillaGTK::DrawPreedit(GtkWidget *widget, cairo_t *cr, ScintillaGTK gboolean ScintillaGTK::ExposePreeditThis(GtkWidget *widget, GdkEventExpose *ose) { try { - gchar *str; - gint cursor_pos; - PangoAttrList *attrs; - - gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); - PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); - pango_layout_set_attributes(layout, attrs); + PreEditString pes(im_context); + PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); + pango_layout_set_attributes(layout, pes.attrs); cairo_t *context = gdk_cairo_create(reinterpret_cast<GdkDrawable *>(WindowFromWidget(widget))); cairo_move_to(context, 0, 0); pango_cairo_show_layout(context, layout); cairo_destroy(context); - g_free(str); - pango_attr_list_unref(attrs); g_object_unref(layout); } catch (...) { errorStatus = SC_STATUS_FAILURE; @@ -2275,9 +2311,43 @@ gboolean ScintillaGTK::ExposePreedit(GtkWidget *widget, GdkEventExpose *ose, Sci #endif +bool ScintillaGTK::KoreanIME() { + // Warn : for KoreanIME use only. + if (pdoc->TentativeActive()) { + return true; + } + + bool koreanIME = false; + PreEditString utfval(im_context); + + // Only need to check if the first preedit char is Korean. + // The rest will be handled in TentativeActive() + // which can handle backspace and CJK commons and so forth. + + if (strlen(utfval.str) == 3) { // One hangul char has 3byte. + int unicode = UnicodeFromUTF8(reinterpret_cast<unsigned char *>(utfval.str)); + // Korean character ranges which are used for the first preedit chars. + //
http://www.programminginkorean.com/programming/hangul-in-unicode/
+ bool HangulJamo = (0x1100 <= unicode && unicode <= 0x11FF); + bool HangulCompatibleJamo = (0x3130 <= unicode && unicode <= 0x318F); + bool HangulJamoExtendedA = (0xA960 <= unicode && unicode <= 0xA97F); + bool HangulJamoExtendedB = (0xD7B0 <= unicode && unicode <= 0xD7FF); + bool HangulSyllable = (0xAC00 <= unicode && unicode <= 0xD7A3); + koreanIME = (HangulJamo | HangulCompatibleJamo | HangulSyllable + | HangulJamoExtendedA | HangulJamoExtendedB); + } + return koreanIME; +} + void ScintillaGTK::CommitThis(char *utfVal) { try { //~ fprintf(stderr, "Commit '%s'\n", utfVal); + if (pdoc->TentativeActive()) { + pdoc->TentativeUndo(); + } + + view.imeCaretBlockOverride = false; + if (IsUnicodeMode()) { AddCharUTF(utfVal, strlen(utfVal)); } else { @@ -2285,7 +2355,7 @@ void ScintillaGTK::CommitThis(char *utfVal) { if (*source) { Converter conv(source, "UTF-8", true); if (conv) { - char localeVal[4] = "\0\0\0"; + char localeVal[maxLenInputIME * 2]; char *pin = utfVal; size_t inLeft = strlen(utfVal); char *pout = localeVal; @@ -2293,15 +2363,14 @@ void ScintillaGTK::CommitThis(char *utfVal) { size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft); if (conversions != ((size_t)(-1))) { *pout = '\0'; - for (int i = 0; localeVal[i]; i++) { - AddChar(localeVal[i]); - } + AddCharUTF(localeVal, strlen(localeVal)); } else { fprintf(stderr, "Conversion failed '%s'\n", utfVal); } } } } + ShowCaretAtCurrentPosition(); } catch (...) { errorStatus = SC_STATUS_FAILURE; } @@ -2313,36 +2382,99 @@ void ScintillaGTK::Commit(GtkIMContext *, char *str, ScintillaGTK *sciThis) { void ScintillaGTK::PreeditChangedThis() { try { - gchar *str; - PangoAttrList *attrs; - gint cursor_pos; - gtk_im_context_get_preedit_string(im_context, &str, &attrs, &cursor_pos); - if (strlen(str) > 0) { - PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), str); - pango_layout_set_attributes(layout, attrs); - - gint w, h; - pango_layout_get_pixel_size(layout, &w, &h); - g_object_unref(layout); - - gint x, y; - gdk_window_get_origin(PWindow(wText), &x, &y); - - Point pt = PointMainCaret(); - if (pt.x < 0) - pt.x = 0; - if (pt.y < 0) - pt.y = 0; - - gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y); - gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h); - gtk_widget_show(PWidget(wPreedit)); - gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h); - } else { - gtk_widget_hide(PWidget(wPreedit)); + if (KoreanIME()) { + // Copy & paste by johnsonj. + // Great thanks to + // jiniya from
http://www.jiniya.net/tt/494
for DBCS input with AddCharUTF(). + // BLUEnLIVE from
http://zockr.tistory.com/1118
for UNDO and inOverstrike. + view.imeCaretBlockOverride = false; // If backspace. + + if (pdoc->TentativeActive()) { + pdoc->TentativeUndo(); + } else { + // No tentative undo means start of this composition so + // fill in any virtual spaces. + bool tmpOverstrike = inOverstrike; + inOverstrike = false; // Not allowed to be deleted twice. + AddCharUTF("", 0); + inOverstrike = tmpOverstrike; + } + + PreEditString utfval(im_context); + + if (strlen(utfval.str) > maxLenInputIME * 3) { + return; // Do not allow over 200 chars. + } + + char localeVal[maxLenInputIME * 2]; + char *hanval = (char *)""; + + if (IsUnicodeMode()) { + hanval = utfval.str; + } else { + const char *source = CharacterSetID(); + if (*source) { + Converter conv(source, "UTF-8", true); + if (conv) { + char *pin = utfval.str; + size_t inLeft = strlen(utfval.str); + char *pout = localeVal; + size_t outLeft = sizeof(localeVal); + size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft); + if (conversions != ((size_t)(-1))) { + *pout = '\0'; + hanval = localeVal; + } else { + fprintf(stderr, "Conversion failed '%s'\n", utfval.str); + } + } + } + } + + if (!pdoc->TentativeActive()) { + pdoc->TentativeStart(); + } + + bool tmpRecordingMacro = recordingMacro; + recordingMacro = false; + int hanlen = strlen(hanval); + AddCharUTF(hanval, hanlen); + recordingMacro = tmpRecordingMacro; + + // For block caret which means KoreanIME is in composition. + view.imeCaretBlockOverride = true; + for (size_t r = 0; r < sel.Count(); r++) { + int positionInsert = sel.Range(r).Start().Position(); + sel.Range(r).caret.SetPosition(positionInsert - hanlen); + sel.Range(r).anchor.SetPosition(positionInsert - hanlen); + } + } else { // Original code follows for other IMEs. + PreEditString pes(im_context); + if (strlen(pes.str) > 0) { + PangoLayout *layout = gtk_widget_create_pango_layout(PWidget(wText), pes.str); + pango_layout_set_attributes(layout, pes.attrs); + + gint w, h; + pango_layout_get_pixel_size(layout, &w, &h); + g_object_unref(layout); + + gint x, y; + gdk_window_get_origin(PWindow(wText), &x, &y); + + Point pt = PointMainCaret(); + if (pt.x < 0) + pt.x = 0; + if (pt.y < 0) + pt.y = 0; + + gtk_window_move(GTK_WINDOW(PWidget(wPreedit)), x + pt.x, y + pt.y); + gtk_window_resize(GTK_WINDOW(PWidget(wPreedit)), w, h); + gtk_widget_show(PWidget(wPreedit)); + gtk_widget_queue_draw_area(PWidget(wPreeditDraw), 0, 0, w, h); + } else { + gtk_widget_hide(PWidget(wPreedit)); + } } - g_free(str); - pango_attr_list_unref(attrs); } catch (...) { errorStatus = SC_STATUS_FAILURE; } @@ -2711,8 +2843,8 @@ void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context, } } -int ScintillaGTK::TimeOut(ScintillaGTK *sciThis) { - sciThis->Tick(); +int ScintillaGTK::TimeOut(TimeThunk *tt) { + tt->scintilla->TickFor(tt->reason); return 1; } Modified: scintilla/include/SciLexer.h 18 lines changed, 18 insertions(+), 0 deletions(-) =================================================================== @@ -127,6 +127,7 @@ #define SCLEX_DMAP 112 #define SCLEX_AS 113 #define SCLEX_DMIS 114 +#define SCLEX_REGISTRY 115 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 @@ -906,6 +907,7 @@ #define SCE_KIX_KEYWORD 7 #define SCE_KIX_FUNCTIONS 8 #define SCE_KIX_OPERATOR 9 +#define SCE_KIX_COMMENTSTREAM 10 #define SCE_KIX_IDENTIFIER 31 #define SCE_GC_DEFAULT 0 #define SCE_GC_COMMENTLINE 1 @@ -1692,6 +1694,9 @@ #define SCE_RUST_LIFETIME 18 #define SCE_RUST_MACRO 19 #define SCE_RUST_LEXERROR 20 +#define SCE_RUST_BYTESTRING 21 +#define SCE_RUST_BYTESTRINGR 22 +#define SCE_RUST_BYTECHARACTER 23 #define SCE_DMAP_DEFAULT 0 #define SCE_DMAP_COMMENT 1 #define SCE_DMAP_NUMBER 2 @@ -1713,6 +1718,19 @@ #define SCE_DMIS_UNSUPPORTED_MAJOR 7 #define SCE_DMIS_UNSUPPORTED_MINOR 8 #define SCE_DMIS_LABEL 9 +#define SCE_REG_DEFAULT 0 +#define SCE_REG_COMMENT 1 +#define SCE_REG_VALUENAME 2 +#define SCE_REG_STRING 3 +#define SCE_REG_HEXDIGIT 4 +#define SCE_REG_VALUETYPE 5 +#define SCE_REG_ADDEDKEY 6 +#define SCE_REG_DELETEDKEY 7 +#define SCE_REG_ESCAPED 8 +#define SCE_REG_KEYPATH_GUID 9 +#define SCE_REG_STRING_GUID 10 +#define SCE_REG_PARAMETER 11 +#define SCE_REG_OPERATOR 12 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ #endif Modified: scintilla/include/Scintilla.h 15 lines changed, 12 insertions(+), 3 deletions(-) =================================================================== @@ -18,9 +18,9 @@ extern "C" { #if defined(_WIN32) /* Return false on failure: */ int Scintilla_RegisterClasses(void *hInstance); -int Scintilla_ReleaseResources(); +int Scintilla_ReleaseResources(void); #endif -int Scintilla_LinkLexers(); +int Scintilla_LinkLexers(void); #ifdef __cplusplus } @@ -92,6 +92,9 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_SETBUFFEREDDRAW 2035 #define SCI_SETTABWIDTH 2036 #define SCI_GETTABWIDTH 2121 +#define SCI_CLEARTABSTOPS 2675 +#define SCI_ADDTABSTOP 2676 +#define SCI_GETNEXTTABSTOP 2677 #define SC_CP_UTF8 65001 #define SCI_SETCODEPAGE 2037 #define MARKER_MAX 31 @@ -517,6 +520,11 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_APPENDTEXT 2282 #define SCI_GETTWOPHASEDRAW 2283 #define SCI_SETTWOPHASEDRAW 2284 +#define SC_PHASES_ONE 0 +#define SC_PHASES_TWO 1 +#define SC_PHASES_MULTIPLE 2 +#define SCI_GETPHASESDRAW 2673 +#define SCI_SETPHASESDRAW 2674 #define SC_EFF_QUALITY_MASK 0xF #define SC_EFF_QUALITY_DEFAULT 0 #define SC_EFF_QUALITY_NON_ANTIALIASED 1 @@ -952,7 +960,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SC_MOD_CONTAINER 0x40000 #define SC_MOD_LEXERSTATE 0x80000 #define SC_MOD_INSERTCHECK 0x100000 -#define SC_MODEVENTMASKALL 0x1FFFFF +#define SC_MOD_CHANGETABSTOPS 0x200000 +#define SC_MODEVENTMASKALL 0x3FFFFF #define SC_UPDATE_CONTENT 0x1 #define SC_UPDATE_SELECTION 0x2 #define SC_UPDATE_V_SCROLL 0x4 Modified: scintilla/include/Scintilla.iface 48 lines changed, 46 insertions(+), 2 deletions(-) =================================================================== @@ -226,6 +226,15 @@ set void SetTabWidth=2036(int tabWidth,) # Retrieve the visible size of a tab. get int GetTabWidth=2121(,) +# Clear explicit tabstops on a line. +fun void ClearTabStops=2675(int line,) + +# Add an explicit tab stop for a line. +fun void AddTabStop=2676(int line, int x) + +# Find the next explicit tab stop position on a line after a position. +fun int GetNextTabStop=2677(int line, int x) + # The SC_CP_UTF8 value can be used to enter Unicode mode. # This is the same value as CP_UTF8 in Windows val SC_CP_UTF8=65001 @@ -1291,13 +1300,27 @@ get bool GetVScrollBar=2281(,) # Append a string to the end of the document without changing the selection. fun void AppendText=2282(int length, string text) -# Is drawing done in two phases with backgrounds drawn before faoregrounds? +# Is drawing done in two phases with backgrounds drawn before foregrounds? get bool GetTwoPhaseDraw=2283(,) # In twoPhaseDraw mode, drawing is performed in two phases, first the background # and then the foreground. This avoids chopping off characters that overlap the next run. set void SetTwoPhaseDraw=2284(bool twoPhase,) +enu FontQuality=SC_PHASES_ +val SC_PHASES_ONE=0 +val SC_PHASES_TWO=1 +val SC_PHASES_MULTIPLE=2 + +# How many phases is drawing done in? +get int GetPhasesDraw=2673(,) + +# In one phase draw, text is drawn in a series of rectangular blocks with no overlap. +# In two phase draw, text is drawn in a series of lines allowing runs to overlap horizontally. +# In multiple phase draw, each element is drawn over the whole drawing area, allowing text +# to overlap from one line to the next. +set void SetPhasesDraw=2674(int phases,) + # Control font anti-aliasing. enu FontQuality=SC_EFF_ @@ -2509,7 +2532,8 @@ val SC_MOD_CHANGEANNOTATION=0x20000 val SC_MOD_CONTAINER=0x40000 val SC_MOD_LEXERSTATE=0x80000 val SC_MOD_INSERTCHECK=0x100000 -val SC_MODEVENTMASKALL=0x1FFFFF +val SC_MOD_CHANGETABSTOPS=0x200000 +val SC_MODEVENTMASKALL=0x3FFFFF enu Update=SC_UPDATE_ val SC_UPDATE_CONTENT=0x1 @@ -2675,6 +2699,7 @@ val SCLEX_RUST=111 val SCLEX_DMAP=112 val SCLEX_AS=113 val SCLEX_DMIS=114 +val SCLEX_REGISTRY=115 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -3567,6 +3592,7 @@ val SCE_KIX_MACRO=6 val SCE_KIX_KEYWORD=7 val SCE_KIX_FUNCTIONS=8 val SCE_KIX_OPERATOR=9 +val SCE_KIX_COMMENTSTREAM=10 val SCE_KIX_IDENTIFIER=31 # Lexical states for SCLEX_GUI4CLI lex Gui4Cli=SCLEX_GUI4CLI SCE_GC_ @@ -4443,6 +4469,9 @@ val SCE_RUST_IDENTIFIER=17 val SCE_RUST_LIFETIME=18 val SCE_RUST_MACRO=19 val SCE_RUST_LEXERROR=20 +val SCE_RUST_BYTESTRING=21 +val SCE_RUST_BYTESTRINGR=22 +val SCE_RUST_BYTECHARACTER=23 # Lexical states for SCLEX_DMAP lex DMAP=SCLEX_DMAP SCE_DMAP_ val SCE_DMAP_DEFAULT=0 @@ -4468,6 +4497,21 @@ val SCE_DMIS_MINORWORD=6 val SCE_DMIS_UNSUPPORTED_MAJOR=7 val SCE_DMIS_UNSUPPORTED_MINOR=8 val SCE_DMIS_LABEL=9 +# Lexical states for SCLEX_REGISTRY +lex REG=SCLEX_REGISTRY SCE_REG_ +val SCE_REG_DEFAULT=0 +val SCE_REG_COMMENT=1 +val SCE_REG_VALUENAME=2 +val SCE_REG_STRING=3 +val SCE_REG_HEXDIGIT=4 +val SCE_REG_VALUETYPE=5 +val SCE_REG_ADDEDKEY=6 +val SCE_REG_DELETEDKEY=7 +val SCE_REG_ESCAPED=8 +val SCE_REG_KEYPATH_GUID=9 +val SCE_REG_STRING_GUID=10 +val SCE_REG_PARAMETER=11 +val SCE_REG_OPERATOR=12 # Events Modified: scintilla/lexers/LexHTML.cxx 12 lines changed, 10 insertions(+), 2 deletions(-) =================================================================== @@ -822,19 +822,27 @@ static void ColouriseHyperTextDoc(unsigned int startPos, int length, int initSty // handle start of Mako comment line if (isMako && ch == '#' && chNext == '#') { makoComment = 1; + state = SCE_HP_COMMENTLINE; } // handle end of Mako comment line else if (isMako && makoComment && (ch == '\r' || ch == '\n')) { makoComment = 0; - styler.ColourTo(i, SCE_HP_COMMENTLINE); - state = SCE_HP_DEFAULT; + styler.ColourTo(i, StateToPrint); + if (scriptLanguage == eScriptPython) { + state = SCE_HP_DEFAULT; + } else { + state = SCE_H_DEFAULT; + } } // Allow falling through to mako handling code if newline is going to end a block if (((ch == '\r' && chNext != '\n') || (ch == '\n')) && (!isMako || (0 != strcmp(makoBlockType, "%")))) { } + // Ignore everything in mako comment until the line ends + else if (isMako && makoComment) { + } // generic end of script processing else if ((inScriptType == eNonHtmlScript) && (ch == '<') && (chNext == '/')) { Modified: scintilla/lexers/LexMatlab.cxx 5 lines changed, 4 insertions(+), 1 deletions(-) =================================================================== @@ -12,6 +12,9 @@ ** - added ... displayed as a comment ** - removed unused IsAWord functions ** - added some comments + ** + ** Changes by John Donoghue 2014/08/01 + ** - fix allowed transpose ' after {} operator **/ // Copyright 1998-2001 by Neil Hodgson <neilh(a)scintilla.org> // The License.txt file describes the conditions under which this software may be distributed. @@ -218,7 +221,7 @@ static void ColouriseMatlabOctaveDoc( } else if (isalpha(sc.ch)) { sc.SetState(SCE_MATLAB_KEYWORD); } else if (isoperator(static_cast<char>(sc.ch)) || sc.ch == '@' || sc.ch == '\\') { - if (sc.ch == ')' || sc.ch == ']') { + if (sc.ch == ')' || sc.ch == ']' || sc.ch == '}') { transpose = true; } else { transpose = false; Modified: scintilla/lexers/LexRuby.cxx 36 lines changed, 35 insertions(+), 1 deletions(-) =================================================================== @@ -882,6 +882,31 @@ static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle, preferRE = false; } else if (isSafeWordcharOrHigh(chNext)) { state = SCE_RB_SYMBOL; + } else if ((chNext == '@' || chNext == '$') && + isSafeWordcharOrHigh(chNext2)) { + // instance and global variable followed by an identifier + advance_char(i, ch, chNext, chNext2); + state = SCE_RB_SYMBOL; + } else if (((chNext == '@' && chNext2 == '@') || + (chNext == '$' && chNext2 == '-')) && + isSafeWordcharOrHigh(styler.SafeGetCharAt(i+3))) { + // class variables and special global variable "$-IDENTCHAR" + state = SCE_RB_SYMBOL; + // $-IDENTCHAR doesn't continue past the IDENTCHAR + if (chNext == '$') { + styler.ColourTo(i+3, SCE_RB_SYMBOL); + state = SCE_RB_DEFAULT; + } + i += 3; + ch = styler.SafeGetCharAt(i); + chNext = styler.SafeGetCharAt(i+1); + } else if (chNext == '$' && strchr("_~*$?!(a)/\\;,.=:<>\"&`'+", chNext2)) { + // single-character special global variables + i += 2; + ch = chNext2; + chNext = styler.SafeGetCharAt(i+1); + styler.ColourTo(i, SCE_RB_SYMBOL); + state = SCE_RB_DEFAULT; } else if (strchr("[*!~+-*/%=<>&^|", chNext)) { // Do the operator analysis in-line, looking ahead // Based on the table in pickaxe 2nd ed., page 339 @@ -1260,7 +1285,16 @@ static void ColouriseRbDoc(unsigned int startPos, int length, int initStyle, } else if (state == SCE_RB_CLASS_VAR || state == SCE_RB_INSTANCE_VAR || state == SCE_RB_SYMBOL) { - if (!isSafeWordcharOrHigh(ch)) { + if (state == SCE_RB_SYMBOL && + // FIDs suffices '?' and '!' + (((ch == '!' || ch == '?') && chNext != '=') || + // identifier suffix '=' + (ch == '=' && (chNext != '~' && chNext != '>' && + (chNext != '=' || chNext2 == '>'))))) { + styler.ColourTo(i, state); + state = SCE_RB_DEFAULT; + preferRE = false; + } else if (!isSafeWordcharOrHigh(ch)) { styler.ColourTo(i - 1, state); redo_char(i, ch, chNext, chNext2, state); // pass by ref preferRE = false; Modified: scintilla/lexers/LexRust.cxx 105 lines changed, 69 insertions(+), 36 deletions(-) =================================================================== @@ -230,7 +230,9 @@ static void ScanIdentifier(Accessor& styler, int& pos, WordList *keywords) { } } -static void ScanDigits(Accessor& styler, int& pos, int base) { +/* Scans a sequence of digits, returning true if it found any. */ +static bool ScanDigits(Accessor& styler, int& pos, int base) { + int old_pos = pos; for (;;) { int c = styler.SafeGetCharAt(pos, '\0'); if (IsADigit(c, base) || c == '_') @@ -238,13 +240,17 @@ static void ScanDigits(Accessor& styler, int& pos, int base) { else break; } + return old_pos != pos; } +/* Scans an integer and floating point literals. */ static void ScanNumber(Accessor& styler, int& pos) { int base = 10; int c = styler.SafeGetCharAt(pos, '\0'); int n = styler.SafeGetCharAt(pos + 1, '\0'); bool error = false; + /* Scan the prefix, thus determining the base. + * 10 is default if there's no prefix. */ if (c == '0' && n == 'x') { pos += 2; base = 16; @@ -255,8 +261,11 @@ static void ScanNumber(Accessor& styler, int& pos) { pos += 2; base = 8; } - int old_pos = pos; - ScanDigits(styler, pos, base); + + /* Scan initial digits. The literal is malformed if there are none. */ + error |= !ScanDigits(styler, pos, base); + /* See if there's an integer suffix. We mimic the Rust's lexer + * and munch it even if there was an error above. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'u' || c == 'i') { pos++; @@ -271,14 +280,22 @@ static void ScanNumber(Accessor& styler, int& pos) { } else if (c == '6' && n == '4') { pos += 2; } - } else { + /* See if it's a floating point literal. These literals have to be base 10. + */ + } else if (!error) { + /* If there's a period, it's a floating point literal unless it's + * followed by an identifier (meaning this is a method call, e.g. + * `1.foo()`) or another period, in which case it's a range (e.g. 1..2) + */ n = styler.SafeGetCharAt(pos + 1, '\0'); if (c == '.' && !(IsIdentifierStart(n) || n == '.')) { error |= base != 10; pos++; + /* It's ok to have no digits after the period. */ ScanDigits(styler, pos, 10); } + /* Look for the exponentiation. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'e' || c == 'E') { error |= base != 10; @@ -286,13 +303,11 @@ static void ScanNumber(Accessor& styler, int& pos) { c = styler.SafeGetCharAt(pos, '\0'); if (c == '-' || c == '+') pos++; - int old_pos = pos; - ScanDigits(styler, pos, 10); - if (old_pos == pos) { - error = true; - } + /* It is invalid to have no digits in the exponent. */ + error |= !ScanDigits(styler, pos, 10); } + /* Scan the floating point suffix. */ c = styler.SafeGetCharAt(pos, '\0'); if (c == 'f') { error |= base != 10; @@ -308,9 +323,7 @@ static void ScanNumber(Accessor& styler, int& pos) { } } } - if (old_pos == pos) { - error = true; - } + if (error) styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); else @@ -351,7 +364,7 @@ static bool IsValidCharacterEscape(int c) { } static bool IsValidStringEscape(int c) { - return IsValidCharacterEscape(c) || c == '\n'; + return IsValidCharacterEscape(c) || c == '\n' || c == '\r'; } static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool stop_asap) { @@ -373,12 +386,12 @@ static bool ScanNumericEscape(Accessor &styler, int& pos, int num_digits, bool s /* This is overly permissive for character literals in order to accept UTF-8 encoded * character literals. */ -static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { +static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos, bool ascii_only) { pos++; int c = styler.SafeGetCharAt(pos, '\0'); int n = styler.SafeGetCharAt(pos + 1, '\0'); bool done = false; - bool valid_lifetime = IsIdentifierStart(c); + bool valid_lifetime = !ascii_only && IsIdentifierStart(c); bool valid_char = true; bool first = true; while (!done) { @@ -390,10 +403,10 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { } else if (n == 'x') { pos += 2; valid_char = ScanNumericEscape(styler, pos, 2, false); - } else if (n == 'u') { + } else if (n == 'u' && !ascii_only) { pos += 2; valid_char = ScanNumericEscape(styler, pos, 4, false); - } else if (n == 'U') { + } else if (n == 'U' && !ascii_only) { pos += 2; valid_char = ScanNumericEscape(styler, pos, 8, false); } else { @@ -412,7 +425,10 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { done = true; break; default: - if (!IsIdentifierContinue(c) && !first) { + if (ascii_only && !IsASCII((char)c)) { + done = true; + valid_char = false; + } else if (!IsIdentifierContinue(c) && !first) { done = true; } else { pos++; @@ -433,7 +449,7 @@ static void ScanCharacterLiteralOrLifetime(Accessor &styler, int& pos) { styler.ColourTo(pos - 1, SCE_RUST_LIFETIME); } else if (valid_char) { pos++; - styler.ColourTo(pos - 1, SCE_RUST_CHARACTER); + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTECHARACTER : SCE_RUST_CHARACTER); } else { styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); } @@ -542,7 +558,7 @@ static void ScanComments(Accessor &styler, int& pos, int max) { ResumeBlockComment(styler, pos, max, UnknownComment, 1); } -static void ResumeString(Accessor &styler, int& pos, int max) { +static void ResumeString(Accessor &styler, int& pos, int max, bool ascii_only) { int c = styler.SafeGetCharAt(pos, '\0'); bool error = false; while (c != '"' && !error) { @@ -559,10 +575,10 @@ static void ResumeString(Accessor &styler, int& pos, int max) { } else if (n == 'x') { pos += 2; error = !ScanNumericEscape(styler, pos, 2, true); - } else if (n == 'u') { + } else if (n == 'u' && !ascii_only) { pos += 2; error = !ScanNumericEscape(styler, pos, 4, true); - } else if (n == 'U') { + } else if (n == 'U' && !ascii_only) { pos += 2; error = !ScanNumericEscape(styler, pos, 8, true); } else { @@ -570,16 +586,19 @@ static void ResumeString(Accessor &styler, int& pos, int max) { error = true; } } else { - pos++; + if (ascii_only && !IsASCII((char)c)) + error = true; + else + pos++; } c = styler.SafeGetCharAt(pos, '\0'); } if (!error) pos++; - styler.ColourTo(pos - 1, SCE_RUST_STRING); + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRING : SCE_RUST_STRING); } -static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes) { +static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes, bool ascii_only) { for (;;) { if (pos == styler.LineEnd(styler.GetLine(pos))) styler.SetLineState(styler.GetLine(pos), num_hashes); @@ -594,19 +613,20 @@ static void ResumeRawString(Accessor &styler, int& pos, int max, int num_hashes) } if (trailing_num_hashes == num_hashes) { styler.SetLineState(styler.GetLine(pos), 0); - styler.ColourTo(pos - 1, SCE_RUST_STRINGR); break; } } else if (pos >= max) { - styler.ColourTo(pos - 1, SCE_RUST_STRINGR); break; - } else { + } else { + if (ascii_only && !IsASCII((char)c)) + break; pos++; } } + styler.ColourTo(pos - 1, ascii_only ? SCE_RUST_BYTESTRINGR : SCE_RUST_STRINGR); } -static void ScanRawString(Accessor &styler, int& pos, int max) { +static void ScanRawString(Accessor &styler, int& pos, int max, bool ascii_only) { pos++; int num_hashes = 0; while (styler.SafeGetCharAt(pos, '\0') == '#') { @@ -617,7 +637,7 @@ static void ScanRawString(Accessor &styler, int& pos, int max) { styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); } else { pos++; - ResumeRawString(styler, pos, max, num_hashes); + ResumeRawString(styler, pos, max, num_hashes, ascii_only); } } @@ -635,9 +655,13 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, } else if (initStyle == SCE_RUST_COMMENTLINE || initStyle == SCE_RUST_COMMENTLINEDOC) { ResumeLineComment(styler, pos, max, initStyle == SCE_RUST_COMMENTLINEDOC ? DocComment : NotDocComment); } else if (initStyle == SCE_RUST_STRING) { - ResumeString(styler, pos, max); + ResumeString(styler, pos, max, false); + } else if (initStyle == SCE_RUST_BYTESTRING) { + ResumeString(styler, pos, max, true); } else if (initStyle == SCE_RUST_STRINGR) { - ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1)); + ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), false); + } else if (initStyle == SCE_RUST_BYTESTRINGR) { + ResumeRawString(styler, pos, max, styler.GetLineState(styler.GetLine(pos) - 1), true); } while (pos < max) { @@ -645,7 +669,7 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, int n = styler.SafeGetCharAt(pos + 1, '\0'); int n2 = styler.SafeGetCharAt(pos + 2, '\0'); - if (pos == 0 && c == '#' && n == '!') { + if (pos == 0 && c == '#' && n == '!' && n2 != '[') { pos += 2; ResumeLineComment(styler, pos, max, NotDocComment); } else if (IsWhitespace(c)) { @@ -653,7 +677,16 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, } else if (c == '/' && (n == '/' || n == '*')) { ScanComments(styler, pos, max); } else if (c == 'r' && (n == '#' || n == '"')) { - ScanRawString(styler, pos, max); + ScanRawString(styler, pos, max, false); + } else if (c == 'b' && n == 'r' && (n2 == '#' || n2 == '"')) { + pos++; + ScanRawString(styler, pos, max, true); + } else if (c == 'b' && n == '"') { + pos += 2; + ResumeString(styler, pos, max, true); + } else if (c == 'b' && n == '\'') { + pos++; + ScanCharacterLiteralOrLifetime(styler, pos, true); } else if (IsIdentifierStart(c)) { ScanIdentifier(styler, pos, keywords); } else if (IsADigit(c)) { @@ -668,10 +701,10 @@ void SCI_METHOD LexerRust::Lex(unsigned int startPos, int length, int initStyle, pos++; styler.ColourTo(pos - 1, SCE_RUST_OPERATOR); } else if (c == '\'') { - ScanCharacterLiteralOrLifetime(styler, pos); + ScanCharacterLiteralOrLifetime(styler, pos, false); } else if (c == '"') { pos++; - ResumeString(styler, pos, max); + ResumeString(styler, pos, max, false); } else { pos++; styler.ColourTo(pos - 1, SCE_RUST_LEXERROR); Modified: scintilla/lexlib/LexerModule.h 7 lines changed, 6 insertions(+), 1 deletions(-) =================================================================== @@ -67,7 +67,12 @@ inline int Maximum(int a, int b) { // Shut up annoying Visual C++ warnings: #ifdef _MSC_VER -#pragma warning(disable: 4244 4309) +#pragma warning(disable: 4244 4309 4456 4457) +#endif + +// Turn off shadow warnings for lexers as may be maintained by others +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wshadow" #endif #ifdef SCI_NAMESPACE Modified: scintilla/makefile.win32 3 lines changed, 3 insertions(+), 0 deletions(-) =================================================================== @@ -130,10 +130,13 @@ SRCOBJS=\ Decoration.o \ Document.o \ Editor.o \ + EditModel.o \ + EditView.o \ ExternalLexer.o \ Indicator.o \ KeyMap.o \ LineMarker.o \ + MarginView.o \ PerLine.o \ PositionCache.o \ RESearch.o \ Modified: scintilla/scintilla_changes.patch 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -31,7 +31,7 @@ diff --git b/scintilla/src/Catalogue.cxx a/scintilla/src/Catalogue.cxx index 41d5d54..70ce3bc 100644 --- scintilla/src/Catalogue.cxx +++ scintilla/src/Catalogue.cxx -@@ -76,115 +76,48 @@ int Scintilla_LinkLexers() { +@@ -76,116 +76,48 @@ int Scintilla_LinkLexers() { //++Autogenerated -- run scripts/LexGen.py to regenerate //**\(\tLINK_LEXER(\*);\n\) @@ -123,6 +123,7 @@ index 41d5d54..70ce3bc 100644 LINK_LEXER(lmPython); LINK_LEXER(lmR); - LINK_LEXER(lmREBOL); +- LINK_LEXER(lmRegistry); LINK_LEXER(lmRuby); LINK_LEXER(lmRust); - LINK_LEXER(lmScriptol); Modified: scintilla/src/CellBuffer.cxx 40 lines changed, 39 insertions(+), 1 deletions(-) =================================================================== @@ -144,6 +144,7 @@ UndoHistory::UndoHistory() { currentAction = 0; undoSequenceDepth = 0; savePoint = 0; + tentativePoint = -1; actions[currentAction].Create(startAction); } @@ -194,7 +195,7 @@ const char *UndoHistory::AppendAction(actionType at, int position, const char *d // Visual Studio 2013 Code Analysis wrongly believes actions can be NULL at its next reference __analysis_assume(actions); #endif - if (currentAction == savePoint) { + if ((currentAction == savePoint) || (currentAction == tentativePoint)) { currentAction++; } else if (!actions[currentAction].mayCoalesce) { // Not allowed to coalesce if this set @@ -282,6 +283,7 @@ void UndoHistory::DeleteUndoHistory() { currentAction = 0; actions[currentAction].Create(startAction); savePoint = 0; + tentativePoint = -1; } void UndoHistory::SetSavePoint() { @@ -292,6 +294,26 @@ bool UndoHistory::IsSavePoint() const { return savePoint == currentAction; } +void UndoHistory::TentativeStart() { + tentativePoint = currentAction; +} + +void UndoHistory::TentativeCommit() { + tentativePoint = -1; + // Truncate undo history + maxAction = currentAction; +} + +int UndoHistory::TentativeSteps() { + // Drop any trailing startAction + if (actions[currentAction].at == startAction && currentAction > 0) + currentAction--; + if (tentativePoint >= 0) + return currentAction - tentativePoint; + else + return -1; +} + bool UndoHistory::CanUndo() const { return (currentAction > 0) && (maxAction > 0); } @@ -505,6 +527,22 @@ bool CellBuffer::IsSavePoint() const { return uh.IsSavePoint(); } +void CellBuffer::TentativeStart() { + uh.TentativeStart(); +} + +void CellBuffer::TentativeCommit() { + uh.TentativeCommit(); +} + +int CellBuffer::TentativeSteps() { + return uh.TentativeSteps(); +} + +bool CellBuffer::TentativeActive() const { + return uh.TentativeActive(); +} + // Without undo void CellBuffer::InsertLine(int line, int position, bool lineStart) { Modified: scintilla/src/CellBuffer.h 12 lines changed, 12 insertions(+), 0 deletions(-) =================================================================== @@ -95,6 +95,7 @@ class UndoHistory { int currentAction; int undoSequenceDepth; int savePoint; + int tentativePoint; void EnsureUndoRoom(); @@ -117,6 +118,12 @@ class UndoHistory { void SetSavePoint(); bool IsSavePoint() const; + // Tentative actions are used for input composition so that it can be undone cleanly + void TentativeStart(); + void TentativeCommit(); + bool TentativeActive() const { return tentativePoint >= 0; } + int TentativeSteps(); + /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is /// called that many times. Similarly for redo. bool CanUndo() const; @@ -193,6 +200,11 @@ class CellBuffer { void SetSavePoint(); bool IsSavePoint() const; + void TentativeStart(); + void TentativeCommit(); + bool TentativeActive() const; + int TentativeSteps(); + bool SetUndoCollection(bool collectUndo); bool IsCollectingUndo() const; void BeginUndoAction(); Modified: scintilla/src/ContractionState.cxx 18 lines changed, 9 insertions(+), 9 deletions(-) =================================================================== @@ -150,8 +150,8 @@ bool ContractionState::GetVisible(int lineDoc) const { } } -bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) { - if (OneToOne() && visible_) { +bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool isVisible) { + if (OneToOne() && isVisible) { return false; } else { EnsureData(); @@ -159,9 +159,9 @@ bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible Check(); if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) { for (int line = lineDocStart; line <= lineDocEnd; line++) { - if (GetVisible(line) != visible_) { - int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line); - visible->SetValueAt(line, visible_ ? 1 : 0); + if (GetVisible(line) != isVisible) { + int difference = isVisible ? heights->ValueAt(line) : -heights->ValueAt(line); + visible->SetValueAt(line, isVisible ? 1 : 0); displayLines->InsertText(line, difference); delta += difference; } @@ -191,13 +191,13 @@ bool ContractionState::GetExpanded(int lineDoc) const { } } -bool ContractionState::SetExpanded(int lineDoc, bool expanded_) { - if (OneToOne() && expanded_) { +bool ContractionState::SetExpanded(int lineDoc, bool isExpanded) { + if (OneToOne() && isExpanded) { return false; } else { EnsureData(); - if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) { - expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0); + if (isExpanded != (expanded->ValueAt(lineDoc) == 1)) { + expanded->SetValueAt(lineDoc, isExpanded ? 1 : 0); Check(); return true; } else { Modified: scintilla/src/ContractionState.h 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -48,11 +48,11 @@ class ContractionState { void DeleteLines(int lineDoc, int lineCount); bool GetVisible(int lineDoc) const; - bool SetVisible(int lineDocStart, int lineDocEnd, bool visible); + bool SetVisible(int lineDocStart, int lineDocEnd, bool isVisible); bool HiddenLines() const; bool GetExpanded(int lineDoc) const; - bool SetExpanded(int lineDoc, bool expanded); + bool SetExpanded(int lineDoc, bool isExpanded); int ContractedNext(int lineDocStart) const; int GetHeight(int lineDoc) const; Modified: scintilla/src/Document.cxx 59 lines changed, 59 insertions(+), 0 deletions(-) =================================================================== @@ -209,6 +209,65 @@ void Document::SetSavePoint() { NotifySavePoint(true); } +void Document::TentativeUndo() { + CheckReadOnly(); + if (enteredModification == 0) { + enteredModification++; + if (!cb.IsReadOnly()) { + bool startSavePoint = cb.IsSavePoint(); + bool multiLine = false; + int steps = cb.TentativeSteps(); + //Platform::DebugPrintf("Steps=%d\n", steps); + for (int step = 0; step < steps; step++) { + const int prevLinesTotal = LinesTotal(); + const Action &action = cb.GetUndoStep(); + if (action.at == removeAction) { + NotifyModified(DocModification( + SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action)); + } else if (action.at == containerAction) { + DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO); + dm.token = action.position; + NotifyModified(dm); + } else { + NotifyModified(DocModification( + SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action)); + } + cb.PerformUndoStep(); + if (action.at != containerAction) { + ModifiedAt(action.position); + } + + int modFlags = SC_PERFORMED_UNDO; + // With undo, an insertion action becomes a deletion notification + if (action.at == removeAction) { + modFlags |= SC_MOD_INSERTTEXT; + } else if (action.at == insertAction) { + modFlags |= SC_MOD_DELETETEXT; + } + if (steps > 1) + modFlags |= SC_MULTISTEPUNDOREDO; + const int linesAdded = LinesTotal() - prevLinesTotal; + if (linesAdded != 0) + multiLine = true; + if (step == steps - 1) { + modFlags |= SC_LASTSTEPINUNDOREDO; + if (multiLine) + modFlags |= SC_MULTILINEUNDOREDO; + } + NotifyModified(DocModification(modFlags, action.position, action.lenData, + linesAdded, action.data)); + } + + bool endSavePoint = cb.IsSavePoint(); + if (startSavePoint != endSavePoint) + NotifySavePoint(endSavePoint); + + cb.TentativeCommit(); + } + enteredModification--; + } +} + int Document::GetMark(int line) { return static_cast<LineMarkers *>(perLineData[ldMarkers])->MarkValue(line); } Modified: scintilla/src/Document.h 8 lines changed, 7 insertions(+), 1 deletions(-) =================================================================== @@ -303,6 +303,12 @@ class Document : PerLine, public IDocumentWithLineEnd, public ILoader { void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); } void SetSavePoint(); bool IsSavePoint() const { return cb.IsSavePoint(); } + + void TentativeStart() { cb.TentativeStart(); } + void TentativeCommit() { cb.TentativeCommit(); } + void TentativeUndo(); + bool TentativeActive() const { return cb.TentativeActive(); } + const char * SCI_METHOD BufferPointer() { return cb.BufferPointer(); } const char *RangePointer(int position, int rangeLength) { return cb.RangePointer(position, rangeLength); } int GapPosition() const { return cb.GapPosition(); } @@ -368,7 +374,7 @@ class Document : PerLine, public IDocumentWithLineEnd, public ILoader { void SetDefaultCharClasses(bool includeWordClass); void SetCharClasses(const unsigned char *chars, CharClassify::cc newCharClass); - int GetCharsOfClass(CharClassify::cc charClass, unsigned char *buffer); + int GetCharsOfClass(CharClassify::cc characterClass, unsigned char *buffer); void SCI_METHOD StartStyling(int position, char mask); bool SCI_METHOD SetStyleFor(int length, char style); bool SCI_METHOD SetStyles(int length, const char *styles); Modified: scintilla/src/EditModel.cxx 74 lines changed, 74 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,74 @@ +// Scintilla source code edit control +/** @file EditModel.cxx + ** Defines the editor state that must be visible to EditorView. + **/ +// Copyright 1998-2014 by Neil Hodgson <neilh(a)scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> +#include <ctype.h> + +#include <string> +#include <vector> +#include <map> +#include <algorithm> +#include <memory> + +#include "Platform.h" + +#include "ILexer.h" +#include "Scintilla.h" + +#include "StringCopy.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "CaseFolder.h" +#include "Document.h" +#include "UniConversion.h" +#include "Selection.h" +#include "PositionCache.h" +#include "EditModel.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +Caret::Caret() : + active(false), on(false), period(500) {} + +EditModel::EditModel() { + inOverstrike = false; + xOffset = 0; + trackLineWidth = false; + posDrag = SelectionPosition(invalidPosition); + braces[0] = invalidPosition; + braces[1] = invalidPosition; + bracesMatchStyle = STYLE_BRACEBAD; + highlightGuideColumn = 0; + primarySelection = true; + foldFlags = 0; + hotspot = Range(invalidPosition); + wrapWidth = LineLayout::wrapWidthInfinite; + pdoc = new Document(); + pdoc->AddRef(); +} + +EditModel::~EditModel() { + pdoc->Release(); + pdoc = 0; +} Modified: scintilla/src/EditModel.h 67 lines changed, 67 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,67 @@ +// Scintilla source code edit control +/** @file EditModel.h + ** Defines the editor state that must be visible to EditorView. + **/ +// Copyright 1998-2014 by Neil Hodgson <neilh(a)scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef EDITMODEL_H +#define EDITMODEL_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +/** +*/ +class Caret { +public: + bool active; + bool on; + int period; + + Caret(); +}; + +class EditModel { + // Private so EditModel objects can not be copied + EditModel(const EditModel &); + EditModel &operator=(const EditModel &); + +public: + bool inOverstrike; + int xOffset; ///< Horizontal scrolled amount in pixels + bool trackLineWidth; + + SpecialRepresentations reprs; + Caret caret; + SelectionPosition posDrag; + Position braces[2]; + int bracesMatchStyle; + int highlightGuideColumn; + Selection sel; + bool primarySelection; + + int foldFlags; + ContractionState cs; + // Hotspot support + Range hotspot; + + // Wrapping support + int wrapWidth; + + Document *pdoc; + + EditModel(); + virtual ~EditModel(); + virtual int TopLineOfMain() const = 0; + virtual Point GetVisibleOriginInMain() const = 0; + virtual int LinesOnScreen() const = 0; + virtual Range GetHotSpotRange() const = 0; +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif Modified: scintilla/src/EditView.cxx 2072 lines changed, 2072 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,2072 @@ +// Scintilla source code edit control +/** @file Editor.cxx + ** Defines the appearance of the main text area of the editor window. + **/ +// Copyright 1998-2014 by Neil Hodgson <neilh(a)scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> +#include <ctype.h> + +#include <string> +#include <vector> +#include <map> +#include <algorithm> +#include <memory> + +#include "Platform.h" + +#include "ILexer.h" +#include "Scintilla.h" + +#include "StringCopy.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "ContractionState.h" +#include "CellBuffer.h" +#include "PerLine.h" +#include "KeyMap.h" +#include "Indicator.h" +#include "XPM.h" +#include "LineMarker.h" +#include "Style.h" +#include "ViewStyle.h" +#include "CharClassify.h" +#include "Decoration.h" +#include "CaseFolder.h" +#include "Document.h" +#include "UniConversion.h" +#include "Selection.h" +#include "PositionCache.h" +#include "EditModel.h" +#include "MarginView.h" +#include "EditView.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +static inline bool IsControlCharacter(int ch) { + // iscntrl returns true for lots of chars > 127 which are displayable + return ch >= 0 && ch < ' '; +} + +PrintParameters::PrintParameters() { + magnification = 0; + colourMode = SC_PRINT_NORMAL; + wrapState = eWrapWord; +} + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +bool ValidStyledText(const ViewStyle &vs, size_t styleOffset, const StyledText &st) { + if (st.multipleStyles) { + for (size_t iStyle = 0; iStyle<st.length; iStyle++) { + if (!vs.ValidStyle(styleOffset + st.styles[iStyle])) + return false; + } + } else { + if (!vs.ValidStyle(styleOffset + st.style)) + return false; + } + return true; +} + +static int WidthStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, + const char *text, const unsigned char *styles, size_t len) { + int width = 0; + size_t start = 0; + while (start < len) { + size_t style = styles[start]; + size_t endSegment = start; + while ((endSegment + 1 < len) && (static_cast<size_t>(styles[endSegment + 1]) == style)) + endSegment++; + FontAlias fontText = vs.styles[style + styleOffset].font; + width += static_cast<int>(surface->WidthText(fontText, text + start, + static_cast<int>(endSegment - start + 1))); + start = endSegment + 1; + } + return width; +} + +int WidestLineWidth(Surface *surface, const ViewStyle &vs, int styleOffset, const StyledText &st) { + int widthMax = 0; + size_t start = 0; + while (start < st.length) { + size_t lenLine = st.LineLength(start); + int widthSubLine; + if (st.multipleStyles) { + widthSubLine = WidthStyledText(surface, vs, styleOffset, st.text + start, st.styles + start, lenLine); + } else { + FontAlias fontText = vs.styles[styleOffset + st.style].font; + widthSubLine = static_cast<int>(surface->WidthText(fontText, + st.text + start, static_cast<int>(lenLine))); + } + if (widthSubLine > widthMax) + widthMax = widthSubLine; + start += lenLine + 1; + } + return widthMax; +} + +void DrawTextNoClipPhase(Surface *surface, PRectangle rc, const Style &style, XYPOSITION ybase, + const char *s, int len, DrawPhase phase) { + FontAlias fontText = style.font; + if (phase & drawBack) { + if (phase & drawText) { + // Drawing both + surface->DrawTextNoClip(rc, fontText, ybase, s, len, + style.fore, style.back); + } else { + surface->FillRectangle(rc, style.back); + } + } else if (phase & drawText) { + surface->DrawTextTransparent(rc, fontText, ybase, s, len, style.fore); + } +} + +void DrawStyledText(Surface *surface, const ViewStyle &vs, int styleOffset, PRectangle rcText, + const StyledText &st, size_t start, size_t length, DrawPhase phase) { + + if (st.multipleStyles) { + int x = static_cast<int>(rcText.left); + size_t i = 0; + while (i < length) { + size_t end = i; + size_t style = st.styles[i + start]; + while (end < length - 1 && st.styles[start + end + 1] == style) + end++; + style += styleOffset; + FontAlias fontText = vs.styles[style].font; + const int width = static_cast<int>(surface->WidthText(fontText, + st.text + start + i, static_cast<int>(end - i + 1))); + PRectangle rcSegment = rcText; + rcSegment.left = static_cast<XYPOSITION>(x); + rcSegment.right = static_cast<XYPOSITION>(x + width + 1); + DrawTextNoClipPhase(surface, rcSegment, vs.styles[style], + rcText.top + vs.maxAscent, st.text + start + i, + static_cast<int>(end - i + 1), phase); + x += width; + i = end + 1; + } + } else { + const size_t style = st.style + styleOffset; + DrawTextNoClipPhase(surface, rcText, vs.styles[style], + rcText.top + vs.maxAscent, st.text + start, + static_cast<int>(length), phase); + } +} + +#ifdef SCI_NAMESPACE +} +#endif + +const XYPOSITION epsilon = 0.0001f; // A small nudge to avoid floating point precision issues + +EditView::EditView() { + ldTabstops = NULL; + hideSelection = false; + drawOverstrikeCaret = true; + bufferedDraw = true; + phasesDraw = phasesTwo; + lineWidthMaxSeen = 0; + additionalCaretsBlink = true; + additionalCaretsVisible = true; + imeCaretBlockOverride = false; + pixmapLine = 0; + pixmapIndentGuide = 0; + pixmapIndentGuideHighlight = 0; + llc.SetLevel(LineLayoutCache::llcCaret); + posCache.SetSize(0x400); +} + +EditView::~EditView() { + delete ldTabstops; + ldTabstops = NULL; +} + +bool EditView::SetTwoPhaseDraw(bool twoPhaseDraw) { + const PhasesDraw phasesDrawNew = twoPhaseDraw ? phasesTwo : phasesOne; + const bool redraw = phasesDraw != phasesDrawNew; + phasesDraw = phasesDrawNew; + return redraw; +} + +bool EditView::SetPhasesDraw(int phases) { + const PhasesDraw phasesDrawNew = static_cast<PhasesDraw>(phases); + const bool redraw = phasesDraw != phasesDrawNew; + phasesDraw = phasesDrawNew; + return redraw; +} + +bool EditView::LinesOverlap() const { + return phasesDraw == phasesMultiple; +} + +void EditView::ClearAllTabstops() { + delete ldTabstops; + ldTabstops = 0; +} + +int EditView::NextTabstopPos(int line, int x, int tabWidth) const { + int next = GetNextTabstop(line, x); + if (next > 0) + return next; + return ((((x + 2) / tabWidth) + 1) * tabWidth); +} + +bool EditView::ClearTabstops(int line) { + LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops); + return lt && lt->ClearTabstops(line); +} + +bool EditView::AddTabstop(int line, int x) { + if (!ldTabstops) { + ldTabstops = new LineTabstops(); + } + LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops); + return lt && lt->AddTabstop(line, x); +} + +int EditView::GetNextTabstop(int line, int x) const { + LineTabstops *lt = static_cast<LineTabstops *>(ldTabstops); + if (lt) { + return lt->GetNextTabstop(line, x); + } else { + return 0; + } +} + +void EditView::LinesAddedOrRemoved(int lineOfPos, int linesAdded) { + if (ldTabstops) { + if (linesAdded > 0) { + for (int line = lineOfPos; line < lineOfPos + linesAdded; line++) { + ldTabstops->InsertLine(line); + } + } else { + for (int line = (lineOfPos + -linesAdded) - 1; line >= lineOfPos; line--) { + ldTabstops->RemoveLine(line); + } + } + } +} + +void EditView::DropGraphics(bool freeObjects) { + if (freeObjects) { + delete pixmapLine; + pixmapLine = 0; + delete pixmapIndentGuide; + pixmapIndentGuide = 0; + delete pixmapIndentGuideHighlight; + pixmapIndentGuideHighlight = 0; + } else { + if (pixmapLine) + pixmapLine->Release(); + if (pixmapIndentGuide) + pixmapIndentGuide->Release(); + if (pixmapIndentGuideHighlight) + pixmapIndentGuideHighlight->Release(); + } +} + +void EditView::AllocateGraphics(const ViewStyle &vsDraw) { + if (!pixmapLine) + pixmapLine = Surface::Allocate(vsDraw.technology); + if (!pixmapIndentGuide) + pixmapIndentGuide = Surface::Allocate(vsDraw.technology); + if (!pixmapIndentGuideHighlight) + pixmapIndentGuideHighlight = Surface::Allocate(vsDraw.technology); +} + +const char *ControlCharacterString(unsigned char ch) { + const char *reps[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", + "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", + "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" + }; + if (ch < ELEMENTS(reps)) { + return reps[ch]; + } else { + return "BAD"; + } +} + +void DrawTabArrow(Surface *surface, PRectangle rcTab, int ymid) { + int ydiff = static_cast<int>(rcTab.bottom - rcTab.top) / 2; + int xhead = static_cast<int>(rcTab.right) - 1 - ydiff; + if (xhead <= rcTab.left) { + ydiff -= static_cast<int>(rcTab.left) - xhead - 1; + xhead = static_cast<int>(rcTab.left) - 1; + } + if ((rcTab.left + 2) < (rcTab.right - 1)) + surface->MoveTo(static_cast<int>(rcTab.left) + 2, ymid); + else + surface->MoveTo(static_cast<int>(rcTab.right) - 1, ymid); + surface->LineTo(static_cast<int>(rcTab.right) - 1, ymid); + surface->LineTo(xhead, ymid - ydiff); + surface->MoveTo(static_cast<int>(rcTab.right) - 1, ymid); + surface->LineTo(xhead, ymid + ydiff); +} + +void EditView::RefreshPixMaps(Surface *surfaceWindow, WindowID wid, const ViewStyle &vsDraw) { + if (!pixmapIndentGuide->Initialised()) { + // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line + pixmapIndentGuide->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid); + pixmapIndentGuideHighlight->InitPixMap(1, vsDraw.lineHeight + 1, surfaceWindow, wid); + PRectangle rcIG = PRectangle::FromInts(0, 0, 1, vsDraw.lineHeight); + pixmapIndentGuide->FillRectangle(rcIG, vsDraw.styles[STYLE_INDENTGUIDE].back); + pixmapIndentGuide->PenColour(vsDraw.styles[STYLE_INDENTGUIDE].fore); + pixmapIndentGuideHighlight->FillRectangle(rcIG, vsDraw.styles[STYLE_BRACELIGHT].back); + pixmapIndentGuideHighlight->PenColour(vsDraw.styles[STYLE_BRACELIGHT].fore); + for (int stripe = 1; stripe < vsDraw.lineHeight + 1; stripe += 2) { + PRectangle rcPixel = PRectangle::FromInts(0, stripe, 1, stripe + 1); + pixmapIndentGuide->FillRectangle(rcPixel, vsDraw.styles[STYLE_INDENTGUIDE].fore); + pixmapIndentGuideHighlight->FillRectangle(rcPixel, vsDraw.styles[STYLE_BRACELIGHT].fore); + } + } +} + +LineLayout *EditView::RetrieveLineLayout(int lineNumber, const EditModel &model) { + int posLineStart = model.pdoc->LineStart(lineNumber); + int posLineEnd = model.pdoc->LineStart(lineNumber + 1); + PLATFORM_ASSERT(posLineEnd >= posLineStart); + int lineCaret = model.pdoc->LineFromPosition(model.sel.MainCaret()); + return llc.Retrieve(lineNumber, lineCaret, + posLineEnd - posLineStart, model.pdoc->GetStyleClock(), + model.LinesOnScreen() + 1, model.pdoc->LinesTotal()); +} + +/** +* Fill in the LineLayout data for the given line. +* Copy the given @a line and its styles from the document into local arrays. +* Also determine the x position at which each character starts. +*/ +void EditView::LayoutLine(const EditModel &model, int line, Surface *surface, const ViewStyle &vstyle, LineLayout *ll, int width) { + if (!ll) + return; + + PLATFORM_ASSERT(line < model.pdoc->LinesTotal()); + PLATFORM_ASSERT(ll->chars != NULL); + int posLineStart = model.pdoc->LineStart(line); + int posLineEnd = model.pdoc->LineStart(line + 1); + // If the line is very long, limit the treatment to a length that should fit in the viewport + if (posLineEnd >(posLineStart + ll->maxLineLength)) { + posLineEnd = posLineStart + ll->maxLineLength; + } + if (ll->validity == LineLayout::llCheckTextAndStyle) { + int lineLength = posLineEnd - posLineStart; + if (!vstyle.viewEOL) { + lineLength = model.pdoc->LineEnd(line) - posLineStart; + } + if (lineLength == ll->numCharsInLine) { + // See if chars, styles, indicators, are all the same + bool allSame = true; + // Check base line layout + char styleByte = 0; + int numCharsInLine = 0; + while (numCharsInLine < lineLength) { + int charInDoc = numCharsInLine + posLineStart; + char chDoc = model.pdoc->CharAt(charInDoc); + styleByte = model.pdoc->StyleAt(charInDoc); + allSame = allSame && + (ll->styles[numCharsInLine] == static_cast<unsigned char>(styleByte)); + if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseMixed) + allSame = allSame && + (ll->chars[numCharsInLine] == chDoc); + else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower) + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast<char>(tolower(chDoc))); + else // Style::caseUpper + allSame = allSame && + (ll->chars[numCharsInLine] == static_cast<char>(toupper(chDoc))); + numCharsInLine++; + } + allSame = allSame && (ll->styles[numCharsInLine] == styleByte); // For eolFilled + if (allSame) { + ll->validity = LineLayout::llPositions; + } else { + ll->validity = LineLayout::llInvalid; + } + } else { + ll->validity = LineLayout::llInvalid; + } + } + if (ll->validity == LineLayout::llInvalid) { + ll->widthLine = LineLayout::wrapWidthInfinite; + ll->lines = 1; + if (vstyle.edgeState == EDGE_BACKGROUND) { + ll->edgeColumn = model.pdoc->FindColumn(line, vstyle.theEdge); + if (ll->edgeColumn >= posLineStart) { + ll->edgeColumn -= posLineStart; + } + } else { + ll->edgeColumn = -1; + } + + // Fill base line layout + const int lineLength = posLineEnd - posLineStart; + model.pdoc->GetCharRange(ll->chars, posLineStart, lineLength); + model.pdoc->GetStyleRange(ll->styles, posLineStart, lineLength); + int numCharsBeforeEOL = model.pdoc->LineEnd(line) - posLineStart; + const int numCharsInLine = (vstyle.viewEOL) ? lineLength : numCharsBeforeEOL; + for (int styleInLine = 0; styleInLine < numCharsInLine; styleInLine++) { + const unsigned char styleByte = ll->styles[styleInLine]; + ll->styles[styleInLine] = styleByte; + } + const unsigned char styleByteLast = (lineLength > 0) ? ll->styles[lineLength - 1] : 0; + if (vstyle.someStylesForceCase) { + for (int charInLine = 0; charInLine<lineLength; charInLine++) { + char chDoc = ll->chars[charInLine]; + if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseUpper) + ll->chars[charInLine] = static_cast<char>(toupper(chDoc)); + else if (vstyle.styles[ll->styles[charInLine]].caseForce == Style::caseLower) + ll->chars[charInLine] = static_cast<char>(tolower(chDoc)); + } + } + ll->xHighlightGuide = 0; + // Extra element at the end of the line to hold end x position and act as + ll->chars[numCharsInLine] = 0; // Also triggers processing in the loops as this is a control character + ll->styles[numCharsInLine] = styleByteLast; // For eolFilled + + // Layout the line, determining the position of each character, + // with an extra element at the end for the end of the line. + ll->positions[0] = 0; + bool lastSegItalics = false; + + BreakFinder bfLayout(ll, NULL, Range(0, numCharsInLine), posLineStart, 0, false, model.pdoc, &model.reprs); + while (bfLayout.More()) { + + const TextSegment ts = bfLayout.Next(); + + std::fill(&ll->positions[ts.start + 1], &ll->positions[ts.end() + 1], 0.0f); + if (vstyle.styles[ll->styles[ts.start]].visible) { + if (ts.representation) { + XYPOSITION representationWidth = vstyle.controlCharWidth; + if (ll->chars[ts.start] == '\t') { + // Tab is a special case of representation, taking a variable amount of space + const int x = static_cast<int>(ll->positions[ts.start]); + const int tabWidth = static_cast<int>(vstyle.tabWidth); + representationWidth = static_cast<XYPOSITION>(NextTabstopPos(line, x, tabWidth) - ll->positions[ts.start]); + } else { + if (representationWidth <= 0.0) { + XYPOSITION positionsRepr[256]; // Should expand when needed + posCache.MeasureWidths(surface, vstyle, STYLE_CONTROLCHAR, ts.representation->stringRep.c_str(), + static_cast<unsigned int>(ts.representation->stringRep.length()), positionsRepr, model.pdoc); + representationWidth = positionsRepr[ts.representation->stringRep.length() - 1] + vstyle.ctrlCharPadding; + } + } + for (int ii = 0; ii < ts.length; ii++) + ll->positions[ts.start + 1 + ii] = representationWidth; + } else { + if ((ts.length == 1) && (' ' == ll->chars[ts.start])) { + // Over half the segments are single characters and of these about half are space characters. + ll->positions[ts.start + 1] = vstyle.styles[ll->styles[ts.start]].spaceWidth; + } else { + posCache.MeasureWidths(surface, vstyle, ll->styles[ts.start], ll->chars + ts.start, + ts.length, ll->positions + ts.start + 1, model.pdoc); + } + } + lastSegItalics = (!ts.representation) && ((ll->chars[ts.end() - 1] != ' ') && vstyle.styles[ll->styles[ts.start]].italic); + } + + for (int posToIncrease = ts.start + 1; posToIncrease <= ts.end(); posToIncrease++) { + ll->positions[posToIncrease] += ll->positions[ts.start]; + } + } + + // Small hack to make lines that end with italics not cut off the edge of the last character + if (lastSegItalics) { + ll->positions[numCharsInLine] += vstyle.lastSegItalicsOffset; + } + ll->numCharsInLine = numCharsInLine; + ll->numCharsBeforeEOL = numCharsBeforeEOL; + ll->validity = LineLayout::llPositions; + } + // Hard to cope when too narrow, so just assume there is space + if (width < 20) { + width = 20; + } + if ((ll->validity == LineLayout::llPositions) || (ll->widthLine != width)) { + ll->widthLine = width; + if (width == LineLayout::wrapWidthInfinite) { + ll->lines = 1; + } else if (width > ll->positions[ll->numCharsInLine]) { + // Simple common case where line does not need wrapping. + ll->lines = 1; + } else { + if (vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { + width -= static_cast<int>(vstyle.aveCharWidth); // take into account the space for end wrap mark + } + XYPOSITION wrapAddIndent = 0; // This will be added to initial indent of line + if (vstyle.wrapIndentMode == SC_WRAPINDENT_INDENT) { + wrapAddIndent = model.pdoc->IndentSize() * vstyle.spaceWidth; + } else if (vstyle.wrapIndentMode == SC_WRAPINDENT_FIXED) { + wrapAddIndent = vstyle.wrapVisualStartIndent * vstyle.aveCharWidth; + } + ll->wrapIndent = wrapAddIndent; + if (vstyle.wrapIndentMode != SC_WRAPINDENT_FIXED) + for (int i = 0; i < ll->numCharsInLine; i++) { + if (!IsSpaceOrTab(ll->chars[i])) { + ll->wrapIndent += ll->positions[i]; // Add line indent + break; + } + } + // Check for text width minimum + if (ll->wrapIndent > width - static_cast<int>(vstyle.aveCharWidth) * 15) + ll->wrapIndent = wrapAddIndent; + // Check for wrapIndent minimum + if ((vstyle.wrapVisualFlags & SC_WRAPVISUALFLAG_START) && (ll->wrapIndent < vstyle.aveCharWidth)) + ll->wrapIndent = vstyle.aveCharWidth; // Indent to show start visual + ll->lines = 0; + // Calculate line start positions based upon width. + int lastGoodBreak = 0; + int lastLineStart = 0; + XYACCUMULATOR startOffset = 0; + int p = 0; + while (p < ll->numCharsInLine) { + if ((ll->positions[p + 1] - startOffset) >= width) { + if (lastGoodBreak == lastLineStart) { + // Try moving to start of last character + if (p > 0) { + lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) + - posLineStart; + } + if (lastGoodBreak == lastLineStart) { + // Ensure at least one character on line. + lastGoodBreak = model.pdoc->MovePositionOutsideChar(lastGoodBreak + posLineStart + 1, 1) + - posLineStart; + } + } + lastLineStart = lastGoodBreak; + ll->lines++; + ll->SetLineStart(ll->lines, lastGoodBreak); + startOffset = ll->positions[lastGoodBreak]; + // take into account the space for start wrap mark and indent + startOffset -= ll->wrapIndent; + p = lastGoodBreak + 1; + continue; + } + if (p > 0) { + if (vstyle.wrapState == eWrapChar) { + lastGoodBreak = model.pdoc->MovePositionOutsideChar(p + posLineStart, -1) + - posLineStart; + p = model.pdoc->MovePositionOutsideChar(p + 1 + posLineStart, 1) - posLineStart; + continue; + } else if ((vstyle.wrapState == eWrapWord) && (ll->styles[p] != ll->styles[p - 1])) { + lastGoodBreak = p; + } else if (IsSpaceOrTab(ll->chars[p - 1]) && !IsSpaceOrTab(ll->chars[p])) { + lastGoodBreak = p; + } + } + p++; + } + ll->lines++; + } + ll->validity = LineLayout::llLines; + } +} + +Point EditView::LocationFromPosition(Surface *surface, const EditModel &model, SelectionPosition pos, int topLine, const ViewStyle &vs) { + Point pt; + if (pos.Position() == INVALID_POSITION) + return pt; + const int line = model.pdoc->LineFromPosition(pos.Position()); + const int lineVisible = model.cs.DisplayFromDoc(line); + //Platform::DebugPrintf("line=%d\n", line); + AutoLineLayout ll(llc, RetrieveLineLayout(line, model)); + if (surface && ll) { + const int posLineStart = model.pdoc->LineStart(line); + LayoutLine(model, line, surface, vs, ll, model.wrapWidth); + const int posInLine = pos.Position() - posLineStart; + pt = ll->PointFromPosition(posInLine, vs.lineHeight); + pt.y += (lineVisible - topLine) * vs.lineHeight; + pt.x += vs.textStart - model.xOffset; + } + pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth; + return pt; +} + +SelectionPosition EditView::SPositionFromLocation(Surface *surface, const EditModel &model, Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace, const ViewStyle &vs) { + pt.x = pt.x - vs.textStart; + int visibleLine = static_cast<int>(floor(pt.y / vs.lineHeight)); + if (!canReturnInvalid && (visibleLine < 0)) + visibleLine = 0; + const int lineDoc = model.cs.DocFromDisplay(visibleLine); + if (canReturnInvalid && (lineDoc < 0)) + return SelectionPosition(INVALID_POSITION); + if (lineDoc >= model.pdoc->LinesTotal()) + return SelectionPosition(canReturnInvalid ? INVALID_POSITION : model.pdoc->Length()); + const int posLineStart = model.pdoc->LineStart(lineDoc); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + const int lineStartSet = model.cs.DisplayFromDoc(lineDoc); + const int subLine = visibleLine - lineStartSet; + if (subLine < ll->lines) { + const Range rangeSubLine = ll->SubLineRange(subLine); + const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; + if (subLine > 0) // Wrapped + pt.x -= ll->wrapIndent; + const int positionInLine = ll->FindPositionFromX(pt.x + subLineStart, rangeSubLine, charPosition); + if (positionInLine < rangeSubLine.end) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); + } + if (virtualSpace) { + const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; + const int spaceOffset = static_cast<int>( + (pt.x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); + return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); + } else if (canReturnInvalid) { + if (pt.x < (ll->positions[rangeSubLine.end] - subLineStart)) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(rangeSubLine.end + posLineStart, 1)); + } + } else { + return SelectionPosition(rangeSubLine.end + posLineStart); + } + } + if (!canReturnInvalid) + return SelectionPosition(ll->numCharsInLine + posLineStart); + } + return SelectionPosition(canReturnInvalid ? INVALID_POSITION : posLineStart); +} + +/** +* Find the document position corresponding to an x coordinate on a particular document line. +* Ensure is between whole characters when document is in multi-byte or UTF-8 mode. +* This method is used for rectangular selections and does not work on wrapped lines. +*/ +SelectionPosition EditView::SPositionFromLineX(Surface *surface, const EditModel &model, int lineDoc, int x, const ViewStyle &vs) { + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + const int posLineStart = model.pdoc->LineStart(lineDoc); + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + const Range rangeSubLine = ll->SubLineRange(0); + const XYPOSITION subLineStart = ll->positions[rangeSubLine.start]; + const int positionInLine = ll->FindPositionFromX(x + subLineStart, rangeSubLine, false); + if (positionInLine < rangeSubLine.end) { + return SelectionPosition(model.pdoc->MovePositionOutsideChar(positionInLine + posLineStart, 1)); + } + const XYPOSITION spaceWidth = vs.styles[ll->EndLineStyle()].spaceWidth; + const int spaceOffset = static_cast<int>( + (x + subLineStart - ll->positions[rangeSubLine.end] + spaceWidth / 2) / spaceWidth); + return SelectionPosition(rangeSubLine.end + posLineStart, spaceOffset); + } + return SelectionPosition(0); +} + +int EditView::DisplayFromPosition(Surface *surface, const EditModel &model, int pos, const ViewStyle &vs) { + int lineDoc = model.pdoc->LineFromPosition(pos); + int lineDisplay = model.cs.DisplayFromDoc(lineDoc); + AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model)); + if (surface && ll) { + LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth); + unsigned int posLineStart = model.pdoc->LineStart(lineDoc); + int posInLine = pos - posLineStart; + lineDisplay--; // To make up for first increment ahead. + for (int subLine = 0; subLine < ll->lines; subLine++) { + if (posInLine >= ll->LineStart(subLine)) { + lineDisplay++; + } + } + } + return lineDisplay; +} + +int EditView::StartEndDisplayLine(Surface *surface, const EditModel &model, int pos, bool start, const ViewStyle &vs) { + int line = model.pdoc->LineFromPosition(pos); + AutoLineLayout ll(llc, RetrieveLineLayout(line, model)); + int posRet = INVALID_POSITION; + if (surface && ll) { + unsigned int posLineStart = model.pdoc->LineStart(line); + LayoutLine(model, line, surface, vs, ll, model.wrapWidth); + int posInLine = pos - posLineStart; + if (posInLine <= ll->maxLineLength) { + for (int subLine = 0; subLine < ll->lines; subLine++) { + if ((posInLine >= ll->LineStart(subLine)) && (posInLine <= ll->LineStart(subLine + 1))) { + if (start) { + posRet = ll->LineStart(subLine) + posLineStart; + } else { + if (subLine == ll->lines - 1) + posRet = ll->LineStart(subLine + 1) + posLineStart; + else + posRet = ll->LineStart(subLine + 1) + posLineStart - 1; + } + } + } + } + } + return posRet; +} + +static ColourDesired SelectionBackground(const ViewStyle &vsDraw, bool main, bool primarySelection) { + return main ? + (primarySelection ? vsDraw.selColours.back : vsDraw.selBackground2) : + vsDraw.selAdditionalBackground; +} + +static ColourDesired TextBackground(const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + ColourOptional background, int inSelection, bool inHotspot, int styleMain, int i) { + if (inSelection == 1) { + if (vsDraw.selColours.back.isSet && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { + return SelectionBackground(vsDraw, true, model.primarySelection); + } + } else if (inSelection == 2) { + if (vsDraw.selColours.back.isSet && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) { + return SelectionBackground(vsDraw, false, model.primarySelection); + } + } else { + if ((vsDraw.edgeState == EDGE_BACKGROUND) && + (i >= ll->edgeColumn) && + (i < ll->numCharsBeforeEOL)) + return vsDraw.edgecolour; + if (inHotspot && vsDraw.hotspotColours.back.isSet) + return vsDraw.hotspotColours.back; + } + if (background.isSet && (styleMain != STYLE_BRACELIGHT) && (styleMain != STYLE_BRACEBAD)) { + return background; + } else { + return vsDraw.styles[styleMain].back; + } +} + +void EditView::DrawIndentGuide(Surface *surface, int lineVisible, int lineHeight, int start, PRectangle rcSegment, bool highlight) { + Point from = Point::FromInts(0, ((lineVisible & 1) && (lineHeight & 1)) ? 1 : 0); + PRectangle rcCopyArea = PRectangle::FromInts(start + 1, static_cast<int>(rcSegment.top), start + 2, static_cast<int>(rcSegment.bottom)); + surface->Copy(rcCopyArea, from, + highlight ? *pixmapIndentGuideHighlight : *pixmapIndentGuide); +} + +static void SimpleAlphaRectangle(Surface *surface, PRectangle rc, ColourDesired fill, int alpha) { + if (alpha != SC_ALPHA_NOALPHA) { + surface->AlphaRectangle(rc, 0, fill, alpha, fill, alpha, 0); + } +} + +static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle rcSegment, + const char *s, ColourDesired textBack, ColourDesired textFore, bool fillBackground) { + if (fillBackground) { + surface->FillRectangle(rcSegment, textBack); + } + FontAlias ctrlCharsFont = vsDraw.styles[STYLE_CONTROLCHAR].font; + int normalCharHeight = static_cast<int>(surface->Ascent(ctrlCharsFont) - + surface->InternalLeading(ctrlCharsFont)); + PRectangle rcCChar = rcSegment; + rcCChar.left = rcCChar.left + 1; + rcCChar.top = rcSegment.top + vsDraw.maxAscent - normalCharHeight; + rcCChar.bottom = rcSegment.top + vsDraw.maxAscent + 1; + PRectangle rcCentral = rcCChar; + rcCentral.top++; + rcCentral.bottom--; + surface->FillRectangle(rcCentral, textFore); + PRectangle rcChar = rcCChar; + rcChar.left++; + rcChar.right--; + surface->DrawTextClipped(rcChar, ctrlCharsFont, + rcSegment.top + vsDraw.maxAscent, s, static_cast<int>(s ? strlen(s) : 0), + textBack, textFore); +} + +void EditView::DrawEOL(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + PRectangle rcLine, int line, int lineEnd, int xStart, int subLine, XYACCUMULATOR subLineStart, + ColourOptional background) { + + const int posLineStart = model.pdoc->LineStart(line); + PRectangle rcSegment = rcLine; + + const bool lastSubLine = subLine == (ll->lines - 1); + XYPOSITION virtualSpace = 0; + if (lastSubLine) { + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + virtualSpace = model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)) * spaceWidth; + } + XYPOSITION xEol = static_cast<XYPOSITION>(ll->positions[lineEnd] - subLineStart); + + // Fill the virtual space and show selections within it + if (virtualSpace) { + rcSegment.left = xEol + xStart; + rcSegment.right = xEol + xStart + virtualSpace; + surface->FillRectangle(rcSegment, background.isSet ? background : vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) { + SelectionSegment virtualSpaceRange(SelectionPosition(model.pdoc->LineEnd(line)), SelectionPosition(model.pdoc->LineEnd(line), model.sel.VirtualSpaceFor(model.pdoc->LineEnd(line)))); + for (size_t r = 0; r<model.sel.Count(); r++) { + int alpha = (r == model.sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + if (alpha == SC_ALPHA_NOALPHA) { + SelectionSegment portion = model.sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart)+portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - + static_cast<XYPOSITION>(subLineStart)+portion.end.VirtualSpace() * spaceWidth; + rcSegment.left = (rcSegment.left > rcLine.left) ? rcSegment.left : rcLine.left; + rcSegment.right = (rcSegment.right < rcLine.right) ? rcSegment.right : rcLine.right; + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == model.sel.Main(), model.primarySelection)); + } + } + } + } + } + + int eolInSelection = 0; + int alpha = SC_ALPHA_NOALPHA; + if (!hideSelection) { + int posAfterLineEnd = model.pdoc->LineStart(line + 1); + eolInSelection = (subLine == (ll->lines - 1)) ? model.sel.InSelectionForEOL(posAfterLineEnd) : 0; + alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + } + + // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on + XYPOSITION blobsWidth = 0; + if (lastSubLine) { + for (int eolPos = ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) { + rcSegment.left = xStart + ll->positions[eolPos] - static_cast<XYPOSITION>(subLineStart)+virtualSpace; + rcSegment.right = xStart + ll->positions[eolPos + 1] - static_cast<XYPOSITION>(subLineStart)+virtualSpace; + blobsWidth += rcSegment.Width(); + char hexits[4]; + const char *ctrlChar; + unsigned char chEOL = ll->chars[eolPos]; + int styleMain = ll->styles[eolPos]; + ColourDesired textBack = TextBackground(model, vsDraw, ll, background, eolInSelection, false, styleMain, eolPos); + if (UTF8IsAscii(chEOL)) { + ctrlChar = ControlCharacterString(chEOL); + } else { + const Representation *repr = model.reprs.RepresentationFromCharacter(ll->chars + eolPos, ll->numCharsInLine - eolPos); + if (repr) { + ctrlChar = repr->stringRep.c_str(); + eolPos = ll->numCharsInLine; + } else { + sprintf(hexits, "x%2X", chEOL); + ctrlChar = hexits; + } + } + ColourDesired textFore = vsDraw.styles[styleMain].fore; + if (eolInSelection && vsDraw.selColours.fore.isSet) { + textFore = (eolInSelection == 1) ? vsDraw.selColours.fore : vsDraw.selAdditionalForeground; + } + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1)) { + if (alpha == SC_ALPHA_NOALPHA) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + surface->FillRectangle(rcSegment, textBack); + } + } else { + surface->FillRectangle(rcSegment, textBack); + } + DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, phasesDraw == phasesOne); + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + } + + // Draw the eol-is-selected rectangle + rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; + rcSegment.right = rcSegment.left + vsDraw.aveCharWidth; + + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + if (background.isSet) { + surface->FillRectangle(rcSegment, background); + } else if (line < model.pdoc->LinesTotal() - 1) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); + } + if (eolInSelection && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + + // Fill the remainder of the line + rcSegment.left = rcSegment.right; + if (rcSegment.left < rcLine.left) + rcSegment.left = rcLine.left; + rcSegment.right = rcLine.right; + + if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection)); + } else { + if (background.isSet) { + surface->FillRectangle(rcSegment, background); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine]].eolFilled) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine]].back); + } else { + surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back); + } + if (eolInSelection && vsDraw.selEOLFilled && vsDraw.selColours.back.isSet && (line < model.pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1, model.primarySelection), alpha); + } + } + + bool drawWrapMarkEnd = false; + + if (vsDraw.wrapVisualFlags & SC_WRAPVISUALFLAG_END) { + if (subLine + 1 < ll->lines) { + drawWrapMarkEnd = ll->LineStart(subLine + 1) != 0; + } + } + + if (drawWrapMarkEnd) { + PRectangle rcPlace = rcSegment; + + if (vsDraw.wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { + rcPlace.left = xEol + xStart + virtualSpace; + rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; + } else { + // rcLine is clipped to text area + rcPlace.right = rcLine.right; + rcPlace.left = rcPlace.right - vsDraw.aveCharWidth; + } + DrawWrapMarker(surface, rcPlace, true, vsDraw.WrapColour()); + } +} + +static void DrawIndicator(int indicNum, int startPos, int endPos, Surface *surface, const ViewStyle &vsDraw, + const LineLayout *ll, int xStart, PRectangle rcLine, int subLine) { + const XYPOSITION subLineStart = ll->positions[ll->LineStart(subLine)]; + PRectangle rcIndic( + ll->positions[startPos] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent, + ll->positions[endPos] + xStart - subLineStart, + rcLine.top + vsDraw.maxAscent + 3); + vsDraw.indicators[indicNum].Draw(surface, rcIndic, rcLine); +} + +static void DrawIndicators(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int xStart, PRectangle rcLine, int subLine, int lineEnd, bool under) { + // Draw decorators + const int posLineStart = model.pdoc->LineStart(line); + const int lineStart = ll->LineStart(subLine); + const int posLineEnd = posLineStart + lineEnd; + + for (Decoration *deco = model.pdoc->decorations.root; deco; deco = deco->next) { + if (under == vsDraw.indicators[deco->indicator].under) { + int startPos = posLineStart + lineStart; + if (!deco->rs.ValueAt(startPos)) { + startPos = deco->rs.EndRun(startPos); + } + while ((startPos < posLineEnd) && (deco->rs.ValueAt(startPos))) { + int endPos = deco->rs.EndRun(startPos); + if (endPos > posLineEnd) + endPos = posLineEnd; + DrawIndicator(deco->indicator, startPos - posLineStart, endPos - posLineStart, + surface, vsDraw, ll, xStart, rcLine, subLine); + startPos = endPos; + if (!deco->rs.ValueAt(startPos)) { + startPos = deco->rs.EndRun(startPos); + } + } + } + } + + // Use indicators to highlight matching braces + if ((vsDraw.braceHighlightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACELIGHT)) || + (vsDraw.braceBadLightIndicatorSet && (model.bracesMatchStyle == STYLE_BRACEBAD))) { + int braceIndicator = (model.bracesMatchStyle == STYLE_BRACELIGHT) ? vsDraw.braceHighlightIndicator : vsDraw.braceBadLightIndicator; + if (under == vsDraw.indicators[braceIndicator].under) { + Range rangeLine(posLineStart + lineStart, posLineEnd); + if (rangeLine.ContainsCharacter(model.braces[0])) { + int braceOffset = model.braces[0] - posLineStart; + if (braceOffset < ll->numCharsInLine) { + DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, subLine); + } + } + if (rangeLine.ContainsCharacter(model.braces[1])) { + int braceOffset = model.braces[1] - posLineStart; + if (braceOffset < ll->numCharsInLine) { + DrawIndicator(braceIndicator, braceOffset, braceOffset + 1, surface, vsDraw, ll, xStart, rcLine, subLine); + } + } + } + } +} + +void EditView::DrawAnnotation(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int line, int xStart, PRectangle rcLine, int subLine, DrawPhase phase) { + int indent = static_cast<int>(model.pdoc->GetLineIndentation(line) * vsDraw.spaceWidth); + PRectangle rcSegment = rcLine; + int annotationLine = subLine - ll->lines; + const StyledText stAnnotation = model.pdoc->AnnotationStyledText(line); + if (stAnnotation.text && ValidStyledText(vsDraw, vsDraw.annotationStyleOffset, stAnnotation)) { + if (phase & drawBack) { + surface->FillRectangle(rcSegment, vsDraw.styles[0].back); + } + rcSegment.left = static_cast<XYPOSITION>(xStart); + if (model.trackLineWidth || (vsDraw.annotationVisible == ANNOTATION_BOXED)) { + // Only care about calculating width if tracking or need to draw box + int widthAnnotation = WidestLineWidth(surface, vsDraw, vsDraw.annotationStyleOffset, stAnnotation); + if (vsDraw.annotationVisible == ANNOTATION_BOXED) { + widthAnnotation += static_cast<int>(vsDraw.spaceWidth * 2); // Margins + } + if (widthAnnotation > lineWidthMaxSeen) + lineWidthMaxSeen = widthAnnotation; + if (vsDraw.annotationVisible == ANNOTATION_BOXED) { + rcSegment.left = static_cast<XYPOSITION>(xStart + indent); + rcSegment.right = rcSegment.left + widthAnnotation; + } + } + const int annotationLines = model.pdoc->AnnotationLines(line); + size_t start = 0; + size_t lengthAnnotation = stAnnotation.LineLength(start); + int lineInAnnotation = 0; + while ((lineInAnnotation < annotationLine) && (start < stAnnotation.length)) { + start += lengthAnnotation + 1; + lengthAnnotation = stAnnotation.LineLength(start); + lineInAnnotation++; + } + PRectangle rcText = rcSegment; + if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) { + surface->FillRectangle(rcText, + vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back); + rcText.left += vsDraw.spaceWidth; + } + DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, + stAnnotation, start, lengthAnnotation, phase); + if ((phase & drawBack) && (vsDraw.annotationVisible == ANNOTATION_BOXED)) { + surface->PenColour(vsDraw.styles[vsDraw.annotationStyleOffset].fore); + surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.top)); + surface->LineTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.bottom)); + surface->MoveTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.top)); + surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.bottom)); + if (subLine == ll->lines) { + surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.top)); + surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.top)); + } + if (subLine == ll->lines + annotationLines - 1) { + surface->MoveTo(static_cast<int>(rcSegment.left), static_cast<int>(rcSegment.bottom - 1)); + surface->LineTo(static_cast<int>(rcSegment.right), static_cast<int>(rcSegment.bottom - 1)); + } + } + } +} + +static void DrawBlockCaret(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret, ColourDesired caretColour) { + + int lineStart = ll->LineStart(subLine); + int posBefore = posCaret; + int posAfter = model.pdoc->MovePositionOutsideChar(posCaret + 1, 1); + int numCharsToDraw = posAfter - posCaret; + + // Work out where the starting and ending offsets are. We need to + // see if the previous character shares horizontal space, such as a + // glyph / combining character. If so we'll need to draw that too. + int offsetFirstChar = offset; + int offsetLastChar = offset + (posAfter - posCaret); + while ((posBefore > 0) && ((offsetLastChar - numCharsToDraw) >= lineStart)) { + if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - numCharsToDraw]) > 0) { + // The char does not share horizontal space + break; + } + // Char shares horizontal space, update the numChars to draw + // Update posBefore to point to the prev char + posBefore = model.pdoc->MovePositionOutsideChar(posBefore - 1, -1); + numCharsToDraw = posAfter - posBefore; + offsetFirstChar = offset - (posCaret - posBefore); + } + + // See if the next character shares horizontal space, if so we'll + // need to draw that too. + if (offsetFirstChar < 0) + offsetFirstChar = 0; + numCharsToDraw = offsetLastChar - offsetFirstChar; + while ((offsetLastChar < ll->LineStart(subLine + 1)) && (offsetLastChar <= ll->numCharsInLine)) { + // Update posAfter to point to the 2nd next char, this is where + // the next character ends, and 2nd next begins. We'll need + // to compare these two + posBefore = posAfter; + posAfter = model.pdoc->MovePositionOutsideChar(posAfter + 1, 1); + offsetLastChar = offset + (posAfter - posCaret); + if ((ll->positions[offsetLastChar] - ll->positions[offsetLastChar - (posAfter - posBefore)]) > 0) { + // The char does not share horizontal space + break; + } + // Char shares horizontal space, update the numChars to draw + numCharsToDraw = offsetLastChar - offsetFirstChar; + } + + // We now know what to draw, update the caret drawing rectangle + rcCaret.left = ll->positions[offsetFirstChar] - ll->positions[lineStart] + xStart; + rcCaret.right = ll->positions[offsetFirstChar + numCharsToDraw] - ll->positions[lineStart] + xStart; + + // Adjust caret position to take into account any word wrapping symbols. + if ((ll->wrapIndent != 0) && (lineStart != 0)) { + XYPOSITION wordWrapCharWidth = ll->wrapIndent; + rcCaret.left += wordWrapCharWidth; + rcCaret.right += wordWrapCharWidth; + } + + // This character is where the caret block is, we override the colours + // (inversed) for drawing the caret here. + int styleMain = ll->styles[offsetFirstChar]; + FontAlias fontText = vsDraw.styles[styleMain].font; + surface->DrawTextClipped(rcCaret, fontText, + rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar, + numCharsToDraw, vsDraw.styles[styleMain].back, + caretColour); +} + +void EditView::DrawCarets(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, const LineLayout *ll, + int lineDoc, int xStart, PRectangle rcLine, int subLine) const { + // When drag is active it is the only caret drawn + bool drawDrag = model.posDrag.IsValid(); + if (hideSelection && !drawDrag) + return; + const int posLineStart = model.pdoc->LineStart(lineDoc); + // For each selection draw + for (size_t r = 0; (r<model.sel.Count()) || drawDrag; r++) { + const bool mainCaret = r == model.sel.Main(); + const SelectionPosition posCaret = (drawDrag ? model.posDrag : model.sel.Range(r).caret); + const int offset = posCaret.Position() - posLineStart; + const XYPOSITION spaceWidth = vsDraw.styles[ll->EndLineStyle()].spaceWidth; + const XYPOSITION virtualOffset = posCaret.VirtualSpace() * spaceWidth; + if (ll->InLine(offset, subLine) && offset <= ll->nu@@ Diff output truncated at 100000 characters. @@ -------------- This E-Mail was brought to you by github_commit_mail.py (Source:
https://github.com/geany/infrastructure
).
1
0
0
0
← Newer
1
2
3
4
5
6
7
8
9
10
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
Results per page:
10
25
50
100
200