1505 lines
44 KiB
Plaintext
1505 lines
44 KiB
Plaintext
-- ui_gtk.e
|
|
|
|
-- A huge thanks to Irv Mullins for making EuGTK, which made the Linux
|
|
-- and OSX GTK ports painless. Thanks to Irv for:
|
|
-- * focus-in-event for checking modified tabs
|
|
-- * current folder for load and save dialogs
|
|
-- * window placement taking window theme into account
|
|
-- * file dialog filters
|
|
-- * menu accelerator appearance
|
|
-- * new subs dialog
|
|
|
|
-- Changes:
|
|
-- fix intermittent hang on quit (found it, caused by putting the program in the
|
|
-- background using Ctrl-Z and "bg". It blocks on doing something to console
|
|
-- before exiting, so need to do "fg" to unfreeze and exit normally.)
|
|
|
|
-- font seems to be ok on OSX now,
|
|
-- needed to strip spaces and "bold", "italic", from the font name.
|
|
|
|
-- Todo:
|
|
-- fix modifier keys not working on OS X (might be ok now using gtk accelerators)
|
|
-- menu accelerator labels show up as "-/-" on OS X
|
|
-- investigate if widgets need to be Destroy'd
|
|
|
|
|
|
public include std/machine.e
|
|
public include std/error.e
|
|
include std/get.e
|
|
include std/regex.e
|
|
include std/sort.e
|
|
include scintilla.e
|
|
include EuGTK/GtkEngine.e
|
|
include EuGTK/GtkEvents.e
|
|
include wee.exw as wee
|
|
include weeicon.e
|
|
|
|
-- nifty shortcut, thanks Greg Haberek
|
|
function callback(sequence name, atom rid = routine_id(name))
|
|
if rid = -1 then
|
|
crash("routine '"&name&"' is not visible")
|
|
end if
|
|
return call_back(rid)
|
|
end function
|
|
|
|
-- check to see if 64-bit callback arguments are broken
|
|
ifdef BITS64 then
|
|
function check_callback_func(atom x)
|
|
if x = 0 then
|
|
crash("You need a newer 64-bit Euphoria with callback bug fix: 4.1.0 Beta 2 or later")
|
|
end if
|
|
return 0
|
|
end function
|
|
|
|
c_proc(define_c_proc("", callback("check_callback_func"), {C_LONG}),
|
|
{#100000000})
|
|
end ifdef
|
|
|
|
|
|
|
|
wee_init() -- initialize global variables
|
|
|
|
x_pos = 100 y_pos = 50
|
|
x_size = 500 y_size = 600
|
|
|
|
constant wee_conf_file = getenv("HOME") & "/.wee_conf"
|
|
load_wee_conf(wee_conf_file)
|
|
|
|
-- bind the icon so it won't have to be found at runtime;
|
|
constant wee_icon = gtk_func("gdk_pixbuf_new_from_xpm_data", {P},
|
|
{allocate_string_pointer_array(wee_xpm)})
|
|
|
|
--------------------------------------------------
|
|
-- Find dialog
|
|
|
|
constant
|
|
GTK_RESPONSE_FIND = 1,
|
|
GTK_RESPONSE_REPLACE = 2,
|
|
GTK_RESPONSE_REPLACE_ALL = 3
|
|
|
|
integer find_backward = 0
|
|
|
|
procedure find_dialog(integer replace_flag)
|
|
atom dialog, content, row, vbox, hbox, lbl, hedit,
|
|
find_entry, rep_entry, chk_word, chk_case, chk_backward
|
|
integer flags, result, pos
|
|
sequence text
|
|
|
|
text = get_selection()
|
|
if length(text) then
|
|
find_phrase = text
|
|
end if
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"transient for", win},
|
|
{"title", "Find"},
|
|
{"modal", TRUE},
|
|
{"add button", "gtk-close", GTK_RESPONSE_DELETE_EVENT}})
|
|
if replace_flag then
|
|
set(dialog, "add button", "Replace All", GTK_RESPONSE_REPLACE_ALL)
|
|
set(dialog, "add button", "Replace", GTK_RESPONSE_REPLACE)
|
|
end if
|
|
set(dialog, "add button", "Find Next", GTK_RESPONSE_FIND)
|
|
set(dialog, "default response", GTK_RESPONSE_FIND)
|
|
|
|
content = gtk:get(dialog, "content area")
|
|
|
|
vbox = create(GtkBox, VERTICAL, 5)
|
|
set(vbox, "margin bottom", 5)
|
|
add(content, vbox)
|
|
|
|
hbox = create(GtkBox, HORIZONTAL, 5)
|
|
pack(vbox, hbox)
|
|
pack(hbox, create(GtkLabel, "Find What:"))
|
|
find_entry = create(GtkEntry, {
|
|
{"activates default", TRUE},
|
|
{"text", find_phrase}})
|
|
pack(hbox, find_entry, TRUE, TRUE)
|
|
|
|
hedit = tab_hedit()
|
|
|
|
if replace_flag then
|
|
set(dialog, "default response", GTK_RESPONSE_REPLACE)
|
|
hbox = create(GtkBox, HORIZONTAL, 5)
|
|
pack(vbox, hbox)
|
|
pack(hbox, create(GtkLabel, "Replace With:"))
|
|
rep_entry = create(GtkEntry, {
|
|
{"activates default", TRUE},
|
|
{"text", replace_phrase}})
|
|
pack(hbox, rep_entry, TRUE, TRUE)
|
|
|
|
-- clear the target so that first replace won't reuse old one
|
|
SSM(hedit, SCI_SETTARGETSTART, 0)
|
|
SSM(hedit, SCI_SETTARGETEND, 0)
|
|
end if
|
|
|
|
flags = SSM(hedit, SCI_GETSEARCHFLAGS)
|
|
|
|
chk_word = create(GtkCheckButton, {
|
|
{"label", "Match whole word only"},
|
|
{"active", 0 != and_bits(flags, SCFIND_WHOLEWORD)}})
|
|
pack(vbox, chk_word)
|
|
|
|
chk_case = create(GtkCheckButton, {
|
|
{"label", "Match case"},
|
|
{"active", 0 != and_bits(flags, SCFIND_MATCHCASE)}})
|
|
pack(vbox, chk_case)
|
|
|
|
chk_backward = create(GtkCheckButton, {
|
|
{"label", "Search backward"},
|
|
{"active", find_backward}})
|
|
pack(vbox, chk_backward)
|
|
|
|
show_all(dialog)
|
|
|
|
result = set(dialog, "run")
|
|
while result != GTK_RESPONSE_DELETE_EVENT do
|
|
flags = 0
|
|
if gtk:get(chk_word, "active") then
|
|
flags += SCFIND_WHOLEWORD
|
|
end if
|
|
if gtk:get(chk_case, "active") then
|
|
flags += SCFIND_MATCHCASE
|
|
end if
|
|
find_backward = gtk:get(chk_backward, "active")
|
|
|
|
SSM(hedit, SCI_SETSEARCHFLAGS, flags)
|
|
find_phrase = gtk:get(find_entry, "text")
|
|
|
|
if result = GTK_RESPONSE_FIND then
|
|
if search_find(find_phrase, find_backward) = 0 then
|
|
Info(dialog, "Find", "Unable to find a match.")
|
|
end if
|
|
else
|
|
replace_phrase = gtk:get(rep_entry, "text")
|
|
if result = GTK_RESPONSE_REPLACE_ALL then
|
|
result = search_replace_all(find_phrase, replace_phrase)
|
|
if result then
|
|
Info(dialog, "Replace All", sprintf("%d replacements.", {result}))
|
|
else
|
|
Info(dialog, "Replace All", "Unable to find a match.")
|
|
end if
|
|
else
|
|
result = search_replace(replace_phrase)
|
|
if search_find(find_phrase, find_backward) = 0 and result = 0 then
|
|
Info(dialog, "Replace", "Unable to find a match.")
|
|
end if
|
|
end if
|
|
end if
|
|
result = set(dialog, "run")
|
|
end while
|
|
hide(dialog)
|
|
return
|
|
end procedure
|
|
|
|
|
|
--------------------------------------------------
|
|
-- functions called from menu items
|
|
|
|
function FileNew() new_file() return 0 end function
|
|
function FileOpen() open_file("", 0) return 0 end function
|
|
function FileSave() save_if_modified(0) return 0 end function
|
|
function FileSaveAs() save_file_as() return 0 end function
|
|
function FileClose() close_tab() return 0 end function
|
|
function FileQuit()
|
|
if save_modified_tabs() then
|
|
save_wee_conf(wee_conf_file)
|
|
Quit()
|
|
end if
|
|
return 0
|
|
end function
|
|
function EditUndo() SSM(tab_hedit(), SCI_UNDO) return 0 end function
|
|
function EditRedo() SSM(tab_hedit(), SCI_REDO) return 0 end function
|
|
function EditCut() SSM(tab_hedit(), SCI_CUT) return 0 end function
|
|
function EditCopy() SSM(tab_hedit(), SCI_COPY) return 0 end function
|
|
function EditPaste() SSM(tab_hedit(), SCI_PASTE) return 0 end function
|
|
function EditClear() SSM(tab_hedit(), SCI_CLEAR) return 0 end function
|
|
function EditSelectAll() SSM(tab_hedit(), SCI_SELECTALL) return 0 end function
|
|
function EditToggleComment() toggle_comment() return 0 end function
|
|
function SearchFind() find_dialog(0) return 0 end function
|
|
function SearchFindNext()
|
|
if length(find_phrase) = 0 then
|
|
return SearchFind()
|
|
end if
|
|
search_find(find_phrase, 0)
|
|
return 0
|
|
end function
|
|
function SearchFindPrevious() search_find(find_phrase, 1) return 0 end function
|
|
function SearchReplace() find_dialog(1) return 0 end function
|
|
function ViewDecl() view_declaration() return 0 end function
|
|
function ViewArgs() view_subroutine_arguments() return 0 end function
|
|
function ViewComp() view_completions() return 0 end function
|
|
function ViewError() ui_view_error() return 0 end function
|
|
function GoBack() go_back() return 0 end function
|
|
|
|
function OldViewSubs()
|
|
sequence text, word, subs, tmp
|
|
integer pos, result
|
|
atom dialog, scroll, list, content, row, lbl
|
|
|
|
text = get_edit_text()
|
|
pos = get_pos()
|
|
word = word_pos(text, pos)
|
|
tmp = get_subroutines(parse(text, file_name))
|
|
word = word[1]
|
|
|
|
subs = repeat(0, floor(length(tmp)/2))
|
|
for i = 1 to length(subs) do
|
|
subs[i] = {tmp[i*2-1], tmp[i*2]}
|
|
end for
|
|
if sorted_subs then
|
|
subs = sort(subs)
|
|
end if
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"default size", 200, 400},
|
|
{"add button", "gtk-close", GTK_RESPONSE_CLOSE},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"transient for", win},
|
|
{"title", "Subroutines"},
|
|
{"default response", GTK_RESPONSE_OK},
|
|
{"modal", TRUE}})
|
|
|
|
content = gtk:get(dialog, "content area")
|
|
scroll = create(GtkScrolledWindow)
|
|
pack(content, scroll, TRUE, TRUE)
|
|
|
|
list = create(GtkListBox)
|
|
add(scroll, list)
|
|
for i = 1 to length(subs) do
|
|
lbl = create(GtkLabel, subs[i][1])
|
|
set(lbl, "halign", GTK_ALIGN_START)
|
|
set(list, "insert", lbl, -1)
|
|
if equal(subs[i][1], word) then
|
|
row = gtk:get(list, "row at index", i-1)
|
|
set(list, "select row", row)
|
|
end if
|
|
end for
|
|
|
|
show_all(dialog)
|
|
if set(dialog, "run") = GTK_RESPONSE_OK then
|
|
row = gtk:get(list, "selected row")
|
|
--result = gtk:get(row, "index") -- doesn't work?
|
|
for i = 1 to length(subs) do
|
|
if row = gtk:get(list, "row at index", i-1) then
|
|
word = subs[i][1]
|
|
pos = subs[i][2]
|
|
goto_pos(pos, length(word))
|
|
exit
|
|
end if
|
|
end for
|
|
end if
|
|
hide(dialog)
|
|
return 0
|
|
end function
|
|
|
|
function RowActivated(atom ctl, atom path, atom col, atom dialog)
|
|
--? {ctl, path, col, dialog}
|
|
set(dialog, "response", GTK_RESPONSE_OK)
|
|
return 0
|
|
end function
|
|
constant row_activated = callback("RowActivated")
|
|
|
|
-- contributed by Irv
|
|
function ViewSubs()
|
|
sequence text, word, subs
|
|
integer pos, result
|
|
atom dialog, scroll, list, content, row, lbl
|
|
|
|
text = get_edit_text()
|
|
pos = get_pos()
|
|
word = word_pos(text, pos)
|
|
subs = get_subroutines(parse(text, file_name))
|
|
word = word[1]
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"default size", 200, 400},
|
|
{"add button", "gtk-close", GTK_RESPONSE_CLOSE},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"transient for", win},
|
|
{"title", "Subroutines"},
|
|
{"default response", GTK_RESPONSE_OK},
|
|
{"modal", TRUE}})
|
|
|
|
content = gtk:get(dialog, "content area")
|
|
scroll = create(GtkScrolledWindow)
|
|
pack(content, scroll, TRUE, TRUE)
|
|
|
|
object routines = subs, data
|
|
if sorted_subs then
|
|
routines = sort(routines)
|
|
end if
|
|
|
|
list = create(GtkTreeView)
|
|
add(scroll, list)
|
|
object store = create(GtkListStore, {gSTR, gINT})
|
|
set(list, "model", store)
|
|
object col1 = create(GtkTreeViewColumn)
|
|
object rend1 = create(GtkCellRendererText)
|
|
add(col1, rend1)
|
|
set(col1, "add attribute", rend1, "text", 1)
|
|
set(col1, "sort indicator", TRUE)
|
|
set(col1, "max width", 100)
|
|
set(col1, "title", "Routine Name")
|
|
set(list, "append columns", col1)
|
|
|
|
object col2 = create(GtkTreeViewColumn)
|
|
object rend2 = create(GtkCellRendererText)
|
|
add(col2, rend2)
|
|
set(col2, "add attribute", rend2, "text", 2)
|
|
set(list, "append columns", col2)
|
|
set(store, "data", routines)
|
|
|
|
object selection = gtk:get(list,"selection")
|
|
set(selection, "mode", GTK_SELECTION_SINGLE)
|
|
set(col2, "visible", FALSE)
|
|
|
|
set(col1, "sort column id", 1)
|
|
connect(list, "row-activated", row_activated, dialog)
|
|
|
|
show_all(dialog)
|
|
if gtk:get(dialog, "run") = GTK_RESPONSE_OK then
|
|
row = gtk:get(selection, "selected row")
|
|
data = gtk:get(store, "row data", row)
|
|
word = data[1]
|
|
pos = data[2]
|
|
goto_pos(pos, length(word))
|
|
end if
|
|
hide(dialog)
|
|
|
|
return 0
|
|
end function
|
|
|
|
function OptionsFont()
|
|
atom dialog
|
|
sequence font, tmp
|
|
|
|
dialog = create(GtkFontChooserDialog, "Font...", win)
|
|
set(dialog, "font", sprintf("%s %d", {font_name, font_height}))
|
|
if set(dialog, "run") = MB_OK then
|
|
font = gtk:get(dialog, "font")
|
|
for i = length(font) to 1 by -1 do
|
|
if font[i] = ' ' then
|
|
tmp = value(font[i+1..$])
|
|
if tmp[1] = 0 then
|
|
font_height = tmp[2]
|
|
font_name = font[1..i-1]
|
|
--printf(1, "%s %d\n", {font_name, font_height})
|
|
reinit_all_edits()
|
|
end if
|
|
exit
|
|
end if
|
|
end for
|
|
end if
|
|
set(dialog, "hide")
|
|
|
|
return 0
|
|
end function
|
|
|
|
function RunColorDialog(integer color)
|
|
object ccd = create(GtkColorChooserDialog, {
|
|
{"title", "Select a color"},
|
|
{"transient for", win},
|
|
{"use alpha", FALSE},
|
|
{"rgba", sprintf("#%02x%02x%02x",
|
|
and_bits(floor(color/{1,#100,#10000}),#FF))}})
|
|
if gtk:get(ccd, "run") = MB_OK then
|
|
color = gtk:get(ccd, "rgba", 2)
|
|
color = floor(and_bits(color, #FF0000) / #10000) +
|
|
and_bits(color, #FF00) + and_bits(color, #FF) * #10000
|
|
end if
|
|
set(ccd, "hide")
|
|
return color
|
|
end function
|
|
|
|
function ColorButton(atom ctl, atom w)
|
|
if w = 1 then
|
|
normal_color = RunColorDialog(normal_color)
|
|
elsif w = 2 then
|
|
background_color = RunColorDialog(background_color)
|
|
elsif w = 3 then
|
|
comment_color = RunColorDialog(comment_color)
|
|
elsif w = 4 then
|
|
string_color = RunColorDialog(string_color)
|
|
elsif w = 5 then
|
|
keyword_color = RunColorDialog(keyword_color)
|
|
elsif w = 6 then
|
|
builtin_color = RunColorDialog(builtin_color)
|
|
elsif w = 7 then
|
|
number_color = RunColorDialog(number_color)
|
|
elsif w = 8 then
|
|
bracelight_color = RunColorDialog(bracelight_color)
|
|
elsif w = 9 then
|
|
linenumber_color = RunColorDialog(linenumber_color)
|
|
end if
|
|
reinit_all_edits()
|
|
return 0
|
|
end function
|
|
|
|
function BoldToggle(atom ctl, atom flag)
|
|
if gtk:get(ctl, "active") then
|
|
bold_flags = or_bits(bold_flags, flag)
|
|
else
|
|
bold_flags = and_bits(bold_flags, not_bits(flag))
|
|
end if
|
|
reinit_all_edits()
|
|
return 0
|
|
end function
|
|
|
|
constant color_button = callback("ColorButton")
|
|
constant bold_toggle = callback("BoldToggle")
|
|
|
|
function OptionsColors()
|
|
atom dialog, grid
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"default size", 200, 300},
|
|
{"add button", "gtk-close", GTK_RESPONSE_CLOSE},
|
|
{"transient for", win},
|
|
{"title", "Colors"},
|
|
{"default response", GTK_RESPONSE_OK},
|
|
{"modal", TRUE}})
|
|
|
|
grid = create(GtkGrid, VERTICAL)
|
|
set(grid, "margin bottom", 5)
|
|
add(gtk:get(dialog, "content area"), grid)
|
|
|
|
set(grid, {
|
|
{"row spacing", 2},
|
|
{"column spacing", 2},
|
|
{"attach", create(GtkButton, "Normal", color_button, 1), 1, 2, 1, 1},
|
|
{"attach", create(GtkButton, "Background", color_button, 2), 1, 3, 1, 1},
|
|
{"attach", create(GtkButton, "Comment", color_button, 3), 1, 4, 1, 1},
|
|
{"attach", create(GtkButton, "String", color_button, 4), 1, 5, 1, 1},
|
|
{"attach", create(GtkButton, "Keyword", color_button, 5), 1, 6, 1, 1},
|
|
{"attach", create(GtkButton, "Built-in", color_button, 6), 1, 7, 1, 1},
|
|
{"attach", create(GtkButton, "Number", color_button, 7), 1, 8, 1, 1},
|
|
{"attach", create(GtkButton, "Brace Highlight", color_button, 8), 1, 9, 1, 1},
|
|
{"attach", create(GtkButton, "Line Number", color_button, 9), 1, 10, 1, 1},
|
|
{"attach", create(GtkCheckButton, {
|
|
{"label", "Bold"}, {"active", 0 != and_bits(bold_flags, 1)}},
|
|
bold_toggle, 1), 2, 2, 1, 1},
|
|
{"attach", create(GtkCheckButton, {
|
|
{"label", "Bold"}, {"active", 0 != and_bits(bold_flags, 2)}},
|
|
bold_toggle, 2), 2, 4, 1, 1},
|
|
{"attach", create(GtkCheckButton, {
|
|
{"label", "Bold"}, {"active", 0 != and_bits(bold_flags, 4)}},
|
|
bold_toggle, 4), 2, 5, 1, 1},
|
|
{"attach", create(GtkCheckButton, {
|
|
{"label", "Bold"}, {"active", 0 != and_bits(bold_flags, 8)}},
|
|
bold_toggle, 8), 2, 6, 1, 1},
|
|
{"attach", create(GtkCheckButton, {
|
|
{"label", "Bold"}, {"active", 0 != and_bits(bold_flags, #10)}},
|
|
bold_toggle, #10), 2, 7, 1, 1},
|
|
{"attach", create(GtkCheckButton, {
|
|
{"label", "Bold"}, {"active", 0 != and_bits(bold_flags, #20)}},
|
|
bold_toggle, #20), 2, 8, 1, 1},
|
|
{"attach", create(GtkCheckButton, {
|
|
{"label", "Bold"}, {"active", 0 != and_bits(bold_flags, #40)}},
|
|
bold_toggle, #40), 2, 9, 1, 1}
|
|
})
|
|
|
|
show_all(dialog)
|
|
set(dialog, "run")
|
|
set(dialog, "hide")
|
|
return 0
|
|
end function
|
|
|
|
function OptionsLineNumbers(atom handle)
|
|
line_numbers = gtk:get(handle, "active")
|
|
reinit_all_edits()
|
|
return 0
|
|
end function
|
|
|
|
function OptionsSortedSubs(atom handle)
|
|
sorted_subs = gtk:get(handle, "active")
|
|
return 0
|
|
end function
|
|
|
|
function OptionsLineWrap(atom handle)
|
|
line_wrap = gtk:get(handle, "active")
|
|
reinit_all_edits()
|
|
return 0
|
|
end function
|
|
|
|
function OptionsReopenTabs(atom handle)
|
|
reopen_tabs = gtk:get(handle, "active")
|
|
return 0
|
|
end function
|
|
|
|
function OptionsCompleteStatements(atom handle)
|
|
complete_statements = gtk:get(handle, "active")
|
|
return 0
|
|
end function
|
|
|
|
function OptionsCompleteBraces(atom handle)
|
|
complete_braces = gtk:get(handle, "active")
|
|
return 0
|
|
end function
|
|
|
|
function OptionsErrorIndicators(atom handle)
|
|
auto_indicator = gtk:get(handle, "active")
|
|
return 0
|
|
end function
|
|
|
|
function OptionsIndent(atom handle)
|
|
atom dialog, panel, hbox, hedit, indent_entry, tabs_entry, chk_guides, chk_usetabs
|
|
integer indent_width, tab_width, use_tabs
|
|
sequence val
|
|
|
|
hedit = tab_hedit()
|
|
tab_width = SSM(hedit, SCI_GETTABWIDTH)
|
|
indent_width = SSM(hedit, SCI_GETINDENT)
|
|
use_tabs = SSM(hedit, SCI_GETUSETABS)
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"add button", "gtk-close", GTK_RESPONSE_DELETE_EVENT},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"transient for", win},
|
|
{"title", "Indent"},
|
|
{"default response", GTK_RESPONSE_OK},
|
|
{"modal", TRUE}})
|
|
|
|
panel = create(GtkBox, VERTICAL, 5)
|
|
set(panel, "margin bottom", 5)
|
|
add(gtk:get(dialog, "content area"), panel)
|
|
|
|
hbox = create(GtkBox, HORIZONTAL, 5)
|
|
add(panel, hbox)
|
|
add(hbox, create(GtkLabel, "Indent Size"))
|
|
|
|
indent_entry = create(GtkEntry, {
|
|
{"text", sprintf("%d", {indent_width})}})
|
|
add(hbox, indent_entry)
|
|
|
|
chk_guides = create(GtkCheckButton, {
|
|
{"label", "Show indentation guides"},
|
|
{"active", indentation_guides}})
|
|
pack(panel, chk_guides)
|
|
|
|
chk_usetabs = create(GtkCheckButton, {
|
|
{"label", "Use tabs in indentation"},
|
|
{"active", use_tabs}})
|
|
pack(panel, chk_usetabs)
|
|
|
|
hbox = create(GtkBox, HORIZONTAL, 5)
|
|
add(panel, hbox)
|
|
add(hbox, create(GtkLabel, "Tab Size"))
|
|
|
|
tabs_entry = create(GtkEntry, {
|
|
{"text", sprintf("%d", {tab_width})}})
|
|
add(hbox, tabs_entry)
|
|
|
|
show_all(dialog)
|
|
while set(dialog, "run") = GTK_RESPONSE_OK do
|
|
|
|
val = value(gtk:get(indent_entry, "text"))
|
|
if val[1] = 0 and integer(val[2]) and val[2] >= 1 and val[2] <= 8 then
|
|
indent_width = val[2]
|
|
else
|
|
set(indent_entry, "grab focus")
|
|
continue
|
|
end if
|
|
|
|
val = value(gtk:get(tabs_entry, "text"))
|
|
if val[1] = 0 and integer(val[2]) and val[2] >= 1 and val[2] <= 8 then
|
|
tab_width = val[2]
|
|
else
|
|
set(tabs_entry, "grab focus")
|
|
continue
|
|
end if
|
|
|
|
use_tabs = gtk:get(chk_usetabs, "active")
|
|
indentation_guides = gtk:get(chk_guides, "active")
|
|
|
|
SSM(hedit, SCI_SETTABWIDTH, tab_width)
|
|
SSM(hedit, SCI_SETINDENT, indent_width)
|
|
SSM(hedit, SCI_SETUSETABS, use_tabs)
|
|
reinit_all_edits()
|
|
exit
|
|
|
|
end while
|
|
hide(dialog)
|
|
return 0
|
|
end function
|
|
|
|
-- runs the script, maybe in a terminal emulator
|
|
procedure Run(sequence script)
|
|
sequence tmp_name = sprintf("/tmp/wee_run_%d.sh", {rand(1000000)})
|
|
sequence cmd = tmp_name
|
|
if length(terminal_program) then
|
|
if run_waitkey then
|
|
-- need bash for "read -n"
|
|
script = "#!/bin/bash\n" &
|
|
-- don't show "Press Enter" on errors
|
|
match_replace("eui ", script, "eui -batch ") &
|
|
"\nread -n1 -s -p \"Press any key...\"\n"
|
|
end if
|
|
cmd = terminal_program & ' ' & tmp_name
|
|
end if
|
|
-- write script file
|
|
if write_file(tmp_name, script) = -1 then
|
|
printf(2, "Failed to write file %s\n", {tmp_name})
|
|
return
|
|
end if
|
|
-- remove script after running it
|
|
cmd &= "; rm " & tmp_name
|
|
if run_background then
|
|
-- put the command in background
|
|
cmd = "(" & cmd & ") &"
|
|
end if
|
|
-- make script executable and run it
|
|
system("chmod +x " & tmp_name & "; " & cmd)
|
|
end procedure
|
|
|
|
function RunStart(atom ctl)
|
|
object lbl = gtk:get(ctl, "label")
|
|
sequence cmd = ""
|
|
|
|
if save_if_modified(0) = 0 or length(file_name) = 0 then
|
|
return 0 -- cancelled, or no name
|
|
end if
|
|
|
|
run_file_name = file_name
|
|
cmd = "cd " & dirname(run_file_name) & "\n"
|
|
if match("Start", lbl) = 1 then
|
|
reset_ex_err()
|
|
cmd &= get_eu_bin(interpreter) & ' ' & quote_spaces(file_name)
|
|
if not equal(lbl, "Start") then -- with arguments
|
|
if length(get_tab_arguments()) = 0 then
|
|
if RunSetArguments() then
|
|
return 0
|
|
end if
|
|
end if
|
|
cmd &= ' ' & get_tab_arguments()
|
|
end if
|
|
Run(cmd)
|
|
check_ex_err()
|
|
elsif equal(lbl, "Bind") then
|
|
cmd &= get_eu_bin("eubind") & ' ' & quote_spaces(file_name)
|
|
cmd &= "\nwhich upx && upx " & filebase(file_name)
|
|
if run_testrun then
|
|
cmd &= "\n./" & filebase(file_name)
|
|
end if
|
|
Run(cmd)
|
|
elsif equal(lbl, "Shroud") then
|
|
cmd &= get_eu_bin("eushroud") & ' ' & quote_spaces(file_name)
|
|
if run_testrun then
|
|
cmd &= "\n./" & filebase(file_name) & ".il"
|
|
end if
|
|
Run(cmd)
|
|
elsif equal(lbl, "Translate and Compile") then
|
|
cmd &= get_eu_bin("euc") & ' ' & quote_spaces(file_name)
|
|
cmd &= "\nwhich upx && upx " & filebase(file_name)
|
|
if run_testrun then
|
|
cmd &= "\n./" & filebase(file_name)
|
|
end if
|
|
Run(cmd)
|
|
elsif equal(lbl, "Run Terminal Emulator") then
|
|
Run(cmd & "$SHELL")
|
|
else
|
|
crash("Unable to get menu label")
|
|
end if
|
|
return 0
|
|
end function
|
|
|
|
function RunSetArguments()
|
|
atom dialog, content, text_entry, result = -1
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"add button", "gtk-close", GTK_RESPONSE_DELETE_EVENT},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"transient for", win},
|
|
{"title", "Arguments"},
|
|
{"default response", GTK_RESPONSE_OK},
|
|
{"modal", TRUE}})
|
|
content = gtk:get(dialog, "content area")
|
|
|
|
text_entry = create(GtkEntry, {
|
|
{"activates default", TRUE},
|
|
{"text", get_tab_arguments()},
|
|
{"margin bottom", 5}})
|
|
add(content, text_entry)
|
|
|
|
show_all(dialog)
|
|
if set(dialog, "run") = GTK_RESPONSE_OK then
|
|
set_tab_arguments(gtk:get(text_entry, "text"))
|
|
result = 0
|
|
end if
|
|
hide(dialog)
|
|
return result
|
|
end function
|
|
|
|
function ChooseInterpreter(atom ctl, atom text_entry)
|
|
atom dialog
|
|
sequence filenames
|
|
|
|
dialog = create(GtkFileChooserDialog, {
|
|
{"title", "Open..."},
|
|
{"transient for", win},
|
|
{"action", GTK_FILE_CHOOSER_ACTION_OPEN},
|
|
{"add button", "gtk-cancel", GTK_RESPONSE_CLOSE},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"position", GTK_WIN_POS_MOUSE},
|
|
{"current folder", pathname(canonical_path(interpreter))}})
|
|
|
|
if gtk:get(dialog, "run") = GTK_RESPONSE_OK then
|
|
set(text_entry, "prepend text", gtk:get(dialog, "filename"))
|
|
set(text_entry, "active", 1)
|
|
end if
|
|
set(dialog, "hide")
|
|
return 0
|
|
end function
|
|
|
|
constant choose_interpreter = callback("ChooseInterpreter")
|
|
|
|
function RunSetInterpreter()
|
|
atom dialog, text_entry, panel, row
|
|
sequence interpreters = get_interpreters()
|
|
integer index
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"add button", "gtk-close", GTK_RESPONSE_DELETE_EVENT},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"transient for", win},
|
|
{"title", "Choose Interpreter"},
|
|
{"default response", GTK_RESPONSE_OK},
|
|
{"modal", TRUE}})
|
|
|
|
panel = create(GtkBox, VERTICAL, 5)
|
|
set(panel, "margin bottom", 5)
|
|
add(gtk:get(dialog, "content area"), panel)
|
|
|
|
pack(panel, create(GtkLabel,
|
|
`Enter an interpreter to use to run programs, or select one from the list.
|
|
Leave blank to use the default first item in the list.`))
|
|
|
|
row = create(GtkBox, HORIZONTAL, 5)
|
|
pack(panel, row, TRUE)
|
|
|
|
text_entry = create(GtkComboBoxEntry, {
|
|
{"margin bottom", 5},
|
|
{"activates default", TRUE}})
|
|
pack(row, text_entry, TRUE, TRUE)
|
|
if length(interpreters) then
|
|
add(text_entry, interpreters)
|
|
index = find(interpreter, interpreters)
|
|
if index then
|
|
set(text_entry, "active", index)
|
|
end if
|
|
end if
|
|
pack(row, create(GtkButton, "...", choose_interpreter, text_entry))
|
|
|
|
show_all(dialog)
|
|
if set(dialog, "run") = GTK_RESPONSE_OK then
|
|
interpreter = gtk:get(text_entry, "active text")
|
|
end if
|
|
hide(dialog)
|
|
return 0
|
|
end function
|
|
|
|
constant terminals = {"x-terminal-emulator", "urxvt", "rxvt",
|
|
"terminator", "Eterm", "aterm", "xterm", "gnome-terminal",
|
|
"roxterm", "xfce4-terminal", "termite", "lxterminal",
|
|
"mate-terminal", "terminology"}
|
|
|
|
function RunSetTerminal()
|
|
atom dialog, text_entry, panel
|
|
sequence text
|
|
integer n = 0
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"add button", "gtk-close", GTK_RESPONSE_DELETE_EVENT},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"transient for", win},
|
|
{"title", "Choose Terminal Emulator"},
|
|
{"default response", GTK_RESPONSE_OK},
|
|
{"modal", TRUE}})
|
|
|
|
panel = create(GtkBox, VERTICAL, 5)
|
|
set(panel, "margin bottom", 5)
|
|
add(gtk:get(dialog, "content area"), panel)
|
|
|
|
pack(panel, create(GtkLabel,
|
|
`Enter a terminal emulator to use to run programs, or select one
|
|
from the list. Leave blank to run in parent terminal.`))
|
|
|
|
text_entry = create(GtkComboBoxEntry, {
|
|
{"margin bottom", 5},
|
|
{"activates default", TRUE}})
|
|
pack(panel, text_entry)
|
|
for i = 1 to length(terminals) do
|
|
if system_exec("which " & terminals[i] & " >/dev/null 2>&1") = 0 then
|
|
text = terminals[i]
|
|
if find(text, {"gnome-terminal", "xfce4-terminal"}) then
|
|
text &= " -x"
|
|
else
|
|
text &= " -e"
|
|
end if
|
|
add(text_entry, {text})
|
|
n += 1
|
|
if equal(text, terminal_program) then
|
|
set(text_entry, "active", n)
|
|
end if
|
|
end if
|
|
end for
|
|
if length(terminal_program) and gtk:get(text_entry, "active") = 0 then
|
|
set(text_entry, "prepend text", terminal_program)
|
|
set(text_entry, "active", 1)
|
|
end if
|
|
|
|
show_all(dialog)
|
|
if set(dialog, "run") = GTK_RESPONSE_OK then
|
|
terminal_program = gtk:get(text_entry, "active text")
|
|
end if
|
|
hide(dialog)
|
|
return 0
|
|
end function
|
|
|
|
function RunTestRun(atom handle)
|
|
run_testrun = gtk:get(handle, "active")
|
|
return 0
|
|
end function
|
|
|
|
function RunBackground(atom handle)
|
|
run_background = gtk:get(handle, "active")
|
|
return 0
|
|
end function
|
|
|
|
function RunWaitKey(atom handle)
|
|
run_waitkey = gtk:get(handle, "active")
|
|
return 0
|
|
end function
|
|
|
|
function HelpAbout()
|
|
set(about_dialog, "run")
|
|
set(about_dialog, "hide")
|
|
return 0
|
|
end function
|
|
|
|
function HelpReleaseNotes()
|
|
release_notes()
|
|
return 0
|
|
end function
|
|
|
|
function HelpTutorial()
|
|
open_tutorial()
|
|
return 0
|
|
end function
|
|
|
|
function HelpHelp()
|
|
context_help()
|
|
return 0
|
|
end function
|
|
|
|
--------------------------------------
|
|
-- functions called from window events
|
|
|
|
-- this gets called when window is moved or resized
|
|
function configure_event(atom w, atom s)
|
|
atom left_margin, top_margin -- not used, just for show
|
|
{left_margin, top_margin, x_size, y_size} =
|
|
gtk:get(gtk:get(w, "window"), "geometry")
|
|
{x_pos, y_pos} = gtk:get(w, "position")
|
|
return 0
|
|
end function
|
|
|
|
-- called before window is closed, return TRUE to prevent close, otherwise FALSE
|
|
function delete_event()
|
|
if save_modified_tabs() then
|
|
save_wee_conf(wee_conf_file)
|
|
return FALSE
|
|
end if
|
|
return TRUE
|
|
end function
|
|
|
|
function window_set_focus(atom widget)
|
|
check_externally_modified_tabs()
|
|
check_ex_err()
|
|
return 0
|
|
end function
|
|
|
|
-------------------------------------------------------------
|
|
|
|
constant
|
|
group = create(GtkAccelGroup),
|
|
win = create(GtkWindow, {
|
|
{"border width", 0},
|
|
{"add accel group", group},
|
|
{"default size", x_size, y_size},
|
|
{"move", x_pos, y_pos}}),
|
|
panel = create(GtkBox, VERTICAL)
|
|
|
|
gtk_func("gtk_window_set_icon", {P,P}, {win, wee_icon})
|
|
connect(win, "destroy", main_quit)
|
|
connect(win, "configure-event", callback("configure_event"))
|
|
connect(win, "delete-event", callback("delete_event"))
|
|
connect(win, "focus-in-event", callback("window_set_focus"))
|
|
add(win, panel)
|
|
|
|
constant
|
|
about_dialog = create(GtkAboutDialog, {
|
|
{"transient for", win},
|
|
{"name", "about:dialog"},
|
|
{"program name", window_title},
|
|
{"comments", "A small editor for Euphoria programming."},
|
|
{"version", wee:version},
|
|
{"authors", {author, "EuGTK by Irv Mullins http://sites.google.com/site/euphoriagtk/Home/"}},
|
|
{"website", "https://github.com/peberlein/WEE/"},
|
|
{"website label", "Wee on GitHub"},
|
|
{"logo", wee_icon}
|
|
})
|
|
|
|
|
|
constant
|
|
menubar = create(GtkMenuBar),
|
|
menuFile = create(GtkMenuItem, "_File"),
|
|
menuEdit = create(GtkMenuItem, "_Edit"),
|
|
menuSearch = create(GtkMenuItem, "_Search"),
|
|
menuView = create(GtkMenuItem, "_View"),
|
|
menuRun = create(GtkMenuItem, "_Run"),
|
|
menuOptions = create(GtkMenuItem, "_Options"),
|
|
menuHelp = create(GtkMenuItem, "_Help"),
|
|
filemenu = create(GtkMenu, {{"accel group", group}}),
|
|
editmenu = create(GtkMenu, {{"accel group", group}}),
|
|
searchmenu = create(GtkMenu, {{"accel group", group}}),
|
|
viewmenu = create(GtkMenu, {{"accel group", group}}),
|
|
runmenu = create(GtkMenu, {{"accel group", group}}),
|
|
optionsmenu = create(GtkMenu, {{"accel group", group}}),
|
|
helpmenu = create(GtkMenu, {{"accel group", group}}),
|
|
chooseinterpreter_menu = create(GtkMenu),
|
|
tabmenu = create(GtkMenu)
|
|
|
|
-- create a menu item with "activate" signal connected to local routine
|
|
-- and add parsed accelerator key
|
|
function createmenuitem(sequence text, object r, object key = 0, object check = -1)
|
|
atom widget, x
|
|
if equal(check, -1) or sequence(check) then
|
|
if sequence(key) then
|
|
widget = create(GtkMenuItem, text, 0, 0, {group, key})
|
|
if sequence(check) then
|
|
-- check could be a second accelerator
|
|
set(widget, "add accelerator", {group, check})
|
|
end if
|
|
else
|
|
widget = create(GtkMenuItem, text)
|
|
end if
|
|
else
|
|
widget = create(GtkCheckMenuItem, text)
|
|
set(widget, "active", check)
|
|
end if
|
|
if sequence(r) then
|
|
x = routine_id(r)
|
|
if x <= 0 then
|
|
crash(r &" is not a visible function")
|
|
end if
|
|
r = call_back(x)
|
|
end if
|
|
connect(widget, "activate", r)
|
|
return widget
|
|
end function
|
|
|
|
add(filemenu, {
|
|
createmenuitem("_New", "FileNew", "<Control>N"),
|
|
createmenuitem("_Open...", "FileOpen", "<Control>O"),
|
|
createmenuitem("_Save", "FileSave", "<Control>S"),
|
|
createmenuitem("Save _As...", "FileSaveAs", "<Control><Shift>S"),
|
|
createmenuitem("_Close", "FileClose", "<Control>W"),
|
|
create(GtkSeparatorMenuItem),
|
|
createmenuitem("_Quit", "FileQuit", "<Control>Q")
|
|
})
|
|
set(menuFile, "submenu", filemenu)
|
|
|
|
add(editmenu, {
|
|
createmenuitem("_Undo", "EditUndo", "<Control>Z"),
|
|
createmenuitem("_Redo", "EditRedo", "<Control><Shift>Z"),
|
|
create(GtkSeparatorMenuItem),
|
|
createmenuitem("_Cut", "EditCut", "<Control>X"),
|
|
createmenuitem("C_opy", "EditCopy", "<Control>C"),
|
|
createmenuitem("_Paste", "EditPaste", "<Control>V"),
|
|
createmenuitem("Clear", "EditClear"),
|
|
createmenuitem("Select _All", "EditSelectAll", "<Control>A"),
|
|
create(GtkSeparatorMenuItem),
|
|
createmenuitem("Toggle Comment", "EditToggleComment", "<Control>M")
|
|
})
|
|
set(menuEdit, "submenu", editmenu)
|
|
|
|
add(searchmenu, {
|
|
createmenuitem("Find...", "SearchFind", "<Control>F", "<Control>F3"),
|
|
createmenuitem("Find Next", "SearchFindNext", "<Control>G", "F3"),
|
|
createmenuitem("Find Previous", "SearchFindPrevious", "<Control><Shift>G", "<Shift>F3"),
|
|
createmenuitem("Replace...", "SearchReplace", "<Control>R")
|
|
})
|
|
set(menuSearch, "submenu", searchmenu)
|
|
|
|
add(viewmenu, {
|
|
createmenuitem("Subroutines...", "ViewSubs", "F2"),
|
|
createmenuitem("Declaration", "ViewDecl", "<Control>D", "<Control>F2"),
|
|
createmenuitem("Subroutine Arguments...", "ViewArgs", "<Shift>F2"),
|
|
createmenuitem("Completions...", "ViewComp", "<Control>space"),
|
|
createmenuitem("Goto Error", "ViewError", "F4"),
|
|
createmenuitem("Go Back", "GoBack", "Escape")
|
|
})
|
|
set(menuView, "submenu", viewmenu)
|
|
|
|
add(runmenu, {
|
|
createmenuitem("Start", "RunStart", "F5"),
|
|
createmenuitem("Start with Arguments", "RunStart", "<Shift>F5"),
|
|
createmenuitem("Set Arguments...", "RunSetArguments"),
|
|
createmenuitem("Run In Background", "RunBackground", 0, run_background),
|
|
create(GtkSeparatorMenuItem),
|
|
createmenuitem("Set Interpreter...", "RunSetInterpreter"),
|
|
createmenuitem("Set Terminal Emulator...", "RunSetTerminal"),
|
|
createmenuitem("Run Terminal Emulator", "RunStart"),
|
|
createmenuitem("Wait for Keypress after Run in Terminal", "RunWaitKey", 0, run_waitkey),
|
|
create(GtkSeparatorMenuItem),
|
|
createmenuitem("Bind", "RunStart"),
|
|
createmenuitem("Shroud", "RunStart"),
|
|
createmenuitem("Translate and Compile", "RunStart", "F9"),
|
|
create(GtkSeparatorMenuItem),
|
|
createmenuitem("Test Run after Bind/Shroud/Translate", "RunTestRun", 0, run_testrun)
|
|
})
|
|
set(menuRun, "submenu", runmenu)
|
|
|
|
add(optionsmenu, {
|
|
createmenuitem("Font...", "OptionsFont"),
|
|
createmenuitem("Line Numbers", "OptionsLineNumbers", 0, line_numbers),
|
|
createmenuitem("Sort View Subroutines", "OptionsSortedSubs", 0, sorted_subs),
|
|
createmenuitem("Colors...", "OptionsColors"),
|
|
createmenuitem("Line Wrap", "OptionsLineWrap", 0, line_wrap),
|
|
createmenuitem("Reopen Tabs Next Time", "OptionsReopenTabs", 0, reopen_tabs),
|
|
createmenuitem("Complete Statements", "OptionsCompleteStatements", 0, complete_statements),
|
|
createmenuitem("Complete Braces", "OptionsCompleteBraces", 0, complete_braces),
|
|
createmenuitem("Indent...", "OptionsIndent"),
|
|
createmenuitem("Error Indicators", "OptionsErrorIndicators", 0, auto_indicator)
|
|
})
|
|
set(menuOptions, "submenu", optionsmenu)
|
|
|
|
add(helpmenu, {
|
|
createmenuitem("About...", "HelpAbout"),
|
|
createmenuitem("Release Notes...", "HelpReleaseNotes"),
|
|
createmenuitem("Tutorial", "HelpTutorial"),
|
|
createmenuitem("Help", "HelpHelp", "F1")
|
|
})
|
|
set(menuHelp, "submenu", helpmenu)
|
|
|
|
-- popup menu for tab controls
|
|
add(tabmenu, {
|
|
createmenuitem("Save", "FileSave"),
|
|
createmenuitem("Save As...", "FileSaveAs"),
|
|
createmenuitem("Close", "FileClose")
|
|
})
|
|
show_all(tabmenu)
|
|
|
|
add(menubar, {
|
|
menuFile,
|
|
menuEdit,
|
|
menuSearch,
|
|
menuView,
|
|
menuRun,
|
|
menuOptions,
|
|
menuHelp})
|
|
|
|
pack(panel, menubar)
|
|
|
|
-------------------------------------------------
|
|
function NotebookSwitchPage(atom nb, atom page, atom page_num)
|
|
select_tab(page_num + 1)
|
|
return 0
|
|
end function
|
|
|
|
function NotebookButtonPressEvent(atom nb, atom event)
|
|
integer button = events:button(event)
|
|
|
|
-- right click or middle click
|
|
if button = 3 or button = 2 then
|
|
atom x, y, lx, ly, lw, lh
|
|
{x,y} = events:xy(event) -- get mouse coordinates
|
|
atom allocation = allocate(4*4)
|
|
for i = 1 to gtk:get(nb, "n_pages") do
|
|
atom pg = gtk:get(nb, "nth_page", i-1)
|
|
atom lbl = gtk:get(nb, "tab_label", pg)
|
|
|
|
gtk_func("gtk_widget_get_allocation", {P,P}, {lbl, allocation})
|
|
{lx, ly, lw, lh} = peek4u({allocation, 4}) -- get label rect
|
|
|
|
if x >= lx-10 and x <= lx+lw+10 then
|
|
if button = 3 then -- right click
|
|
select_tab(i)
|
|
set(tabmenu, "popup", NULL, NULL, NULL, NULL, 0, events:time(event))
|
|
elsif button = 2 then -- middle click
|
|
select_tab(i)
|
|
close_tab()
|
|
end if
|
|
exit
|
|
end if
|
|
end for
|
|
free(allocation)
|
|
return 1
|
|
end if
|
|
|
|
return 0
|
|
end function
|
|
|
|
-- switch tabs when mouse wheel is scrolled
|
|
function NotebookScrollEvent(atom nb, atom event)
|
|
integer dir = events:scroll_dir(event)
|
|
if dir = 1 then
|
|
select_tab(get_next_tab())
|
|
elsif dir = 0 then
|
|
select_tab(get_prev_tab())
|
|
end if
|
|
return 0
|
|
end function
|
|
|
|
-- detect <Control>Tab and <Shift><Control>Tab
|
|
function NotebookKeyPressEvent(atom nb, atom event)
|
|
integer mod = events:state(event)
|
|
if key(event) = -9 and and_bits(mod, GDK_CONTROL_MASK) then
|
|
if and_bits(mod, GDK_SHIFT_MASK) then
|
|
select_tab(get_prev_tab())
|
|
else
|
|
select_tab(get_next_tab())
|
|
end if
|
|
return 1
|
|
end if
|
|
return 0
|
|
end function
|
|
|
|
|
|
constant
|
|
status_label = create(GtkLabel, "status"),
|
|
notebook = create(GtkNotebook, {
|
|
{"add_events", GDK_SCROLL_MASK},
|
|
{"scrollable", TRUE},
|
|
{"show border", FALSE}, -- seems to have opposite effect?
|
|
{"action widget", status_label, GTK_PACK_END}})
|
|
|
|
pack(panel, notebook, TRUE, TRUE)
|
|
show(status_label)
|
|
|
|
connect(notebook, "switch-page", callback("NotebookSwitchPage"))
|
|
connect(notebook, "button-press-event", callback("NotebookButtonPressEvent"))
|
|
connect(notebook, "scroll-event", callback("NotebookScrollEvent"))
|
|
connect(notebook, "key-press-event", callback("NotebookKeyPressEvent"))
|
|
|
|
--------------------------------------------------
|
|
|
|
sequence ui_hedits
|
|
ui_hedits = {}
|
|
|
|
function tab_hedit()
|
|
integer tab
|
|
tab = gtk:get(notebook, "current page")
|
|
return ui_hedits[tab+1]
|
|
end function
|
|
|
|
--------------------------------------------------
|
|
|
|
global procedure ui_update_status(sequence status)
|
|
set(status_label, "text", status)
|
|
end procedure
|
|
|
|
function file_open_recent(atom handle, integer idx)
|
|
open_recent(idx)
|
|
return 0
|
|
end function
|
|
|
|
sequence filemenu_items = {}
|
|
|
|
global procedure ui_refresh_file_menu(sequence items)
|
|
atom widget
|
|
if length(filemenu_items) = 0 and length(items) != 0 then
|
|
add(filemenu, create(GtkSeparatorMenuItem))
|
|
end if
|
|
for i = 1 to length(items) do
|
|
if i > length(filemenu_items) then
|
|
widget = create(GtkMenuItem, items[i])
|
|
set(widget, "use underline", 0)
|
|
filemenu_items &= widget
|
|
add(filemenu, widget)
|
|
connect(widget, "activate", callback("file_open_recent"), i)
|
|
else
|
|
set(filemenu_items[i], "label", items[i])
|
|
end if
|
|
end for
|
|
end procedure
|
|
|
|
global procedure ui_select_tab(integer tab)
|
|
set(notebook, "current page", tab - 1)
|
|
gtk_proc("gtk_widget_grab_focus", {P}, ui_hedits[tab])
|
|
end procedure
|
|
|
|
global procedure ui_update_window_title(sequence name)
|
|
set(win, "title", name & " ~ " & window_title)
|
|
end procedure
|
|
|
|
global procedure ui_update_tab_name(integer tab, sequence name)
|
|
set(notebook, "tab label text", ui_hedits[tab], name)
|
|
set(gtk:get(notebook, "tab label", ui_hedits[tab]), "tooltip text", file_name)
|
|
end procedure
|
|
|
|
constant sci_notify_cb = callback("sci_notify")
|
|
|
|
global function ui_new_tab(sequence name)
|
|
atom editor
|
|
|
|
editor = scintilla_new()
|
|
ui_hedits &= editor
|
|
init_edit(editor)
|
|
gtk_proc("gtk_widget_show", {P}, editor)
|
|
|
|
set(notebook, "append page", editor, create(GtkLabel, name))
|
|
|
|
connect(editor, "sci-notify", sci_notify_cb, 0)
|
|
|
|
return editor
|
|
end function
|
|
|
|
global procedure ui_close_tab(integer tab)
|
|
set(notebook, "remove page", tab-1)
|
|
|
|
-- remove the window handle
|
|
ui_hedits = ui_hedits[1..tab-1] & ui_hedits[tab+1..$]
|
|
end procedure
|
|
|
|
|
|
constant filters = {
|
|
create(GtkFileFilter, {
|
|
{"name", "Euphoria files"},
|
|
{"add pattern", "*.e"},
|
|
{"add pattern", "*.ex"},
|
|
{"add pattern", "*.exw"},
|
|
{"add pattern", "*.ew"},
|
|
{"add pattern", "ex.err"},
|
|
{"add pattern", "eu.cfg"}}),
|
|
create(GtkFileFilter, {
|
|
{"name", "Text files"},
|
|
{"add mime type", "text/*"}}),
|
|
create(GtkFileFilter, {
|
|
{"name", "All files"},
|
|
{"add pattern", "*"}})}
|
|
atom current_filter = filters[1]
|
|
|
|
global function ui_get_open_file_name()
|
|
atom dialog
|
|
sequence filename
|
|
|
|
dialog = create(GtkFileChooserDialog, {
|
|
{"title", "Open..."},
|
|
{"transient for", win},
|
|
{"action", GTK_FILE_CHOOSER_ACTION_OPEN},
|
|
{"select multiple", TRUE},
|
|
{"add button", "gtk-cancel", GTK_RESPONSE_CLOSE},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"position", GTK_WIN_POS_MOUSE},
|
|
{"current folder", pathname(canonical_path(file_name))}})
|
|
add(dialog, filters)
|
|
set(dialog, "filter", current_filter)
|
|
|
|
if gtk:get(dialog, "run") = GTK_RESPONSE_OK then
|
|
current_filter = gtk:get(dialog, "filter")
|
|
filename = gtk:get(dialog, "filenames")
|
|
if length(filename) = 1 then
|
|
-- single filename selected
|
|
filename = filename[1]
|
|
end if
|
|
else
|
|
filename = ""
|
|
end if
|
|
set(dialog, "hide")
|
|
|
|
return filename
|
|
end function
|
|
|
|
global function ui_get_save_file_name(sequence filename)
|
|
atom dialog
|
|
|
|
dialog = create(GtkFileChooserDialog, {
|
|
{"title", "Save As..."},
|
|
{"transient for", win},
|
|
{"action", GTK_FILE_CHOOSER_ACTION_SAVE},
|
|
{"select multiple", FALSE},
|
|
{"do overwrite confirmation", TRUE},
|
|
{"add button", "gtk-cancel", GTK_RESPONSE_CLOSE},
|
|
{"add button", "gtk-ok", GTK_RESPONSE_OK},
|
|
{"filename", filename},
|
|
{"position", GTK_WIN_POS_MOUSE},
|
|
{"current folder", pathname(canonical_path(file_name))}})
|
|
add(dialog, filters)
|
|
|
|
if gtk:get(dialog, "run") = GTK_RESPONSE_OK then
|
|
current_filter = gtk:get(dialog, "filter")
|
|
filename = gtk:get(dialog, "filename")
|
|
else
|
|
filename = ""
|
|
end if
|
|
set(dialog, "hide")
|
|
|
|
return filename
|
|
end function
|
|
|
|
-- returns yes=1 no=0
|
|
global function ui_message_box_yes_no(sequence title, sequence message)
|
|
integer result
|
|
result = Question(win, title, "", message)
|
|
return (result = MB_YES)
|
|
end function
|
|
|
|
-- returns yes=1 no=0 cancel=-1
|
|
global function ui_message_box_yes_no_cancel(sequence title, sequence message)
|
|
atom dialog, result
|
|
dialog = create(GtkMessageDialog, {
|
|
{"title", title},
|
|
{"transient for", win},
|
|
{"add button", "gtk-cancel", -1},
|
|
{"add button", "gtk-no", 0},
|
|
{"add button", "gtk-yes", 1},
|
|
{"transient for", win},
|
|
{"destroy with parent", TRUE},
|
|
{"text", message},
|
|
{"position", GTK_WIN_POS_CENTER_ON_PARENT}})
|
|
|
|
result = gtk:get(dialog, "run")
|
|
set(dialog, "hide")
|
|
|
|
return result
|
|
end function
|
|
|
|
global function ui_message_box_error(sequence title, sequence message)
|
|
Error(win, title, , message, GTK_BUTTONS_OK)
|
|
return 0
|
|
end function
|
|
|
|
global procedure ui_view_error()
|
|
sequence err
|
|
atom dialog, scroll, list, content, row, lbl
|
|
integer result
|
|
|
|
err = get_ex_err()
|
|
if length(err) = 0 then return end if
|
|
|
|
dialog = create(GtkDialog, {
|
|
{"border width", 5},
|
|
{"default size", 200, 400},
|
|
{"add button", "gtk-close", GTK_RESPONSE_CLOSE},
|
|
{"add button", "Open Ex.Err", GTK_RESPONSE_YES},
|
|
{"add button", "Goto Error", GTK_RESPONSE_OK},
|
|
{"transient for", win},
|
|
{"title", "View Error"},
|
|
{"default response", GTK_RESPONSE_OK},
|
|
{"modal", TRUE}})
|
|
content = gtk:get(dialog, "content area")
|
|
|
|
lbl = create(GtkLabel, err[2])
|
|
pack(content, lbl)
|
|
|
|
content = gtk:get(dialog, "content area")
|
|
scroll = create(GtkScrolledWindow)
|
|
pack(content, scroll, TRUE, TRUE)
|
|
|
|
list = create(GtkListBox)
|
|
add(scroll, list)
|
|
for i = 3 to length(err) do
|
|
lbl = create(GtkLabel, err[i])
|
|
set(lbl, "halign", GTK_ALIGN_START)
|
|
set(list, "insert", lbl, -1)
|
|
end for
|
|
|
|
show_all(dialog)
|
|
result = set(dialog, "run")
|
|
if result = GTK_RESPONSE_OK then
|
|
row = gtk:get(list, "selected row")
|
|
--result = gtk:get(row, "index") -- doesn't work?
|
|
for i = 0 to length(err)-3 do
|
|
if row = gtk:get(list, "row at index", i) then
|
|
goto_error(err, i+1)
|
|
exit
|
|
end if
|
|
end for
|
|
elsif result = GTK_RESPONSE_YES then
|
|
open_file(ex_err_name, 1)
|
|
end if
|
|
hide(dialog)
|
|
end procedure
|
|
|
|
--------------------------------------------------
|
|
-- help window
|
|
|
|
function HelpActivateLink(atom handle, atom uri, atom userdata)
|
|
puts(1, peek_string(uri)&"\n")
|
|
return 1
|
|
end function
|
|
|
|
function Hide(atom handle)
|
|
set(handle,"visible",FALSE)
|
|
return 1
|
|
end function
|
|
|
|
constant helpwin = create(GtkWindow, {
|
|
{"transient for", win},
|
|
{"title", "Help"},
|
|
{"default size", 400, 400},
|
|
{"border width", 10},
|
|
{"deletable", FALSE}, --!
|
|
{"resizable", FALSE}})
|
|
connect(helpwin, "delete-event", callback("Hide"))
|
|
|
|
constant helplbl = create(GtkLabel)
|
|
add(helpwin,helplbl)
|
|
connect(helplbl, "activate-link", callback("HelpActivateLink"))
|
|
|
|
function re(sequence txt, sequence rx, sequence rep)
|
|
return regex:find_replace(regex:new(rx), txt, rep)
|
|
end function
|
|
|
|
-- FIXME this doesn't work very well
|
|
function html_to_markup(sequence html)
|
|
html = re(html, `<a name="[A-Za-z0-9_]+">([A-Za-z0-9. ]*)</a>`, `\1`)
|
|
html = re(html, `<p> ?`, ``)
|
|
html = re(html, `</p>`, ``)
|
|
html = re(html, `<font`, `<span`)
|
|
html = re(html, `</font>`, `</span>`)
|
|
html = re(html, `<pre class="[A-Za-z0-9_]+">`, `<tt>`)
|
|
html = re(html, `</pre>`, `</tt>`)
|
|
html = re(html, `<h5>`, `<big>`)
|
|
html = re(html, `</h5>`, `</big>`)
|
|
html = re(html, `<ol>`, `\n`)
|
|
html = re(html, `</ol>`, ``)
|
|
html = re(html, `<li>`, ` 1. `)
|
|
html = re(html, `</li>`, `\n`)
|
|
html = re(html, `<ul>`, `\n`)
|
|
html = re(html, `</ul>`, ``)
|
|
html = re(html, `\n\n+`, `\n\n`)
|
|
puts(1, html)
|
|
return html
|
|
end function
|
|
|
|
global function ui_show_help(sequence html)
|
|
set(helplbl,"markup",html_to_markup(html))
|
|
show_all(helpwin)
|
|
return 0
|
|
end function
|
|
|
|
global procedure ui_show_uri(sequence uri)
|
|
show_uri(uri)
|
|
end procedure
|
|
|
|
--------------------------------------------------
|
|
|
|
ui_refresh_file_menu(recent_files)
|
|
|
|
-- open files from last time and on command line
|
|
open_tabs()
|
|
|
|
show_all(win)
|
|
main()
|