Initial import of gtk2_ardour.

git-svn-id: svn://localhost/trunk/ardour2@24 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Taybin Rutkin
2005-09-25 18:42:24 +00:00
parent e4b9aed743
commit 209d967b1b
240 changed files with 136995 additions and 0 deletions

7
gtk2_ardour/.cvsignore Normal file
View File

@@ -0,0 +1,7 @@
ardour
ardourx
ardour.bin
version.h
version.cc
*.mo
*.pot

227
gtk2_ardour/SConscript Normal file
View File

@@ -0,0 +1,227 @@
# -*- python -*-
import os
import os.path
import glob
Import('env install_prefix final_prefix config_prefix libraries i18n version')
gtkardour = env.Copy()
#
# this defines the version number of the GTK interface to ardour
#
domain = 'gtk_ardour'
gtkardour.Append(DOMAIN=domain, MAJOR=1,MINOR=0,MICRO=0)
gtkardour.Append(CXXFLAGS="-DPACKAGE=\\\"" + domain + "\\\"")
gtkardour.Append(PACKAGE=domain)
gtkardour.Append(POTFILE=domain + '.pot')
gtkardour.Merge ( [libraries['ardour2'],
libraries['gtkmm2ext'],
libraries['midi++2'],
libraries['pbd3'],
libraries['gtkmm2'],
libraries['sigc2'],
libraries['libgnomecanvasmm'],
libraries['sysmidi'],
libraries['sndfile'],
libraries['lrdf'],
libraries['glibmm2'],
libraries['pangomm'],
libraries['atkmm'],
libraries['gdkmm2'],
libraries['gtk2'],
libraries['libgnomecanvas2'],
libraries['xml'],
libraries['soundtouch'],
libraries['raptor'],
libraries['samplerate'],
libraries['jack']]
)
if gtkardour['VST']:
gtkardour.Merge ([ libraries['fst']])
gtkardour_files=Split("""
add_route_dialog.cc
ardour_dialog.cc
ardour_message.cc
audio_clock.cc
automation_gain_line.cc
axis_view.cc
default_keys.cc
editing.cc
gain_automation_time_axis.cc
grouped_buttons.cc
gtk-custom-hruler.c
gtk-custom-ruler.c
keyboard.cc
keyboard_target.cc
meter_bridge_strip.cc
opts.cc
pan_automation_time_axis.cc
prompter.cc
redirect_automation_line.cc
redirect_automation_time_axis.cc
route_redirect_selection.cc
tempo_dialog.cc
time_selection.cc
version.cc
ardour_ui_dependents.cc
ardour_ui_mixer.cc
automation_pan_line.cc
curvetest.cc
editor_scrub.cc
ghostregion.cc
gtkscrolledwindow.c
imageframe_time_axis.cc
imageframe_time_axis_view.cc
imageframe_view.cc
marker.cc
marker_time_axis.cc
marker_time_axis_view.cc
marker_view.cc
public_editor.cc
region_gain_line.cc
region_selection.cc
selection.cc
ardour_ui_ed.cc
canvas-ruler.c
canvas-simpleline.c
canvas-simplerect.c
canvas-waveview.c
editor_audiotrack.cc
editor_canvas_events.cc
editor_cursors.cc
editor_export_audio.cc
editor_keys.cc
editor_nudge.cc
editor_timefx.cc
imageframe_time_axis_group.cc
send_ui.cc
time_axis_view.cc
editor_markers.cc
editor_tempodisplay.cc
main.cc
panner2d.cc
region_editor.cc
streamview.cc
utils.cc
automation_time_axis.cc
connection_editor.cc
crossfade_edit.cc
crossfade_view.cc
editor_hscroller.cc
editor_mixer.cc
imageframe_socket_handler.cc
location_ui.cc
route_ui.cc
time_axis_view_item.cc
visual_time_axis.cc
ardour_ui.cc
ardour_ui2.cc
ardour_ui_dialogs.cc
audio_time_axis.cc
automation_line.c
canvas-imageframe.cc
about.cc
editor.cc
editor_edit_groups.cc
editor_imageframe.cc
editor_keyboard.cc
editor_mouse.cc
editor_ops.cc
editor_region_list.cc
editor_route_list.cc
editor_rulers.cc
editor_selection_list.cc
export_dialog.cc
gain_meter.cc
io_selector.cc
library_ui.cc
meter_bridge.cc
mixer_strip.cc
mixer_ui.cc
new_session_dialog.cc
option_editor.cc
panner_ui.cc
playlist_selector.cc
plugin_selector.cc
plugin_ui.cc
redirect_box.cc
regionview.cc
route_params_ui.cc
""")
extra_sources = []
vst_files = [ 'vst_pluginui.cc' ]
if env['VST']:
extra_sources += vst_files
gtkardour.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
gtkardour.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
gtkardour.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
versionflag = '-DVERSIONSTRING=\\\"' + env['VERSION'] + '\\\"'
gtkardour.Append(CXXFLAGS=versionflag)
gtkardour.VersionBuild(['version.cc','version.h'], 'SConscript')
executable = 'ardour.bin'
ardour = gtkardour.Program(target = executable, source = gtkardour_files + extra_sources)
Default(ardour)
if env['VERSIONED']:
Default (env.VersionedExecutable ('tagged_executable', ardour))
if env['NLS']:
i18n (gtkardour, gtkardour_files + extra_sources, env)
#install
env.Alias('install', env.InstallAs(os.path.join(install_prefix, 'bin')+'/ardour', ardour))
env.Alias('install', env.Install(os.path.join(config_prefix, 'ardour'), 'ardour_ui.rc'))
env.Alias('install', env.Install(os.path.join(install_prefix, 'share/ardour'), 'splash.ppm'))
#dist
env.Alias ('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript',
'i18n.h', 'gettext.h',
'editor_xpms', 'misc_xpms', 'transport_xpms',
'ardour_ui.rc', 'splash.ppm'
] +
gtkardour_files + vst_files +
glob.glob('po/*.po') + glob.glob('*.h')))
# generate a prototype full-featured ardour_ui.rc file
env.Alias ('protorc', env.Command ('proto.rc', gtkardour_files, """
grep set_name $SOURCES | \
sed 's/.*("\([a-zA-Z_][a-zA-Z_]*\)").*/\\1/' | \
grep -v '\\.' | sort | uniq | \
awk '/\\./ {} { printf ("style \\"%s\\"\\n{\\n\
fg[NORMAL] = { 0, 0, 0 }\\n\
fg[ACTIVE] = { 0, 0, 0 }\\n\
fg[SELECTED] = { 0, 0, 0 }\\n\
bg[NORMAL] = { 0, 0, 0 }\\n\
bg[ACTIVE] = { 0, 0, 0 }\\n\
bg[SELECTED] = { 0, 0, 0 }\\n\
}\\nwidget \\"*%s\\" style \\"%s\\"\\nwidget \\"*%s*\\" style \\"%s\\"\\n\\n", \
$$0, $$0, $$0, $$0, $$0) }' > $TARGET && \
grep 'color_map\[[a-zA-Z_][a-zA-Z]*\]' $SOURCES | \
sed 's/.*\[\([a-zA-Z_][a-zA-Z_]*\)].*/\\1/'| \
sort | uniq | \
awk '{ printf ("style \\"%s\\"\\n{\\n\
fg[NORMAL] = { 0, 0, 0 }\\n\
fg[ACTIVE] = { 0, 0, 0 }\\n\
}\\nwidget \\"*%s\\" style \\"%s\\"\\n \\n\\n", $$0, $$0, $$0) }' >> $TARGET ;
"""
))

648
gtk2_ardour/ab.xpm Normal file
View File

@@ -0,0 +1,648 @@
/* XPM */
static const gchar * about_xpm[] = {
"256 256 389 2",
" c None",
". c #DF94BA",
"+ c #DE94BA",
"@ c #DD94BB",
"# c #DC94BB",
"$ c #DB94BC",
"% c #DA94BC",
"& c #D994BC",
"* c #D894BD",
"= c #D794BD",
"- c #D694BE",
"; c #D594BE",
"> c #D494BF",
", c #D394BF",
"' c #D294BF",
") c #D194C0",
"! c #D094C0",
"~ c #CF94C1",
"{ c #CE94C1",
"] c #CD94C1",
"^ c #CD95C2",
"/ c #CC95C2",
"( c #CB95C3",
"_ c #CA95C3",
": c #C995C3",
"< c #C895C4",
"[ c #C795C4",
"} c #C695C5",
"| c #C595C5",
"1 c #C495C6",
"2 c #C395C6",
"3 c #9F7EC4",
"4 c #8C72C4",
"5 c #C295C6",
"6 c #554EC1",
"7 c #1E2BBF",
"8 c #C195C7",
"9 c #544EC2",
"0 c #C095C7",
"a c #8A72C4",
"b c #C095C8",
"c c #BF95C8",
"d c #8972C5",
"e c #BE95C8",
"f c #534EC2",
"g c #BD95C9",
"h c #8872C6",
"i c #BC95C9",
"j c #8772C6",
"k c #BB95CA",
"l c #524EC3",
"m c #BA95CA",
"n c #BA96CA",
"o c #8672C6",
"p c #524FC3",
"q c #B996CA",
"r c #8572C6",
"s c #B896CB",
"t c #8572C7",
"u c #514FC3",
"v c #B796CB",
"w c #8472C7",
"x c #B696CC",
"y c #8372C8",
"z c #B596CC",
"A c #504FC3",
"B c #7267C6",
"C c #A48ACB",
"D c #947FC9",
"E c #AB89C8",
"F c #A88AC9",
"G c #7467C6",
"H c #4043C2",
"I c #625BC5",
"J c #655AC3",
"K c #AA89C9",
"L c #645BC4",
"M c #8272C8",
"N c #B496CD",
"O c #2F37C1",
"P c #504FC4",
"Q c #A989C9",
"R c #3037C0",
"S c #997EC7",
"T c #B396CD",
"U c #927FCA",
"V c #8172C8",
"W c #7167C7",
"X c #A38ACB",
"Y c #3F43C2",
"Z c #B296CD",
"` c #4F4FC4",
" . c #A28ACB",
".. c #A28ACC",
"+. c #B296CE",
"@. c #927FCB",
"#. c #7067C7",
"$. c #8172C9",
"%. c #605BC6",
"&. c #B196CE",
"*. c #635BC4",
"=. c #8072C9",
"-. c #A18ACC",
";. c #B096CE",
">. c #4143C1",
",. c #4243C1",
"'. c #7F72C9",
"). c #A08ACC",
"!. c #6F67C7",
"~. c #5F5BC6",
"{. c #B096CF",
"]. c #AC89C8",
"^. c #A08ACD",
"/. c #3F43C3",
"(. c #7F72CA",
"_. c #907FCB",
":. c #6F67C8",
"<. c #AF96CF",
"[. c #967FC8",
"}. c #4E4FC4",
"|. c #8F7FCB",
"1. c #3E43C3",
"2. c #9F8ACD",
"3. c #AE96CF",
"4. c #7E72CA",
"5. c #6E67C8",
"6. c #2E37C1",
"7. c #9E8ACD",
"8. c #AD96D0",
"9. c #7D72CA",
"0. c #4E4FC5",
"a. c #5E5BC7",
"b. c #AC96D0",
"c. c #4D4FC5",
"d. c #8D7FCC",
"e. c #9C8ACE",
"f. c #AB96D0",
"g. c #7C72CA",
"h. c #8C7FCC",
"i. c #AB96D1",
"j. c #7C72CB",
"k. c #AA96D1",
"l. c #7B72CB",
"m. c #3D43C3",
"n. c #6C67C9",
"o. c #A78ACA",
"p. c #7367C6",
"q. c #2F37C0",
"r. c #977FC8",
"s. c #A996D2",
"t. c #4C4FC5",
"u. c #7B72CC",
"v. c #A896D2",
"w. c #7A72CC",
"x. c #A58ACB",
"y. c #A797D2",
"z. c #7973CC",
"A. c #957FC8",
"B. c #A697D3",
"C. c #4B4FC6",
"D. c #5B5BC8",
"E. c #A597D3",
"F. c #7873CC",
"G. c #2D37C1",
"H. c #6967CA",
"I. c #A497D4",
"J. c #7773CD",
"K. c #958BD2",
"L. c #9B7EC6",
"M. c #877FCF",
"N. c #A397D4",
"O. c #4A4FC6",
"P. c #3C43C4",
"Q. c #6867CB",
"R. c #A297D5",
"S. c #7673CE",
"T. c #595BC9",
"U. c #2D37C2",
"V. c #A197D5",
"W. c #7573CE",
"X. c #847FD0",
"Y. c #978BD1",
"Z. c #3B43C4",
"`. c #938BD3",
" + c #A097D5",
".+ c #968BD1",
"++ c #6D67C8",
"@+ c #6667CB",
"#+ c #494FC6",
"$+ c #928BD3",
"%+ c #837FD0",
"&+ c #585BC9",
"*+ c #5A5BC8",
"=+ c #605BC5",
"-+ c #9F97D6",
";+ c #837FD1",
">+ c #6667CC",
",+ c #7473CE",
"'+ c #494FC7",
")+ c #918BD3",
"!+ c #6767CB",
"~+ c #3C43C3",
"{+ c #9A8AD0",
"]+ c #5C5BC7",
"^+ c #8E7FCB",
"/+ c #9E97D6",
"(+ c #6567CC",
"_+ c #908BD3",
":+ c #7373CE",
"<+ c #987FC8",
"[+ c #8E7FCC",
"}+ c #575BC9",
"|+ c #9D97D7",
"1+ c #595BC8",
"2+ c #867FCF",
"3+ c #997EC8",
"4+ c #817FD2",
"5+ c #7373CF",
"6+ c #8F8BD4",
"7+ c #9C97D7",
"8+ c #9B97D8",
"9+ c #9A97D8",
"0+ c #9997D8",
"a+ c #9997D9",
"b+ c #9897D9",
"c+ c #9797D9",
"d+ c #9797DA",
"e+ c #9697DA",
"f+ c #6E73D1",
"g+ c #7273CF",
"h+ c #7173D0",
"i+ c #898BD7",
"j+ c #3943C5",
"k+ c #545BCB",
"l+ c #6167CD",
"m+ c #464FC8",
"n+ c #2C37C2",
"o+ c #9597DA",
"p+ c #9D8ACE",
"q+ c #484FC7",
"r+ c #555BCA",
"s+ c #6D73D1",
"t+ c #6167CE",
"u+ c #7C7FD3",
"v+ c #9C8ACF",
"w+ c #948BD2",
"x+ c #7F7FD3",
"y+ c #7073D0",
"z+ c #6F73D0",
"A+ c #7C7FD4",
"B+ c #6067CE",
"C+ c #888BD7",
"D+ c #8B8BD6",
"E+ c #8E8BD4",
"F+ c #6A67CA",
"G+ c #8C7FCD",
"H+ c #474FC7",
"I+ c #6F73D1",
"J+ c #7B7FD4",
"K+ c #8A8BD7",
"L+ c #6267CD",
"M+ c #6367CD",
"N+ c #3A43C5",
"O+ c #615BC5",
"P+ c #9B8ACF",
"Q+ c #827FD1",
"R+ c #7D7FD3",
"S+ c #857FD0",
"T+ c #6967CB",
"U+ c #937FCA",
"V+ c #7566C5",
"W+ c #917FCB",
"X+ c #555BCB",
"Y+ c #5D5BC7",
"Z+ c #7E7FD3",
"`+ c #535BCB",
" @ c #474FC8",
".@ c #6467CC",
"+@ c #7467C5",
"@@ c #957FC9",
"#@ c #645AC4",
"$@ c #7567C5",
"%@ c #5B5BC7",
"&@ c #565BCA",
"*@ c #8C8BD5",
"=@ c #8A8BD6",
"-@ c #887FCF",
";@ c #807FD3",
">@ c #3A43C4",
",@ c #8B7FCD",
"'@ c #7267C7",
")@ c #998AD0",
"!@ c #6B67CA",
"~@ c #807FD2",
"{@ c #8B8BD5",
"]@ c #8A7FCE",
"^@ c #6467CD",
"/@ c #988BD0",
"(@ c #8D8BD5",
"_@ c #575BCA",
":@ c #9358B7",
"<@ c #700999",
"[@ c #A587CA",
"}@ c #9058B8",
"|@ c #A487CB",
"1@ c #8A48B2",
"2@ c #77199F",
"3@ c #8338AC",
"4@ c #9967BE",
"5@ c #9E77C5",
"6@ c #8438AC",
"7@ c #9767BE",
"8@ c #A587CB",
"9@ c #8438AB",
"0@ c #7D29A5",
"a@ c #9158B8",
"b@ c #7E29A5",
"c@ c #8B48B2",
"d@ c #9F77C4",
"e@ c #9867BE",
"f@ c #A077C4",
"g@ c #9D67BC",
"h@ c #9C67BC",
"i@ c #A477C2",
"j@ c #A687CA",
"k@ c #A067BA",
"l@ c #B187C5",
"m@ c #9E67BB",
"n@ c #78199F",
"o@ c #8638AA",
"p@ c #8638AB",
"q@ c #9967BD",
"r@ c #8C48B1",
"s@ c #8538AB",
"t@ c #A787C9",
"u@ c #A077C3",
"v@ c #A377C2",
"w@ c #8F48B0",
"x@ c #8029A4",
"y@ c #8838AA",
"z@ c #9957B4",
"A@ c #A677C1",
"B@ c #7F29A5",
"C@ c #9A67BD",
"D@ c #A887C9",
"E@ c #A177C3",
"F@ c #8738AA",
"G@ c #B386C5",
"H@ c #7F29A4",
"I@ c #A987C9",
"J@ c #9B67BD",
"K@ c #9458B7",
"L@ c #8D48B1",
"M@ c #A277C3",
"N@ c #9B67BC",
"O@ c #A777C1",
"P@ c #A266BA",
"Q@ c #9658B6",
"R@ c #A277C2",
"S@ c #A987C8",
"T@ c #AC87C7",
"U@ c #A577C2",
"V@ c #AA87C8",
"W@ c #AB76BF",
"X@ c #9658B5",
"Y@ c #9558B7",
"Z@ c #AB87C8",
"`@ c #8E48B1",
" # c #8838A9",
".# c #8938A9",
"+# c #9558B6",
"@# c #8E48B0",
"## c #AB87C7",
"$# c #AD87C7",
"%# c #9F67BA",
"&# c #AD87C6",
"*# c #9858B5",
"=# c #AE87C6",
"-# c #9758B5",
";# c #9F67BB",
"># c #9048AF",
",# c #AF87C6",
"'# c #A777C0",
")# c #A977BF",
"!# c #A877C0",
"~# c #9958B4",
"{# c #A167BA",
"]# c #AA76BF",
"^# c #B286C5",
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + ",
". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ + ",
". + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # @ + ",
". + @ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # $ # @ + ",
". + @ # $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ % $ # @ + ",
". + @ # $ % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % & % $ # @ + ",
". + @ # $ % & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & * & % $ # @ + ",
". + @ # $ % & * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * = * & % $ # @ + ",
". + @ # $ % & * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = - = * & % $ # @ + ",
". + @ # $ % & * = - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 4 4 4 4 4 4 4 4 4 4 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 7 7 7 7 7 7 7 7 7 7 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 9 7 7 7 7 7 7 7 7 7 7 9 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 a 7 7 7 7 7 7 7 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b 9 7 7 7 7 7 7 9 b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c d 7 7 7 7 7 7 9 c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e d 7 7 7 7 7 7 f e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g h 7 7 7 7 7 7 f g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i j 7 7 7 7 7 7 f i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i j 7 7 7 7 7 7 f i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k j 7 7 7 7 7 7 l k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n o 7 7 7 7 7 7 p n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n n q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q r 7 7 7 7 7 7 p q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s t 7 7 7 7 7 7 u s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s t 7 7 7 7 7 7 u s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v w 7 7 7 7 7 7 u v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x y 7 7 7 7 7 7 u x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v y y A A A A A B y z z z z z z z z z z z z z z z z z z z z z z z z z z z z z C y A A A y z z z z z z z z z z z z z z y y A A A A A y y D y 7 7 7 7 7 7 A z z z z z z z z z z z z z z z z z z y B A A A A B y z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z z x v s s q m k i E h f 9 9 a 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n F G H 7 7 7 7 7 7 7 7 7 7 7 A D z z z z z z z z z 7 7 7 7 7 7 7 7 7 7 7 y z z z z I 7 7 7 7 7 A z z z z z z z z z z z D A 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 A z z z z z z z z z z z z z z z D H 7 7 7 7 7 7 7 7 7 7 H D z z z z z z z z z z z A 7 7 7 7 7 7 7 7 7 7 A z z z z z z z A 7 7 7 7 7 7 7 7 7 7 A z z z z z z 7 7 7 7 7 7 7 7 7 7 7 t s q m k J 7 7 7 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i K L 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 M N N N N N N N N 7 7 7 7 7 7 7 7 7 7 7 M N N C O 7 7 7 7 7 7 P N N N N N N N N N C P 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 P N N N N N N N N N N N N N C H 7 7 7 7 7 O P P O 7 7 7 7 7 H C N N N N N N N N N P 7 7 7 7 7 7 7 7 7 7 P N N N N N N N P 7 7 7 7 7 7 7 7 7 7 P N N N N N N 7 7 7 7 7 7 7 7 7 7 7 t s q Q R 7 7 7 7 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i S 7 7 7 7 7 7 I D z N T U P 7 7 7 7 7 7 V T T T T T T T V V W O 7 7 7 7 7 7 7 V T X O 7 7 7 7 7 7 7 P T T T T T T T T U O 7 7 7 7 7 7 Y V X T T T V W Y 7 7 7 7 7 7 P T T T T T T T T T T T T V 7 7 7 7 7 O U T T T T U O 7 7 7 7 7 V T T T T T T T T U V V Y 7 7 7 7 7 7 7 P T T T T T T T U V V Y 7 7 7 7 7 7 7 P T T T T T T V V W O 7 7 7 7 7 7 7 t s F R 7 7 7 7 7 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i j 7 7 7 7 7 w x z z N T Z Z ` 7 7 7 7 7 O Z Z Z Z Z Z Z Z Z Z .7 7 7 7 7 7 7 V Z O 7 7 7 7 7 7 7 7 ` Z Z Z Z Z Z Z V 7 7 7 7 7 7 O V Z Z Z Z Z Z Z Z V 7 7 7 7 7 7 ` Z Z Z Z Z Z Z Z Z Z Z V 7 7 7 7 7 O .Z Z Z Z Z Z .O 7 7 7 7 7 V Z Z Z Z Z Z Z Z Z Z Z Y 7 7 7 7 7 7 ` Z Z Z Z Z Z Z Z Z Z Z Y 7 7 7 7 7 7 ` Z Z Z Z Z Z Z Z Z ..7 7 7 7 7 7 7 t s R 7 7 7 7 7 7 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i j 7 7 7 7 H v x z z N T Z +.@.7 7 7 7 7 7 #.+.+.+.+.+.+.+.+.+.+.Y 7 7 7 7 7 7 $.%.7 7 7 7 7 7 7 7 7 ` +.+.+.+.+.+...O 7 7 7 7 7 O ..+.+.+.+.+.+.+.+.+.$.7 7 7 7 7 7 ` +.+.+.+.+.+.+.+.+.+.$.7 7 7 7 7 O ..+.+.+.+.+.+.+.+...7 7 7 7 7 7 @.+.+.+.+.+.+.+.+.+.+.#.7 7 7 7 7 7 ` +.+.+.+.+.+.+.+.+.+.+.#.7 7 7 7 7 7 ` +.+.+.+.+.+.+.+.&.+.Y 7 7 7 7 7 7 t *.7 7 7 7 7 7 7 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i j 7 7 7 7 *.v x z z N T Z +.&.7 7 7 7 7 7 ` &.&.&.&.&.&.&.&.&.&.` 7 7 7 7 7 7 %.7 7 7 Y =.=.Y 7 7 7 ` &.&.&.&.&.&.O 7 7 7 7 7 7 -.&.&.&.&.&.&.&.&.&.&.=.7 7 7 7 7 7 ` &.&.&.&.&.&.&.&.&.-.O 7 7 7 7 7 #.&.&.&.&.&.&.&.&.&.&.#.7 7 7 7 7 O -.&.&.&.&.&.&.&.&.&.=.7 7 7 7 7 7 ` &.&.&.&.&.&.&.&.&.&.&.=.7 7 7 7 7 7 ` &.&.&.&.&.&.&.;.&.+.` 7 7 7 7 7 7 *.7 7 7 >.j j ,.7 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i j 7 7 7 7 t v x z z N T Z +.&.7 7 7 7 7 7 7 ;.;.;.;.;.;.;.;.;.;.` 7 7 7 7 7 7 7 7 O '.;.;.;.).7 7 7 ` ;.;.;.;.;.!.7 7 7 7 7 7 !.;.;.;.;.;.;.;.;.;.;.;.'.7 7 7 7 7 7 ` ;.;.;.;.;.;.;.;.;.` 7 7 7 7 7 O ;.;.;.;.;.;.;.;.;.;.;.;.O 7 7 7 7 7 ~.;.;.;.;.;.;.;.;.;.'.7 7 7 7 7 7 ` ;.;.;.;.;.;.;.;.;.;.;.'.7 7 7 7 7 7 ` ;.;.;.;.;.;.{.;.&.+.` 7 7 7 7 7 7 7 7 R o k i i ].7 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i j 7 7 7 7 t v x z z N T Z +.&.` 7 7 7 7 7 7 ^.{.{.{.{.{.{.{.{.{.` 7 7 7 7 7 7 7 O ^.{.{.{.{.{./.7 7 ` {.{.{.{.^.7 7 7 7 7 7 O {.{.{.{.{.{.{.{.{.{.{.{.(.7 7 7 7 7 7 ` {.{.{.{.{.{.{.{._.7 7 7 7 7 7 :.{.{.{.{.{.{.{.{.{.{.{.{.:.7 7 7 7 7 7 _.{.{.{.{.{.{.{.{.(.7 7 7 7 7 7 ` {.{.{.{.{.{.{.{.{.{.{.(.7 7 7 7 7 7 ` {.{.{.{.{.<.{.;.&.+.` 7 7 7 7 7 7 7 R F m k i i g ,.7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i S l p p u [.v x z z N T Z +.&.` 7 7 7 7 7 7 (.<.<.<.<.<.<.<.<.<.}.7 7 7 7 7 7 7 |.<.<.<.<.<.<.}.7 7 }.<.<.<.<.~.7 7 7 7 7 7 :.<.<.<.<.<.<.<.<.<.<.<.<.(.7 7 7 7 7 7 }.<.<.<.<.<.<.<.<.1.7 7 7 7 7 7 2.<.<.<.<.<.<.<.<.<.<.<.<.2.7 7 7 7 7 7 }.<.<.<.<.<.<.<.<.(.7 7 7 7 7 7 }.<.<.<.<.<.<.<.<.<.<.<.(.7 7 7 7 7 7 }.<.<.<.<.3.<.{.;.&.+.` 7 7 7 7 7 7 7 [.q m k i i g f 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.` 7 7 7 7 7 7 4.3.3.3.3.3.3.3.3.3.}.7 7 7 7 7 7 5.3.3.3.3.3.3.3.}.7 7 }.3.3.3.3.6.7 7 7 7 7 7 3.3.3.3.3.3.3.3.3.3.3.3.3.4.7 7 7 7 7 7 }.3.3.3.3.3.3.3.7.7 7 7 7 7 7 1.3.3.3.3.3.3.3.3.3.3.3.3.3.3.1.7 7 7 7 7 7 7.3.3.3.3.3.3.3.4.7 7 7 7 7 7 }.3.3.3.3.3.3.3.3.3.3.3.4.7 7 7 7 7 7 }.3.3.3.8.3.<.{.;.&.+.` 7 7 7 7 7 7 G s q m k i i g f 7 7 9 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.` 7 7 7 7 7 7 9.8.8.8.8.8.8.8.8.8.0.7 7 7 7 7 7 9.8.8.8.8.8.8.8.8.8.8.8.8.8.8.9.7 7 7 7 7 7 0.8.8.8.8.8.8.8.8.8.8.8.8.8.9.7 7 7 7 7 7 0.8.8.8.8.8.8.8.5.7 7 7 7 7 7 a.8.8.8.8.8.8.8.8.8.8.8.8.8.8.a.7 7 7 7 7 7 5.8.8.8.8.8.8.8.9.7 7 7 7 7 7 0.8.8.8.8.8.8.8.8.8.8.8.9.7 7 7 7 7 7 0.8.8.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.` 7 7 7 7 7 7 9.8.8.8.8.8.8.8.8.8.0.7 7 7 7 7 7 9.8.8.8.8.8.8.8.8.8.8.8.8.8.8.a.7 7 7 7 7 7 5.8.8.8.8.8.8.8.8.8.8.8.8.8.9.7 7 7 7 7 7 0.8.8.8.8.8.8.8.0.7 7 7 7 7 7 9.8.8.8.8.8.8.8.8.8.8.8.8.8.8.9.7 7 7 7 7 7 0.8.8.8.8.8.8.8.9.7 7 7 7 7 7 0.8.8.8.8.8.8.8.8.8.8.8.9.7 7 7 7 7 7 0.8.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.` 7 7 7 7 7 7 9.b.b.b.b.b.b.b.b.b.c.7 7 7 7 7 7 9.b.b.b.b.b.b.b.b.b.b.b.b.b.b.6.7 7 7 7 7 7 d.b.b.b.b.b.b.b.b.b.b.b.b.b.9.7 7 7 7 7 7 c.b.b.b.b.b.b.b.7 7 7 7 7 7 7 e.b.b.b.b.b.b.b.b.b.b.b.b.b.b.d.7 7 7 7 7 7 7 b.b.b.b.b.b.b.9.7 7 7 7 7 7 c.b.b.b.b.b.b.b.b.b.b.b.9.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.` 7 7 7 7 7 7 g.f.f.f.f.f.f.f.f.f.c.7 7 7 7 7 7 g.f.f.f.f.f.f.f.f.f.f.f.f.f.f.7 7 7 7 7 7 7 f.f.f.f.f.f.f.f.f.f.f.f.f.f.g.7 7 7 7 7 7 c.f.f.f.f.f.f.h.7 7 7 7 7 7 7 f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.7 7 7 7 7 7 7 h.f.f.f.f.f.f.g.7 7 7 7 7 7 c.f.f.f.f.f.f.f.f.f.f.f.g.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.i.i.i.i.i.i.i.i.c.7 7 7 7 7 7 j.i.i.i.i.i.i.i.i.i.i.i.i.i.j.7 7 7 7 7 7 7 i.i.i.i.i.i.i.i.i.i.i.i.i.i.j.7 7 7 7 7 7 c.i.i.i.i.i.i.j.7 7 7 7 7 7 7 i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.7 7 7 7 7 7 7 j.i.i.i.i.i.i.j.7 7 7 7 7 7 c.i.i.i.i.i.i.i.i.i.i.i.j.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z C V V $.=.Y 7 7 7 7 7 7 g.i.k.k.k.k.k.k.k.k.c.7 7 7 7 7 7 l.k.k.k.k.k.k.k.k.k.k.k.k.k.l.7 7 7 7 7 7 m.k.k.k.k.k.k.k.k.k.k.k.k.k.k.l.7 7 7 7 7 7 c.k.k.k.k.k.k.n.7 7 7 7 7 7 m.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.m.7 7 7 7 7 7 l.k.k.k.k.k.k.l.7 7 7 7 7 7 c.k.k.k.k.k.k.k.k.k.k.k.l.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s o.p.u q.7 7 7 7 7 7 7 7 7 7 7 7 7 g.i.k.k.k.k.k.k.k.k.c.7 7 7 7 7 7 l.k.k.k.k.k.k.k.k.k.k.k.k.k.n.7 7 7 7 7 7 c.k.k.k.k.k.k.k.k.k.k.k.k.k.k.l.7 7 7 7 7 7 c.k.k.k.k.k.k.c.7 7 7 7 7 7 c.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.c.7 7 7 7 7 7 c.k.k.k.k.k.k.l.7 7 7 7 7 7 c.k.k.k.k.k.k.k.k.k.k.k.l.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r.H 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 g.i.k.k.s.s.s.s.s.s.t.7 7 7 7 7 7 u.s.s.s.s.s.s.s.s.s.s.s.s.s.t.7 7 7 7 7 7 t.s.s.s.s.s.s.s.s.s.s.s.s.s.s.u.7 7 7 7 7 7 t.s.s.s.s.s.s.t.7 7 7 7 7 7 t.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.t.7 7 7 7 7 7 t.s.s.s.s.s.s.u.7 7 7 7 7 7 t.s.s.s.s.s.s.s.s.s.s.s.u.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k p 7 7 7 7 7 7 I M T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.v.v.v.t.7 7 7 7 7 7 w.v.v.v.v.v.v.v.v.v.v.v.v.v.t.7 7 7 7 7 7 t.v.v.v.v.v.v.v.v.v.v.v.v.v.v.w.7 7 7 7 7 7 t.v.v.v.v.v.v.t.7 7 7 7 7 7 t.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.t.7 7 7 7 7 7 t.v.v.v.v.v.v.w.7 7 7 7 7 7 t.v.v.v.v.v.v.v.v.v.v.v.w.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i E R 7 7 7 7 7 q.C z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.v.v.v.t.7 7 7 7 7 7 w.v.v.v.v.v.v.v.v.v.v.v.v.v.t.7 7 7 7 7 7 t.v.v.v.v.v.v.v.v.v.v.v.v.v.v.w.7 7 7 7 7 7 t.v.v.v.v.v.v.t.7 7 7 7 7 7 t.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.t.7 7 7 7 7 7 t.v.v.v.v.v.v.w.7 7 7 7 7 7 t.v.v.v.v.v.v.v.v.v.v.v.w.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i R 7 7 7 7 7 q.x.z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.y.y.t.7 7 7 7 7 7 z.y.y.y.y.y.y.y.y.y.y.y.y.y.t.7 7 7 7 7 7 t.y.y.y.y.y.y.y.y.y.y.y.y.y.y.z.7 7 7 7 7 7 t.y.y.y.y.y.y.t.7 7 7 7 7 7 t.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.t.7 7 7 7 7 7 t.y.y.y.y.y.y.z.7 7 7 7 7 7 t.y.y.y.y.y.y.y.y.y.y.y.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g J 7 7 7 7 7 7 A.x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 z.B.B.B.B.B.B.B.B.B.B.B.B.B.C.7 7 7 7 7 7 C.B.B.B.B.B.B.B.B.B.B.B.B.B.B.z.7 7 7 7 7 7 C.B.B.B.B.B.B.C.7 7 7 7 7 7 C.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.C.7 7 7 7 7 7 C.B.B.B.B.B.B.z.7 7 7 7 7 7 C.B.B.B.B.B.B.B.B.B.B.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e ].7 7 7 7 7 7 H v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 z.B.B.B.B.B.B.B.B.B.B.B.B.B.C.7 7 7 7 7 7 C.B.B.B.B.B.B.B.B.B.B.B.B.B.B.z.7 7 7 7 7 7 C.B.B.B.B.B.B.D.7 7 7 7 7 7 C.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.C.7 7 7 7 7 7 D.B.B.B.B.B.B.z.7 7 7 7 7 7 C.B.B.B.B.B.B.B.B.B.E.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e J 7 7 7 7 7 7 G v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 F.E.E.E.E.E.E.E.E.E.E.E.E.E.C.7 7 7 7 7 7 G.E.E.E.E.E.E.E.E.E.E.E.E.E.E.F.7 7 7 7 7 7 C.E.E.E.E.E.E.F.7 7 7 7 7 7 C.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.G.7 7 7 7 7 7 F.E.E.E.E.E.E.F.7 7 7 7 7 7 C.E.E.E.E.E.E.E.E.E.E.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e ,.7 7 7 7 7 7 t v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 F.E.E.E.E.E.E.E.E.E.E.E.E.E.H.7 7 7 7 7 7 7 E.E.E.E.E.E.E.E.E.E.E.E.E.E.F.7 7 7 7 7 7 C.E.E.E.E.E.E.F.7 7 7 7 7 7 G.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.7 7 7 7 7 7 7 F.E.E.E.E.E.E.F.7 7 7 7 7 7 C.E.E.E.E.E.E.E.I.E.E.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e 7 7 7 7 7 7 7 s v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 J.I.I.I.I.I.I.I.I.I.I.I.I.I.J.7 7 7 7 7 7 7 I.I.I.I.I.I.I.I.I.I.I.I.I.I.J.7 7 7 7 7 7 C.I.I.I.I.I.I.K.7 7 7 7 7 7 7 I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.7 7 7 7 7 7 7 K.I.I.I.I.I.I.J.7 7 7 7 7 7 C.I.I.I.I.I.I.I.I.E.E.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c L.7 7 7 7 7 7 7 s v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 J.I.I.I.I.I.I.I.I.I.I.I.I.I.J.7 7 7 7 7 7 7 M.I.I.I.I.I.I.I.I.I.I.I.I.I.J.7 7 7 7 7 7 C.I.I.I.I.I.I.I.G.7 7 7 7 7 7 I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.J.7 7 7 7 7 7 G.I.I.I.I.I.I.I.J.7 7 7 7 7 7 C.I.I.I.I.I.N.I.I.E.E.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c d 7 7 7 7 7 7 7 s v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 J.N.N.N.N.N.N.N.N.N.N.N.N.N.N.7 7 7 7 7 7 7 J.N.N.N.N.N.N.N.N.N.N.N.N.N.J.7 7 7 7 7 7 O.N.N.N.N.N.N.N.O.7 7 7 7 7 7 J.N.N.N.N.N.N.N.N.N.N.N.N.N.N.J.7 7 7 7 7 7 O.N.N.N.N.N.N.N.J.7 7 7 7 7 7 O.N.N.N.N.N.N.I.I.E.E.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c d 7 7 7 7 7 7 7 s v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 J.N.N.N.N.N.N.N.N.N.N.N.N.N.N.P.7 7 7 7 7 7 O.N.N.N.N.N.N.N.N.N.N.N.N.N.J.7 7 7 7 7 7 O.N.N.N.N.N.N.N.J.7 7 7 7 7 7 Q.N.N.N.N.N.N.N.N.N.N.N.N.N.N.O.7 7 7 7 7 7 J.N.N.N.N.N.N.N.J.7 7 7 7 7 7 O.N.N.N.R.N.N.I.I.E.E.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c d 7 7 7 7 7 7 7 s v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 S.R.R.R.R.R.R.R.R.R.R.R.R.R.R.T.7 7 7 7 7 7 7 R.R.R.R.R.R.R.R.R.R.R.R.R.Q.7 7 7 7 7 7 O.R.R.R.R.R.R.R.R.U.7 7 7 7 7 O.R.R.R.R.R.R.R.R.R.R.R.R.R.R.U.7 7 7 7 7 7 R.R.R.R.R.R.R.R.S.7 7 7 7 7 7 O.R.R.V.R.N.N.I.I.E.E.B.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c d 7 7 7 7 7 7 7 t v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 W.V.V.V.V.V.V.V.V.V.V.V.V.V.V.X.7 7 7 7 7 7 7 W.V.V.V.V.V.V.V.V.V.V.V.W.7 7 7 7 7 7 7 O.V.V.V.V.V.V.V.V.T.7 7 7 7 7 7 V.V.V.V.V.V.V.V.V.V.V.V.V.X.7 7 7 7 7 7 T.V.V.V.V.V.V.V.V.X.7 7 7 7 7 7 U.V.V.V.R.N.N.I.I.E.E.Y.G.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e 7 7 7 7 7 7 7 *.v x z z N T Z +.&.` 7 7 7 7 7 7 g.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 W.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.U.7 7 7 7 7 7 Z.V.V.V.V.V.V.V.V.V.V.W.7 7 7 7 7 7 7 7 O.V.V.V.V.V.V.V.V.`.U.7 7 7 7 7 W.V.V.V.V.V.V.V.V.V.V.V.V.T.7 7 7 7 7 7 `.V.V.V.V.V.V.V.V.V.7 7 7 7 7 7 7 +V.V.R.N.N.I.I.E..+G.7 7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e R 7 7 7 7 7 7 R v x z z N T Z +.-.O 7 7 7 7 7 7 ++i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 W.V. + + + + + + + + + + + + + +@+7 7 7 7 7 7 7 @+ + + + + + + + +W.7 7 #+7 7 7 7 7 7 #+ + + + + + + + + +@+7 7 7 7 7 Z. + + + + + + + + + + +$+7 7 7 7 7 7 @+ + + + + + + + + + +7 7 7 7 7 7 7 W.V.V.R.N.N.I.I.F.G.7 C.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e J 7 7 7 7 7 7 7 u x z z N T Z @.O 7 ` 7 7 7 7 7 c.i.k.k.s.v.v.y.B.B.C.7 7 7 7 7 7 W.V. + + + + + + + + + + + + + + +U.7 7 7 7 7 7 7 @+ + + + + +$+#+7 7 #+W.7 7 7 7 7 7 #+ + + + + + + + + + +Z.7 7 7 7 7 %+ + + + + + + + + + +&+7 7 7 7 7 Z. + + + + + + + + + + +#+7 7 7 7 7 7 U.V.V.R.N.N.K.*+7 7 C.z.7 7 7 7 7 7 c.f.b.8.8.3.<.{.;.&.+.` 7 7 7 7 7 7 t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e ].7 7 7 7 7 7 7 7 u D z N U =+7 7 O ^.}.7 7 7 7 1.i.k.k.s.v.v.y.B.B.7 7 7 7 7 7 7 O.V. + +-+-+-+-+-+-+-+-+-+-+-+-+-+;+7 7 7 7 7 7 7 7 Z.>+,+,+'+7 7 7 U.)+,+7 7 7 7 7 7 7 -+-+-+-+-+-+-+-+-+-+)+U.7 7 7 7 U.)+-+-+-+-+-+-+-+-+,+7 7 7 7 7 U.)+-+-+-+-+-+-+-+-+-+-+-+>+7 7 7 7 7 7 7 U.!+S.J.O.7 7 7 ~+B.z.7 7 7 7 7 7 7 f.b.8.8.3.<.{.;.&.+.7 7 7 7 7 7 7 u s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g J 7 7 7 7 7 7 7 7 7 7 7 7 7 7 O ).{.(.7 7 7 7 7 j.k.k.{+v.v.y.Y.C.7 7 7 7 7 7 7 7 !+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+&+7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 )+-+,+7 7 7 7 7 7 7 '+)+-+-+-+-+-+-+-+-+-+)+U.7 7 7 7 U.)+-+-+-+-+-+-+,+7 7 7 7 7 U.)+-+-+-+-+-+-+-+-+-+-+-+-+)+7 7 7 7 7 7 7 7 7 7 7 7 7 7 G..+B.z.7 7 7 7 7 7 7 c.e.8.8.3.<.{.;.-.` 7 7 7 7 7 7 7 7 G q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i f 7 7 7 7 7 7 7 7 7 7 7 7 O -.;.{.<.6.7 7 7 7 7 7 7 ]+v.7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 '+-+-+-+-+-+-+-+-+-+-+-+-+-+-+'+7 7 7 7 7 7 7 7 7 7 7 7 U.,+-+-+,+7 7 7 7 7 7 7 7 7 7 7 -+-+-+-+-+-+-+-+)+Z.7 7 7 7 7 &+;+-+-+;+&+7 7 7 7 7 Z.)+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&+7 7 7 7 7 7 7 7 7 7 7 7 P..+E.B.z.7 7 7 7 7 7 7 7 7 7 7 3.<.7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 l i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i l 7 7 7 7 7 7 7 7 7 7 Y ..&.;.{.<.^+7 7 7 7 7 7 7 t.v.7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 '+-+-+/+/+/+/+/+/+/+/+/+/+/+/+/+(+7 7 7 7 7 7 7 7 7 7 U._+/+/+/+:+7 7 7 7 7 7 7 7 7 7 7 /+/+/+/+/+/+/+/+/+/+(+7 7 7 7 7 7 7 7 7 7 7 7 7 U.(+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+'+7 7 7 7 7 7 7 7 7 7 *+I.E.E.B.z.7 7 7 7 7 7 7 7 7 7 7 3.<.7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 l i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k <+>.7 7 7 7 7 7 H U Z +.&.;.{.<.3.[+6.7 7 7 7 m.u.v.w.z.z.z.F.F.J.J.J.J.S.W.W.W.W.;+-+-+/+/+/+/+/+/+/+/+/+/+/+/+/+/+_+}+7 7 7 7 7 7 Z.(+/+/+/+/+/+_+:+:+:+:+:+:+:+:+:+:+:+/+/+/+/+/+/+/+/+/+/+/+/+(+Z.7 7 7 7 7 7 7 7 '+:+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+|+/+/+>+U.7 7 7 7 7 7 1+2+I.I.E.E.B.Y.z.w.w.u.l.l.j.g.9.9.9.3.<.(.'.=.$.V V M y y y w t t r o 3+i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s t w y y z N T Z +.&.;.{.<.3.8.8.d.g.j.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+4+5+5+5+6+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+4+5+5+5+5+6+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+/+/+-+-+)+W.W.W.X.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+7+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+9+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+a+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+7 7 7 7 7 f+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.C.7 7 7 7 u.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i E j o r t t w y y y M V V @.&.;.{.<.3.8.8.b.f.i.k.k.u.w.w.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+g+g+h+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+i+j+7 7 f+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+k+l+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.Y.6.7 7 u.k.k.i.f.d.9.9.7.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i S l >.7 7 7 7 u A A O 7 7 7 7 Y (.<.3.8.8.b.f.i.k.k.7 7 7 y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7 7 7 8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+m+7 7 f+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+i+7 n+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n *.7 7 7 x z z N T U %.O 7 7 1.7.8.8.b.f.i.k.k.7 7 7 y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7 7 7 8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+m+7 7 f+e+e+e+e+e+e+e+e+e+e+e+e+e+e+o+e+e+e+e+e+k+7 7 l+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.-.` 7 7 6.p+8.b.f.i.k.k.t.t.t.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+q+q+q+8+9+9+9+0+r+j+7 b+b+b+c+c+c+d+e+e+e+e+e+e+o+o+o+o+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+e+7 7 7 j+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.t.7 7 u.k.k.i.f.++0.0.^+<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.` 7 7 6.p+b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+7 7 7 b+b+b+c+c+c+d+e+e+e+e+e+e+o+o+o+o+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+t+7 7 7 7 u+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.t.7 7 u.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.^.7 7 7 a.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+7 7 7 b+b+b+c+c+c+d+e+e+e+e+e+e+o+o+o+o+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+j+k+n+7 7 k+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.t.7 7 u.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.~.7 7 7 e.f.v+l.l.u.w.w.y.B.B.E.E.I.I.w+Q.O.O.T.%+ +,+,+,+:+_+6+5+g+g+g+h+8+9+9+x+y+7 7 7 z+z+z+u+c+c+d+e+A+t+m+m+m+B+C+o+o+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+A+7 i+k+7 7 7 D+b+b+a+a+0+0+9+x+h+h+h+g+E+7+|+|+:+:+,+,+,+ + +V.V.R.N.N.K.J.C.C.C.F+m.7 7 u.k.k.j.g.9.9.9.7.<.{.;.&.+.Z T C B A u u t s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.|.7 7 7 ++f.G+c.6.7 7 7 y.B.B.E.E.I.J.7 7 Q.W.O.7 7 Z.7 7 7 _+4+q+n+7 7 7 8+9+9+H+7 7 7 7 7 7 7 m+c+c+I+n+7 n+m+m+n+7 n+J+o+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+m+m+e+K+7 7 7 L+b+b+a+a+0+0+9+M+N+7 7 7 g+7+|+|+'+U.7 7 7 + +V.V.R.N.Q.7 7 7 C.C.C.7 7 7 u.k.k.c.1.7 7 7 4.<.{.;.&.+.Z O+7 7 B y u 7 R r.m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.<.7 7 7 c.f.i.k.P+7 7 7 y.B.B.E.E.J.7 7 Q.R.V.V.Z.7 '+-+)+Q+/+|+|+E+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+c+m+7 n+i+e+e+i+7 7 n+o+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+i+7 A+e+d+m+7 7 n+b+b+a+a+0+0+9+9+9+N+7 7 g+7+|+|+/+_+7 7 7 + +V.V.R.1+7 7 G..+E.B.B.t.7 7 u.k.k.i.f.1.7 7 4.<.{.;.&.+.` 7 7 D z x v u 7 7 o k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.<.1.7 7 6.f.i.k.k.7 7 7 y.B.B.E.E.G.7 7 N.R.V.V.W.7 7 ;+-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+c+m+7 m+e+e+e+e+j+7 7 C+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+k+j+e+e+d+u+7 7 7 R+b+a+a+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.V.S+7 7 G.K.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.&.$.7 7 O+z z x v s 7 7 R k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.<.}.7 7 7 f.i.k.k.7 7 7 y.B.B.E..+7 7 O.N.R.V.V.$+7 7 '+-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+c+A+f+A+e+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+n+t+e+e+d+c+n+7 7 j+b+a+a+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.V.P.7 7 T+I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.&.O 7 7 U+z z x v s u 7 7 V+i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.<.}.7 7 7 f.i.k.k.7 7 7 y.B.B.E.F.7 7 O.N.R.V.V. +7 7 7 -+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+c+d+e+e+e+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+f+n+e+e+e+d+c+l+7 7 7 D+a+a+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.`.7 7 7 K.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.W+7 7 7 N z z x v s t 7 7 R i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.<.}.7 7 7 f.i.k.k.7 7 7 y.B.B.E.F.7 7 O.N.R.V.V. +7 7 7 -+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+c+d+e+e+e+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+j+k+e+e+e+d+c+c+7 7 7 X+a+a+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.W.7 7 G.I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.=.7 7 Y N z z x v s [.7 7 7 i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.<.}.7 7 7 f.i.k.k.7 7 7 y.B.B.E.F.7 7 O.N.R.V.V. +7 7 U.-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+c+d+e+e+e+f+f+f+j+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+A+7 i+e+e+e+d+c+c+k+7 7 n+a+a+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.T.7 7 O.I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.` 7 7 P N z z x v s s 7 7 7 j i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.<.1.7 7 1.f.i.k.k.7 7 7 y.B.B.E.E.7 7 P.N.R.V.V.%+7 7 '+-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+c+d+f+j+7 n+m+m+n+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+k+j+e+e+e+e+d+c+c+u+7 7 7 y+a+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.O.7 7 O.I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.` 7 7 P N z z x v s s 7 7 7 j i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.<.7 7 7 Y+f.i.k.k.7 7 7 y.B.B.E.E.*+7 7 w+R.V.V.@+7 7 )+-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+c+m+7 7 m+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+7 j+m+m+m+m+m+m+m+m+7 7 7 j+a+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.O.7 7 O.I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.` 7 7 P N z z x v s s 7 7 7 j i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.|.7 7 7 9.f.i.k.k.7 7 7 y.B.B.E.E.I.C.7 O.R.V.`.U.7 ,+-+-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+z+7 7 j+e+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+B+n+m+m+m+m+m+m+m+m+m+j+7 7 7 Z+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.O.7 7 O.I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.` 7 7 P N z z x v s s 7 7 7 j i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.:.7 7 6.b.f.i.k.k.7 7 7 y.B.B.E.E.I.I.Q.7 P.O.U.U.W.-+-+-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+j+7 7 t+e+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+o+n+t+e+e+e+e+e+d+c+c+c+b+n+7 7 X+0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.O.7 7 O.I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.#.7 7 P N z z x v s o.7 7 7 E i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.{.6.7 7 5.b.f.i.k.k.7 7 7 y.B.B.E.E.I.K.G.O.S+W.W. + +-+-+-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+7 7 7 f+e+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+J+7 e+e+e+e+e+e+d+c+c+c+b+L+7 7 7 0+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.W.7 7 7 I.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.=.7 7 O N z z x v s t 7 7 7 i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.;.~.7 7 1.8.b.f.i.k.k.7 7 7 y.B.B.E.E.K.G.7 w+R.V.V. + +-+-+-+/+/+|+|+7+7 7 7 8+9+9+9+0+7 7 7 b+b+b+c+c+7 7 7 f+e+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+o+j+`+e+e+e+e+e+e+d+c+c+c+b+D+7 7 7 L+0+9+9+9+q+7 7 g+7+|+|+/+/+7 7 7 + +V.X.7 7 7 K.I.E.E.B.B.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.&.7 7 7 N z z x v s *.7 7 l i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n r 7 7 7 x z z N T Z +.&.'.7 7 6.p+8.b.f.i.k.k.7 7 7 y.B.B.E.E.C.7 7 J.R.V.V. + +-+-+-+/+/+|+|+7+7 7 7 8+9+9+9+0+n+7 7 b+b+b+c+c+7 7 7 k+e+e+e+e+m+7 7 s+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+C+7 C+e+e+e+e+e+e+d+c+c+c+b+b+ @7 7 n+0+9+9+9+q+7 7 .@7+|+|+/+'+7 7 7 + +V.V.U.7 7 *+I.E.E.B.z.7 7 7 u.k.k.i.f.c.7 7 4.<.{.;.&.%.7 7 M z z x v s R 7 7 3+i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n +@7 7 7 @@z z N T Z +.#.7 7 1.7.8.8.b.f.i.k.k.7 7 7 y.B.B.E.E.*+7 7 7 7 7 7 7 7 '+>+-+/+/+|+|+7+7 7 7 8+9+9+9+0+H+7 7 D+b+b+c+c+k+7 7 7 f+e+i+t+n+7 7 B+o+o+o+o+m+7 7 s+o+o+o+o+o+o+o+o+o+o+o+o+`+j+o+e+e+e+e+e+e+d+c+c+c+b+b+z+7 7 7 L+9+9+9+h+7 7 n+E+|+5+U.}+7 7 7 + +V.V.Q.7 7 7 T+E..+D.G.t.7 7 u.k.k.i.f.c.7 7 4.<.{.;.&.+.O 7 H z z x v t 7 7 #@k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i E j $@R 7 7 7 q.B y M V ` 7 7 O :.<.3.8.8.b.f.v+l.Y+7 7 7 %@z.Y.E.E.K.P.7 7 7 7 7 7 7 7 7 U./+/+6+5+&@7 7 7 &@h+*@9+0+Z+7 7 @z+L+c+c+=@n+7 7 7 7 7 n+C+`+7 n+s+C+s+B+n+7 7 j+s+J+o+o+o+o+o+o+o+o+J+B+7 n+s+i+e+e+e+e+e+d+c+c+c+D+z+ @7 7 7 7 M+*@9+8+n+7 7 7 7 7 '+/+7 7 7 #+W.V.V.R.O.7 7 7 7 7 G.Y.t.7 7 6.l.P+j.++6.7 7 1.(._.;.&.+. .O 7 A C x w R 7 p m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i S l p p u u u u A A P P ` $.W+;.{.<.3.8.8.b.f.G+c.c.t.t.t.t.C.-@E.E.K.P.O.J.S.W.W.W.Z.7 7 7 (+/+4+q+q+q+q+q+q+H+x+9+0+0+y+j+7 7 j+c+c+c+K+m+7 7 n+k+i+o+C+j+7 n+J+m+m+m+m+m+m+m+B+o+o+o+o+o+o+o+o+B+m+m+m+m+A+e+e+e+e+e+d+c+c+c+R+ @ @ @ @H+H+H+x+9+8+;@>@7 7 >@5+/+/+'+'+'+#+#+V.V.R.N.Q.G.7 7 *+Y.B.F+t.t.t.c.,@c.c.c.0.0.}.}.:.;.&.+.Z T '@H 7 7 7 u [.q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.F.7 7 N.N.R.V.V. + +'+7 7 '+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B..+7 7 C.N.N.R.V.V. + +,+7 7 '+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.F.7 7 C.N.N.R.V.V. + +>+7 7 :+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.M.7 7 7 w+N.R.V.V. + +U.7 U./+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.C.7 7 O.w+R.V.V.$+Z.7 Z.)+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.T+G.7 7 O.O.Z.7 Z.>+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+d+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+m+7 7 7 7 f+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+e+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z y M V V $.=.'.(.2.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.F.J.J.J.J.S.`.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+K+n+7 7 I+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+d+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+_+:+,+;+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z A P 7 7 7 7 ` ` |.3.8.8.b.f.i.c.c.s.v.v.y.B.B.E.C.C.G.7 P.O.X.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+m+7 7 z+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+:+7 7 '+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N P 7 7 ` ;.{.<.3.8.8.b.f.i.7 7 s.v.v.y.B.B.E.E.I.J.P.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+c+c+c+m+7 7 z+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+b+b+b+a+a+0+0+9+9+9+8+8+7+7+7+|+|+:+7 7 '+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N W 7 7 Y ;.{.<.3.8.8.b.f.j.7 7 u.v.v.y.B.B.E.E.I.C.1+N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+c+c+c+c+m+7 7 z+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+c+z+m+7 z+c+c+c+c+c+c+c+c+c+c+c+c+b+b+b+a+a+0+0+*@H+n+q+8+7+7+7+|+|+Q+'+'+>+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N X 7 7 7 ;.{.<.3.8.8.b.f.c.7 7 ]+v.v.y.B.B.E.E.I.7 2+N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+b+b+b+ @7 7 z+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+ @7 7 z+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+a+a+0+0+h+7 7 q+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T O 7 7 '.{.<.3.8.8.b.f.7 7 7 6.v.v.y.B.B.E.E.M.G.N.N.R.V.V. + +-+-+-+/+/+|+|+7+7+7+8+8+9+9+9+0+0+a+a+b+b+b+b+b+b+ @7 7 z+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+ @7 7 z+b+b+b+b+b+b+b+b+b+b+b+b+b+b+b+a+a+0+0+h+7 7 q+8+7+7+7+|+|+/+/+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T =+7 7 ` {.<.3.8.8.b.g.7 6.7 7 )@v.y.B.B.E.E.*+*+N.N.R.V.V. + +-+)+>+'+'+q+5+7+7+7+8+8+*@h+h+y+y+Z+b+b+L+ @L+b+b+ @7 7 z+b+b+b+R+z+z+z+z+R+b+b+b+b+D+L+ @ @ @z+D+b+b+D+z+j+7 7 X+z+z+z+b+b+b+b+D+z+ @ @ @X+R+b+a+a+0+y+r+7 7 N+h+g+g+E+4+5+:+:+,+;+-+ + +V.V.R.N.N.J.C.C.C.F+Y.y.v.v.s.k.l.j.g.9.9.8.3.<.:.` ` #.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T V 7 7 O {.<.3.8.8.b.c.c.Y+7 7 !@v.y.B.B.E.E.G.M.N.N.R.V.V. + +&+7 7 (+:+q+7 n+~@7+8+8+x+H+7 7 7 @D+n+7 7 @a+a+ @7 7 y+a+a+a+L+ @7 7 @L+a+a+a+y+7 7 X+y+X+7 7 Z+a+y+7 7 7 7 7 7 7 7 a+a+D+j+7 7 @ @j+7 7 L+a+a+0+7 7 7 7 7 7 7 7 g+(+q+7 7 7 '+-+ + +V.V.R.J.G.7 C.F.H.7 7 F+v.v.s.k.c.6.7 7 7 8.4.6.7 7 7 7 ` T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z 7 7 7 ^.<.3.8.8.b.7 j.l.7 7 t.v.y.B.B.E.M.7 I.N.N.R.V.V. +#+7 7 ;+/+/+|+q+7 7 g+8+8+9+9+M+7 7 @j+7 7 7 @a+a+ @7 7 y+a+a+a+a+y+7 y+a+a+a+a+Z+7 7 X+a+a+a+X+7 y+a+a+a+ @7 7 y+a+a+a+a+a+y+7 7 y+a+a+a+j+7 7 Z+a+0+0+h+7 7 q+8+7+7+7+|+|+(+7 7 '+-+ + +V.V.S.7 7 *+I.E.E.z.7 7 t.v.s.k.k.v+7 7 7 9.7 }.(.!.7 7 7 U N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z Y 7 7 :.<.3.8.8.9.7 i.k.7 7 7 v.y.B.B.E.*+C.I.N.N.R.V.V.W.7 7 &+-+/+/+|+|+7 7 n+8+8+9+9+h+7 7 7 n+Z+{@7 H+0+0+H+7 7 y+0+0+0+{@n+L+0+0+0+0+0+r+7 7 y+0+0+0+y+7 y+0+0+0+H+7 7 y+0+0+0+0+0+y+7 7 0+0+0+0+L+7 7 L+0+0+0+h+7 7 q+8+7+7+7+|+|+:+7 7 '+-+ + +V.`.U.7 G.I.I.E.E.B.C.7 7 ]@s.k.k.i.7 7 7 1.^+<.{.;.` 7 7 O+N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z #.7 7 ` <.3.8.8.c.c.i.k.c.7 7 w.y.B.B.E.G.J.I.N.N.R.V.V.U.7 7 ;+-+/+/+|+|+q+7 7 ^@8+9+9+y+7 7 n+{@0+0+j+H+0+0+H+7 7 y+0+0+0+j+H+0+0+0+0+0+0+H+7 7 y+0+0+0+y+7 y+0+0+0+H+7 7 y+0+0+0+0+0+{@y+y+0+0+0+0+y+7 7 H+0+0+0+h+7 7 q+8+7+7+7+|+|+:+7 7 '+-+ + +V.T.7 7 1+I.I.E.E.B.z.7 7 m.s.k.k.i.7 7 7 p+3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z @.7 7 7 <.3.8.8.7 g.i.k.n.7 7 ]+y.B.B..+7 I.I.N.N.R.V.X.7 7 7 -+-+/+/+|+|+g+7 7 n+8+9+9+h+7 7 H+9+9+9+9+9+9+9+H+7 7 h+9+9+H+n+*@9+9+9+9+9+9+H+7 7 N+9+9+9+9+9+9+9+9+9+H+7 7 h+9+9+9+9+9+9+9+9+9+9+9+9+h+7 7 H+9+9+9+h+7 7 q+8+7+7+7+|+|+:+7 7 '+-+ + +V.U.7 7 J.I.I.E.E.B.B.7 7 7 ]@k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.7 7 7 (.3.8.9.7 f.i.k.P+7 7 6.y.B.B.H.C.I.I.N.N.R.V.W.7 7 Z.-+-+/+/+|+|+~@7 7 7 8+9+9+h+7 7 H+9+9+9+9+9+9+9+H+7 7 h+9+h+7 x+9+9+9+9+9+9+9+M+7 7 7 H+9+9+9+9+9+9+9+9+H+7 7 h+9+9+9+9+9+9+9+9+9+9+9+9+h+7 7 H+9+9+9+h+7 7 q+8+7+7+7+|+|+:+7 7 '+-+ + +V.7 7 7 w+I.I.E.E.B.B.6.7 7 u.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.` 7 7 ~.3.8.0.c.f.i.k.k.6.7 7 /@B.B.~+F.I.I.N.N.R.V.O.7 7 '+-+-+/+/+|+|+7+7 7 7 h+9+9+h+7 7 H+9+9+9+9+9+9+9+H+7 7 h+*@7 M+9+9+9+9+9+9+9+9+9+n+7 7 7 n+h+9+9+9+9+9+9+H+7 7 h+9+9+9+9+9+9+9+9+9+x+h+h+r+7 7 H+9+9+9+h+7 7 q+8+7+7+7+|+|+:+7 7 '+-+ + +W.7 7 7 N.I.I.E.E.B.B.t.7 7 t.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.=.7 7 1.3.8.7 9.f.i.k.k.t.7 7 F+B.Y.7 .+I.I.N.N.R.V.O.7 7 '+-+-+/+/+|+|+7+7 7 7 h+8+8+h+7 7 q+8+8+8+8+8+8+8+q+7 7 &@n+7 n+8+8+8+8+8+8+8+8+8+(@N+7 7 7 7 q+(@8+8+8+8+q+7 7 h+8+8+8+8+8+8+(@q+7 7 q+q+N+7 7 q+8+8+8+h+7 7 q+8+7+7+7+|+|+:+7 7 '+-+ + +W.7 7 7 N.I.I.E.E.B.B.t.7 7 t.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.-.7 7 7 7.9.7 b.f.i.k.k.u.7 7 t.B.F+~+E.I.I.N.N.R.V.O.7 7 '+-+-+/+/+|+|+7+7 7 7 h+8+8+h+7 7 q+8+8+8+8+8+8+8+q+7 7 &@N+7 7 q+8+8+8+8+8+8+8+8+8+8+^@7 7 7 7 n+(@8+8+8+q+7 7 h+8+8+8+8+8+h+7 7 n+(@8+8+h+7 7 q+8+8+8+h+7 7 q+8+7+7+7+|+|+:+7 7 '+-+ + +W.7 7 7 N.I.I.E.E.B.B.t.7 7 t.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.O 7 7 4.0.0.b.f.i.k.k.s.7 7 7 B.~+H.E.I.I.N.N.R.V.O.7 7 '+-+-+/+/+|+|+7+7 7 7 g+7+7+g+7 7 q+7+7+7+7+7+7+7+q+7 7 g+E+7 7 7 g+7+7+7+7+7+7+7+7+7+7+E+>@7 7 7 n+E+7+7+q+7 7 g+7+7+7+7+E+n+7 7 E+7+7+7+g+7 7 q+7+7+7+g+7 7 q+7+7+7+7+|+|+:+7 7 '+-+ + +W.7 7 7 N.I.I.E.E.B.B.t.7 7 t.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.~.7 7 }.7 9.b.f.i.k.k.s.m.7 7 F+7 .+E.I.I.N.N.R.V.!+7 7 '+-+-+/+/+|+|+E+7 7 7 E+7+7+g+7 7 q+7+7+7+7+7+7+7+q+7 7 g+7+.@7 7 n+E+7+7+7+7+7+7+7+7+7+7+7+.@7 7 7 .@7+7+q+7 7 g+7+7+7+7+.@7 7 >@7+7+7+7+g+7 7 q+7+7+7+g+7 7 q+7+7+7+7+|+|+:+7 7 '+-+ + +`.7 7 7 N.I.I.E.E.B.B.m.7 7 !@k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.'.7 7 7 7 8.b.f.i.k.k.s.!@7 7 G.~+E.E.I.I.N.N.R.V.W.7 7 U.-+-+/+/+|+7+g+7 7 7 7+7+7+g+7 7 q+7+7+7+7+7+7+7+q+7 7 g+7+7+q+7 7 q+7+7+7+7+7+7+7+7+7+7+7+7+&@7 7 q+7+7+q+7 7 g+7+7+7+7+q+7 7 q+7+7+7+7+g+7 7 q+7+7+7+g+7 7 q+7+7+7+7+|+|+:+7 7 '+-+ + +V.7 7 7 2+I.I.E.E.B.B.7 7 7 u.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.7 7 7 0.8.b.f.i.k.k.s.]@7 7 7 D.E.E.I.I.N.N.R.V.V.7 7 7 -+-+/+/+|+|+_@7 7 q+|+|+|+5+7 7 q+|+|+|+|+|+|+|+q+7 7 5+|+|+6+n+7 7 (+|+|+|+|+q+7 |+|+|+|+|+5+7 7 q+|+|+q+7 7 5+|+|+|+|+q+7 7 q+|+|+|+|+5+7 7 q+|+|+|+5+7 7 q+|+|+|+|+|+|+:+7 7 '+-+ + +V.O.7 7 J.I.I.E.E.B.-@7 7 7 s.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;./.7 7 5.8.b.f.i.k.k.s.v.6.7 7 -@E.E.I.I.N.N.R.V.V.&+7 7 ,+-+/+|+|+|+n+7 7 4+|+|+|+5+7 7 q+|+|+|+|+|+|+|+q+7 7 5+|+|+|+5+7 7 7 6+|+|+|+q+7 |+|+|+|+|+5+7 7 (+|+|+_@7 7 5+|+|+|+|+q+7 7 n+|+|+|+|+5+7 7 q+|+|+|+4+7 7 q+|+|+|+|+|+|+:+7 7 '+-+ + +V.X.7 7 O.I.I.E.E.B.D.7 7 ]+s.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.:.7 7 p+8.b.f.i.k.k.s.v.t.7 G.B.E.E.I.I.N.N.R.V.V. +U.7 Z.-+/+/+/+:+7 7 }+/+/+/+/+:+7 7 '+/+/+/+/+/+/+/+'+7 7 :+/+/+/+/+'+7 7 U./+/+/+'+7 Q+/+/+/+/+}+7 7 _+/+/+:+7 7 (+/+/+/+/+Q+7 7 7 '+/+/+:+U.U.7 Z./+/+/+/+7 7 Z./+/+/+/+/+/+:+7 7 '+-+ + +V.V.T.7 7 K.I.E.E.Y.G.7 6.v.s.k.k.i.7 7 7 8.3.<.{.;.=.7 7 P N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;._.7 1.8.8.b.f.i.k.k.s.v.w.7 D.B.E.E.I.I.N.N.R.V.V. +$+U.7 '+_+/+:+U.7 '+/+/+/+_+:+U.7 7 7 (+Q+/+/+/+Q+(+7 7 7 U.:+_+/+/+/+U.7 7 Z.:+/+'+7 U.Q+/+/+(+7 7 :+/+/+/+/+U.7 U.:+:+Q+/+/+'+7 7 7 7 7 7 :+Q+7 7 (+Q+/+/+}+7 7 (+:+:+/+Q+:+Z.7 7 U.>+W. +V.V.R.O.7 G.M.E..+~+7 6.)@v.s.k.l.c.7 7 7 0.4.<.^.'.O 7 7 7 '@D z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.7 5.8.8.b.f.i.k.k.s.v.v.7 z.B.E.E.I.I.N.N.R.V.V. + +-+>+Z.7 7 7 '+;+-+-+-+-+;+'+'+'+'+'+'+>+-+-+-+>+'+'+'+'+'+'+;+-+-+-+;+'+'+'+'+-+-+;+'+U.7 7 7 '+;+-+-+-+-+-+)+'+7 7 U.;+-+-+-+&+U.7 7 '+;+-+-+&+7 7 >+-+-+-+&+U.7 7 >+-+>+'+'+'+'+'+'+#+ +V.V.R.N.2+C.7 7 7 ~+F+y.v.v.s.k.c.c.c.c.0.0.}.<._.` ` ` ` P P B z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.R.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.y.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.y.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.s.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.8.8.b.f.i.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.:@<@<@<@[@k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.}@<@<@<@|@k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.|@1@2@3@2@1@k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.k.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.4@<@<@i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.5@6@6@i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.7@<@<@i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.2@<@8@i.6@2@i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.9@<@9@f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.1@<@0@f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.9@<@9@f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.a@<@9@f.f.9@9@f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.b@<@c@b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.a@9@a@b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.d@9@c@b.b.b.b.0@<@c@b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.0@<@e@b.b.c@e@b.b.b.b.b.b.b.b.b.b.b.b.[@c@0@b.b.b.b.b.b.b.b.b.b.b.b.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N T Z +.&.;.{.<.3.<@<@4@8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.2@<@4@8.8.8.8.<@<@4@8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.<@<@f@8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.c@<@9@8.8.8.8.8.8.8.8.8.8.8.8.8.8.3.<.{.;.&.+.Z T N z z x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z N g@h@i@&.;.{.<.f@<@<@j@8.j@4@4@8.8.8.8.8.8.8.4@4@4@8.8.8.8.8.8.8.8.8.j@4@j@8.8.8.8.8.8.8.8.8.8.8.8.8.4@4@j@8.8.8.8.8.8.f@4@f@8.8.8.8.8.8.8.8.8.8.8.8.8.<@<@f@8.8.8.f@<@<@j@8.j@4@4@8.8.8.8.8.8.8.j@4@4@8.8.8.8.8.8.8.8.8.8.8.4@<@<@8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.9@<@c@8.8.8.8.8.8.8.8.8.8.8.8.8.8.3.<.{.;.&.+.i@g@N z z x v k@k@l@m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z m@n@o@h@p@2@;.{.3.q@<@<@3.r@<@<@<@s@3.3.3.t@s@<@s@s@<@2@t@3.t@2@<@<@r@q@<@<@q@s@<@<@<@3.3.u@2@<@<@q@q@2@<@<@2@t@3.3.3.t@b@2@q@s@2@2@<@<@r@3.3.3.3.3.3.s@<@<@<@<@<@s@3.q@<@<@3.r@<@<@<@s@3.3.3.3.t@b@r@q@2@2@u@3.3.3.3.3.3.3.t@<@<@<@<@<@<@q@u@2@<@<@q@3.3.b@<@<@s@3.q@<@<@<@<@<@<@:@<@<@<@3.3.u@2@<@<@q@3.q@<@<@<@v@p@<@<@N z z w@x@k@y@<@z@k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x A@<@B@T Z h@<@;.<.<.s@<@s@s@r@C@s@<@<@<.<.<.r@<@C@<.<.s@<@s@<.<.<.<@<@s@2@b@<@D@<.C@<@b@<.<.<.C@<@<@C@b@C@:@<@<@C@<.<.D@2@<@D@<.D@<@2@<.D@<.<.<.<.<.<.<.<.r@<@2@<.<.<.<.s@<@s@s@r@C@s@<@<@<.<.<.D@2@:@<.<.C@<@b@<.<.<.<.<.<.<.<.<.s@<@s@<.<.<.<.C@<@<@D@<.<.<.<@<@:@<.<.E@<@<@E@<.<.<.s@<@b@<.<.<.C@<@<@D@<.<.C@<@<@p@B@n@B@N z F@x@v s s <@<@G@i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x H@<@g@T Z h@p@{.{.{.b@<@2@I@{.{.J@<@<@{.{.{.K@L@{.{.{.s@<@s@{.{.M@<@<@s@{.J@<@{.{.s@<@s@{.{.{.K@<@<@J@{.{.{.<@<@J@{.{.b@<@L@{.{.{.<@<@M@{.{.{.{.{.{.{.{.{.s@<@s@{.{.{.{.b@<@2@I@{.{.J@<@<@{.{.{.2@2@{.{.{.J@<@<@{.{.{.{.{.{.{.{.{.<@<@K@{.{.{.{.J@<@<@{.{.{.M@<@<@J@{.{.J@<@<@{.{.{.{.s@<@s@{.{.{.L@<@<@{.{.{.L@<@<@N@+.o@o@N w@<@O@v s s <@<@P@i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x <@<@Q@T Z i@R@;.;.;.<@<@N@;.;.;.s@<@s@;.;.;.;.;.;.;.;.<@<@K@;.;.N@<@<@;.;.S@R@;.;.b@<@N@;.;.;.s@<@s@;.;.;.N@<@<@;.;.S@<@<@N@;.;.;.<@<@N@;.;.;.;.;.;.;.;.;.<@<@N@;.;.;.;.<@<@N@;.;.;.s@<@s@;.;.L@<@s@;.;.;.N@<@<@;.;.;.;.;.;.;.;.S@<@<@N@;.;.;.;.s@<@s@;.;.;.N@<@<@;.;.;.s@<@s@;.;.;.;.<@<@N@;.;.;.s@<@s@;.;.;.s@<@s@&.+.i@T@U@<@<@x v s s <@<@P@i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x n@<@n@g@Z &.&.&.&.v@<@<@V@&.&.&.B@<@L@&.&.&.&.&.&.&.V@<@<@N@&.&.p@<@p@&.&.&.&.&.&.<@<@v@&.&.&.2@<@K@&.&.&.K@<@2@&.&.N@<@<@&.&.&.v@<@<@v@&.&.&.&.&.&.&.&.V@<@<@v@&.&.&.v@<@<@V@&.&.&.B@<@L@&.&.<@<@N@&.&.&.p@<@2@&.&.&.&.&.&.&.&.N@<@<@&.&.&.&.&.B@<@L@&.&.&.L@<@2@&.&.&.B@<@L@&.&.&.V@<@<@v@&.&.&.2@<@L@&.&.&.<@<@N@&.+.Z T F@<@F@x v s k@<@<@W@i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x X@<@<@<@Y@+.+.+.+.h@<@<@+.+.+.+.<@<@h@+.+.+.Z@Y@p@p@B@<@<@+.+.+.B@<@`@+.+.+.+.+.i@<@<@+.+.+.+.<@<@h@+.+.+.p@<@p@+.+.h@<@<@+.+.+.Y@<@B@+.+.+.+.+.+.+.+.+.h@<@<@+.+.+.+.h@<@<@+.+.+.+.<@<@h@+.h@<@<@p@p@p@p@p@p@Y@+.+.+.+.+.+.+.+.`@<@B@+.+.+.+.+.<@<@h@+.+.+.p@<@p@+.+.+.<@<@h@+.+.+.h@<@<@+.+.+.+.<@<@h@+.+.Z@<@<@i@+.+.Z T <@<@H@F@y@y@y@ #.#k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z X@<@<@<@o@Z Z Z o@<@o@Z Z Z i@<@<@Z Z Z +#<@n@i@Z @#<@n@Z Z Z <@<@h@Z Z Z Z Z +#<@B@Z Z Z h@<@<@Z Z Z Z n@<@h@Z Z ##<@<@Z Z Z n@<@##Z Z Z Z Z Z Z Z Z @#<@B@Z Z Z Z o@<@o@Z Z Z i@<@<@Z Z @#<@<@Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z o@<@o@Z Z Z Z i@<@<@##Z Z Z <@<@+#Z Z i@<@<@##Z Z Z @#<@B@Z Z Z h@<@<@##Z Z h@<@<@Z Z Z Z i@<@<@m@x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z z g@n@<@<@i@T T B@<@@#T T T g@<@n@T T +#<@n@T@T T B@<@o@T T i@<@<@T@T T T T T o@<@o@T T T +#<@n@T T T T <@<@i@T T T g@<@g@T o@n@g@T T T T T T T T T T B@<@o@T T T T B@<@@#T T T g@<@n@T T o@<@<@T T T T T T T T T T T T T T T <@<@g@T T T T +#<@<@T T T T <@<@g@T T +#<@<@T T T T B@<@o@T T T g@<@<@T T T @#<@B@T T T T g@<@<@m@x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s v x z N N g@<@<@g@N N <@<@g@N N N F@<@F@N N <@<@@#N N N <@<@Q@N N g@<@n@N N N N N N n@<@g@N N N F@<@F@N N N g@<@<@N N N N U@B@@#F@Q@$#N N N N N N N N N N N <@<@g@N N N N <@<@g@N N N F@<@F@N N F@<@<@N N N N N N N N N N N N N N $#<@<@U@N N N N F@<@F@N N N g@<@<@N N N F@<@F@N N N N <@<@g@N N N F@<@F@N N N F@<@@#N N N N g@<@<@m@x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s %#<@z z z z <@<@A@z A@<@<@&#z z z H@<@m@z m@<@<@m@z z A@<@<@m@z z F@<@F@z z z z z &#<@<@m@z z z n@<@X@z z z X@<@F@z z z m@<@&#z z z z z z z z z z z z z z A@<@<@m@z z z A@<@<@&#z z z H@<@m@z z F@<@<@z z z z z z z z z z z z z z m@<@<@z z z z z n@<@X@z z z X@<@n@z z z n@<@F@z z z A@<@<@&#z z z H@<@w@z z z <@<@m@z z z z m@<@<@m@x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s *#F@z z z &#<@n@z z m@<@n@z z z z <@<@A@z m@<@<@m@z z X@<@<@z z z H@<@X@z z z z z m@<@<@z z z z <@<@A@z z z F@<@w@z z z <@<@w@m@m@m@A@z z z z z z z z z z m@<@<@z z z z m@<@n@z z z z <@<@A@z z A@<@<@X@z z z z z z z z z z z z z w@<@H@z z z z z <@<@m@z z X@n@<@F@z z z <@<@m@z z z m@<@<@z z &#w@<@<@m@z z &#<@<@&#z z z z z n@<@H@x v s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s F@x@x x x F@<@O@x x x@<@x@=#x x -#<@<@O@x O@<@<@n@;#w@F@n@<@x x O@<@<@-#x x x x =#F@<@<@O@x x -#<@<@O@x x =#<@<@w@x x x x@<@<@<@<@<@<@n@=#x x x x x x x x ;#<@<@=#=#x x x@<@x@=#x x -#<@<@O@x x x F@<@<@w@;#;#F@w@x x x x x x x =#x@<@x@=#x x x x <@<@n@F@n@;#n@<@x@x x x <@<@-#x =#x ;#<@<@x@F@n@;#<@<@-#x x w@<@<@=#x x x x x ;#<@<@x@%#k@>#x@m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s v ,#>#x@y@x@y@,#v ,#y@y@y@y@y@v >#y@y@y@y@'#v >#<@<@x@%#v *#<@x@*#y@y@y@y@*#v v '#y@y@y@y@y@'#>#y@y@y@y@'#%#y@y@y@y@*#v ,#x@*#%#%#%#>#<@<@y@v v v v v v v v v >#<@<@x@,#y@y@y@y@y@v >#y@y@y@y@'#v v v >#n@<@<@x@*#,#v v v v v v '#y@y@y@y@y@'#v v v %#<@<@x@'#v y@y@y@*#v v %#n@<@n@'#v v y@<@<@>#,#'#y@y@y@'#y@y@y@y@y@'#v v v v v %#x@<@<@n@>#)#m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n q s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s k@<@>#s s s s s y@<@y@s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k n s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s n@<@k@s s s s s x@<@!#s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i k q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q <@<@~#q q q q {#<@ #q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q q m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m z@<@n@]#m ^#z@<@z@m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m m k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k k i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e g i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c e i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b c g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g g e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 b e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 0 c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 8 b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b b 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 2 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 1 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } | 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < [ } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : < } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ : [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( _ < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / ( : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ / _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] ^ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ] / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ { ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! ~ ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ! { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ) ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ' ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > , ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; > ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ; ; - = * & % $ # @ + ",
". + @ # $ % & * = - ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; - = * & % $ # @ + ",
". + @ # $ % & * = ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; - = * & % $ # @ + ",
". + @ # $ % & * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - = * & % $ # @ + ",
". + @ # $ % & = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * & % $ # @ + ",
". + @ # $ % * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * & % $ # @ + ",
". + @ # $ & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & % $ # @ + ",
". + @ # % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % $ # @ + ",
". + @ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ # @ + ",
". + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @ + ",
". @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + ",
"+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "};

498
gtk2_ardour/about.cc Normal file
View File

@@ -0,0 +1,498 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <algorithm>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <gtk--/label.h>
#include <gtk--/text.h>
#include <gtk--/scrolledwindow.h>
#include <gtk--/notebook.h>
#include <ardour/ardour.h>
#include <ardour/version.h>
#include "utils.h"
#include "version.h"
#include <gtkmmext/gtk_ui.h>
#include <gtkmmext/doi.h>
#include "about.h"
#include "rgb_macros.h"
#include "ardour_ui.h"
#include "i18n.h"
using namespace Gtk;
using namespace std;
using namespace SigC;
using namespace ARDOUR;
#ifdef WITH_PAYMENT_OPTIONS
/* XPM */
static const gchar * paypal_xpm[] = {
"62 31 33 1",
" c None",
". c #325781",
"+ c #154170",
"@ c #C1CDDA",
"# c #4E6E92",
"$ c #D1D5DA",
"% c #88A0B8",
"& c #B4C4D3",
"* c #C8D3DE",
"= c #D7E1E9",
"- c #002158",
"; c #F6F8FA",
"> c #44658B",
", c #E7ECF0",
"' c #A4B7CA",
") c #9DB0C4",
"! c #E3F1F7",
"~ c #708CA9",
"{ c #E1E7ED",
"] c #567698",
"^ c #7C96B1",
"/ c #E7F5FA",
"( c #EEF1F4",
"_ c #6883A2",
": c #244873",
"< c #BBBBBB",
"[ c #E9E9E9",
"} c #063466",
"| c #22364D",
"1 c #94A7BD",
"2 c #000000",
"3 c #EAF7FC",
"4 c #FFFFFF",
"1'111111111111111111111111111111111111111111111111111111111%_#",
"%333333333333333333333333333333333333333333333333333333333333.",
"%444444444444444444444444444444444444444444444444444444444444:",
"_4333333!!!!!!33333333333333333333!!!!!!33333333333!%%%%1334[:",
"_444444@+}}}}+>)44444444444444444,:}}}}}.^(44444444@}..+.44($:",
"_433333^:&&&&)_}_33///33333333333&+)&&&'~+./3///333^.(;#]33($:",
"_444444>_444444'}_>...#%####~,]##..444444=+#]...>1;#_4;.144($:",
"_43333!+'4,>#=4(:+_%%%]}}#~#}_+~~:]44_>&44#}_%%%_+>:14=}@33($:",
"_44444*+$4&--)4(+%44444%-)4=--'4{+14,}-~44##44444&}}*4)+444($:",
"_433331:;4):_;4*}_]:.$4*-~4{}>44#-=4@.#{4;+>_:.&4,++;4_#333($:",
"_44444_#444444=.-.%&*,41-#4(:@4'-:(44444(_-:^&*,4*}#44.%444($:",
"_43333:%4;@@'~+-%44*&44]-.;;'4,:-#44*@&%:-];4{'(4)-%4{+&333($:",
"_4444{}@4*}}+>#:;4^-#4;.>+,444_+:^4(:}+.]}=4'-+(4_-&4&+{444($:",
"_4333'+(41:*=3'.44*)(4=+)+*44@}%+@4=}&=/@}{4{1{44:+,4^.3333($:",
"_4444~>,,]#444*})(;**,':*}'4;._@}=,%:444(+~(;{&,*}.,,>~4444($:",
"_4333>}}}}^3333~}::}}}}>].;4^+=~}}}}]3333'}+:}}}}}}}}}'3333($:",
"_4444$@@@@(44444$))@*@*^}$4=}14=@@@@{44444=))&*@@@@@@@;4444($:",
"_433333333333333333333=+:%%.>/33333333333333333333333333333($:",
"_4444444444444444444441....>=444444444444444444444444444444($:",
"_4333333333333333333333333333333333333333333333333333333333($:",
"_4444444444444444444444444444444444444444444444444444444444($:",
"_4333333333333333333333333333333333333333333333333333333333($:",
"_4444442222444222442444242444244222242444242222244222244444($:",
"_4333332333232333233232332232233233332233233323332333333333($:",
"_4444442222442222244424442424244222442424244424444222444444($:",
"_4333332333332333233323332333233233332332233323333333233333($:",
"_4444442444442444244424442444244222242444244424442222444444($:",
"_433333333333333333333333333333333333333333333333333333333344:",
"#4([[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[=&:",
".=&<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<1|",
"::||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"};
#endif
static gint
stoppit (GdkEventButton* ev, Gtk::Notebook* notebook)
{
gtk_signal_emit_stop_by_name (GTK_OBJECT(notebook->gtkobj()),
"button_release_event");
return TRUE;
}
static const char* author_names[] = {
N_("Marcus Andersson"),
N_("Jeremy Hall"),
N_("Steve Harris"),
N_("Tim Mayberry"),
N_("Mark Stewart"),
N_("Sam Chessman"),
N_("Jack O'Quin"),
N_("Matt Krai"),
N_("Ben Bell"),
N_("Gerard van Dongen"),
N_("Thomas Charbonnel"),
N_("Nick Mainsbridge"),
N_("Colin Law"),
N_("Sampo Savolainen"),
N_("Joshua Leach"),
N_("Rob Holland"),
N_("Per Sigmond"),
N_("Doug Mclain"),
0
};
static const char* translators[] = {
N_("French:\n\tAlain Fréhel <alain.frehel@free.fr>"),
N_("German:\n\tKarsten Petersen <kapet@kapet.de>"),
N_("Italian:\n\tFilippo Pappalardo <filippo@email.it>"),
N_("Portuguese:\n\tRui Nuno Capela <rncbc@rncbc.org>"),
N_("Brazilian Portuguese:\n\tAlexander da Franca Fernandes <alexander@nautae.eti.br>\
\n\tChris Ross <chris@tebibyte.org>"),
N_("Spanish:\n\t Alex Krohn <alexkrohn@fastmail.fm>"),
N_("Russian:\n\t Igor Blinov <pitstop@nm.ru>"),
0
};
About::About (ARDOUR_UI * ui)
: Window (GTK_WINDOW_TOPLEVEL), _ui (ui)
#ifdef WITH_PAYMENT_OPTIONS
, paypal_pixmap (paypal_xpm)
#endif
{
using namespace Notebook_Helpers;
about_index = 0;
about_cnt = 0;
drawn = false;
Gtk::Label* small_label = manage (new Label (_(
"Copyright (C) 1999-2005 Paul Davis\n"
"Ardour comes with ABSOLUTELY NO WARRANTY\n"
"This is free software, and you are welcome to redistribute it\n"
"under certain conditions; see the file COPYING for details.\n")));
Gtk::Label* version_label =
manage (new Label
(compose(_("Ardour: %1\n(built with ardour/gtk %2.%3.%4 libardour: %5.%6.%7)"),
VERSIONSTRING,
gtk_ardour_major_version,
gtk_ardour_minor_version,
gtk_ardour_micro_version,
libardour_major_version,
libardour_minor_version,
libardour_micro_version)));
Notebook* notebook = manage (new Notebook);
ScrolledWindow* author_scroller = manage (new ScrolledWindow);
Text* author_text = manage (new Text);
author_text->set_editable (false);
author_text->set_name (X_("AboutText"));
string str = _(
"Primary author:\n\t\
Paul Davis\n\n\
Major developers:\n\t\
Jesse Chappell\n\t\
Taybin Rutkin\n\
Contributors:\n\t");
for (int32_t n = 0; author_names[n] != 0; ++n) {
str += _(author_names[n]);
str += "\n\t";
}
author_text->insert (str);
author_scroller->add (*author_text);
author_scroller->set_usize (-1, 75);
author_scroller->set_policy (GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
ScrolledWindow* translator_scroller = manage (new ScrolledWindow);
Text* translator_text = manage (new Text);
translator_text->set_editable (false);
translator_text->set_name (X_("AboutText"));
str = "";
for (int32_t n = 0; translators[n] != 0; ++n) {
str += _(translators[n]);
str += '\n';
}
translator_text->insert (str);
translator_scroller->add (*translator_text);
translator_scroller->set_usize (-1, 75);
translator_scroller->set_policy (GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
Label* author_tab_label = manage (new Label (_("Authors")));
Label* translator_tab_label = manage (new Label (_("Translators")));
notebook->pages().push_back (TabElem (*author_scroller, *author_tab_label));
notebook->pages().push_back (TabElem (*translator_scroller, *translator_tab_label));
notebook->set_name ("AboutNoteBook");
notebook->button_release_event.connect_after (bind (slot (stoppit), notebook));
logo_pixmap = 0;
logo_height = 0;
logo_width = 0;
set_name ("AboutWindow");
set_title ("ardour: about");
set_wmclass ("ardour_about", "Ardour");
vbox.set_border_width (5);
vbox.set_spacing (5);
if (load_logo_size ()) {
logo_area.set_usize (logo_width, logo_height);
load_logo (*this);
vbox.pack_start (logo_area, false, false);
logo_area.expose_event.connect (slot (*this, &About::logo_area_expose));
} else {
expose_event.connect (slot (*this, &About::logo_area_expose));
}
small_label->set_name ("AboutWindowSmallLabel");
version_label->set_name("AboutWindowSmallLabel");
first_label.set_name ("AboutWindowLabel");
third_label.set_name ("AboutWindowPDLabel");
second_label.set_name ("AboutWindowLabel");
subvbox.pack_start (*small_label, false, false);
subvbox.pack_start (*version_label, false, false);
subvbox.pack_start (*notebook, true, true);
#ifdef WITH_PAYMENT_OPTIONS
paypal_button.add (paypal_pixmap);
HBox *payment_box = manage (new HBox);
payment_box->pack_start (paypal_button, true, false);
subvbox.pack_start (*payment_box, false, false);
#endif
delete_event.connect (bind (slot (just_hide_it), static_cast<Gtk::Window*> (this)));
add (vbox);
add_events (GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK);
set_position (GTK_WIN_POS_CENTER);
show_all ();
subvbox.hide ();
/* wait for the first logo expose event to complete so that
we know we are fully drawn.
*/
while (!drawn) {
gtk_main_iteration ();
}
}
About::~About ()
{
}
void
About::show_sub (bool yn)
{
if (yn) {
vbox.pack_start (subvbox, true, true);
subvbox.show_all ();
} else {
vbox.remove (subvbox);
subvbox.hide ();
}
}
gint
About::button_release_event_impl (GdkEventButton* ev)
{
hide();
if (!_ui->shown ()) {
/* show it immediately */
_ui->show();
}
return TRUE;
}
void
About::realize_impl ()
{
Window::realize_impl ();
get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
// get_window().set_decorations (GdkWMDecoration (0));
}
bool
About::load_logo_size ()
{
gchar buf[1024];
FILE *fp;
string path = find_data_file ("splash.ppm");
if (path.length() == 0) {
return false;
}
if ((fp = fopen (path.c_str(), "rb")) == 0) {
error << compose (_("cannot open splash image file \"%1\""), path) << endmsg;
return false;
}
fgets (buf, sizeof (buf), fp);
if (strcmp (buf, "P6\n") != 0) {
fclose (fp);
return false;
}
fgets (buf, sizeof (buf), fp);
fgets (buf, sizeof (buf), fp);
sscanf (buf, "%d %d", &logo_width, &logo_height);
fclose (fp);
return true;
}
bool
About::load_logo (Gtk::Window& window)
{
GdkGC* gc;
gchar buf[1024];
guchar *pixelrow;
FILE *fp;
gint count;
gint i;
string path;
path = find_data_file ("splash.ppm");
if (path.length() == 0) {
return false;
}
if ((fp = fopen (path.c_str(), "rb")) == 0) {
return false;
}
fgets (buf, sizeof (buf), fp);
if (strcmp (buf, "P6\n") != 0) {
fclose (fp);
return false;
}
fgets (buf, sizeof (buf), fp);
fgets (buf, sizeof (buf), fp);
sscanf (buf, "%d %d", &logo_width, &logo_height);
fgets (buf, sizeof (buf), fp);
if (strcmp (buf, "255\n") != 0) {
fclose (fp);
return false;
}
Gtk::Preview preview (GTK_PREVIEW_COLOR);
preview.size (logo_width, logo_height);
pixelrow = new guchar[logo_width * 3];
for (i = 0; i < logo_height; i++) {
count = fread (pixelrow, sizeof (unsigned char), logo_width * 3, fp);
if (count != (logo_width * 3))
{
delete [] pixelrow;
fclose (fp);
return false;
}
preview.draw_row (pixelrow, 0, i, logo_width);
}
window.realize ();
logo_pixmap = gdk_pixmap_new (GTK_WIDGET(window.gtkobj())->window, logo_width, logo_height,
gtk_preview_get_visual()->depth);
gc = gdk_gc_new (logo_pixmap);
gtk_preview_put (preview.gtkobj(), logo_pixmap, gc, 0, 0, 0, 0, logo_width, logo_height);
gdk_gc_destroy (gc);
delete [] pixelrow;
fclose (fp);
return true;
}
gint
About::logo_area_expose (GdkEventExpose* ev)
{
if (!drawn) {
drawn = true;
}
if (logo_pixmap) {
logo_area.get_window().draw_pixmap (logo_area.get_style()->get_black_gc(),
Gdk_Pixmap (logo_pixmap),
0, 0,
((logo_area.width() - logo_width) / 2),
((logo_area.height() - logo_height) / 2),
logo_width, logo_height);
gdk_flush ();
}
return FALSE;
}
#ifdef WITH_PAYMENT_OPTIONS
void
About::goto_paypal ()
{
char buf[PATH_MAX+16];
char *argv[4];
char *docfile = "foo";
int grandchild;
if (fork() == 0) {
/* child */
if ((grandchild = fork()) == 0) {
/* grandchild */
argv[0] = "mozilla";
argv[1] = "-remote";
snprintf (buf, sizeof(buf), "openurl(%s)", docfile);
argv[2] = buf;
argv[3] = 0;
execvp ("mozilla", argv);
error << "could not start mozilla" << endmsg;
} else {
int status;
waitpid (grandchild, &status, 0);
}
}
}
#endif

80
gtk2_ardour/about.h Normal file
View File

@@ -0,0 +1,80 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_gtk_about_h__
#define __ardour_gtk_about_h__
#include <gtk--/window.h>
#include <gtk--/pixmap.h>
#include <gtk-canvas.h>
class ARDOUR_UI;
class About : public Gtk::Window
{
public:
About (ARDOUR_UI *);
~About ();
void show_sub (bool yn);
protected:
void realize_impl ();
private:
Gtk::DrawingArea logo_area;
GdkPixmap* logo_pixmap;
Gtk::Label first_label;
Gtk::Label second_label;
Gtk::Label third_label;
Gtk::VBox vbox;
Gtk::VBox subvbox;
vector<string> authors;
vector<string> supporters;
uint32_t about_index;
uint32_t about_cnt;
int logo_height;
int logo_width;
bool drawn;
bool support;
ARDOUR_UI * _ui;
SigC::Connection timeout_connection;
bool load_logo_size ();
bool load_logo (Gtk::Window&);
gint logo_area_expose (GdkEventExpose*);
gint button_release_event_impl (GdkEventButton*);
gint start_animating ();
void stop_animating ();
void gone_hidden ();
#ifdef WITH_PAYMENT_OPTIONS
Gtk::Pixmap paypal_pixmap;
Gtk::Button paypal_button;
void goto_paypal ();
#endif
};
#endif /* __ardour_gtk_about_h__ */

View File

@@ -0,0 +1,148 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdio>
#include <cmath>
#include <sigc++/bind.h>
#include <gtkmmext/utils.h>
#include "utils.h"
#include "add_route_dialog.h"
#include "i18n.h"
using namespace Gtk;
using namespace Gtkmmext;
using namespace SigC;
extern std::vector<string> channel_combo_strings;
AddRouteDialog::AddRouteDialog ()
: ArdourDialog ("add route dialog"),
ok_button (_("OK")),
cancel_button (_("Cancel")),
track_button (_("Tracks")),
bus_button (_("Busses")),
routes_adjustment (1, 1, 32, 1, 4),
routes_spinner (routes_adjustment)
{
set_name ("AddRouteDialog");
set_title (_("ardour: add track/bus"));
set_wmclass (X_("ardour_add_track_bus"), "Ardour");
set_position (GTK_WIN_POS_MOUSE);
set_keyboard_input (true);
name_template_entry.set_name ("AddRouteDialogNameTemplateEntry");
track_button.set_name ("AddRouteDialogRadioButton");
bus_button.set_name ("AddRouteDialogRadioButton");
ok_button.set_name ("AddRouteDialogButton");
cancel_button.set_name ("AddRouteDialogButton");
routes_spinner.set_name ("AddRouteDialogSpinner");
bus_button.set_group (track_button.group());
track_button.set_active (true);
HBox *hbrb = manage (new HBox);
hbrb->set_spacing (6);
hbrb->pack_start (*(manage (new Label (_("Add")))), false, false);
hbrb->pack_start (routes_spinner, false, false);
hbrb->pack_start (track_button, false, false);
hbrb->pack_start (bus_button, false, false);
channel_combo.set_popdown_strings (channel_combo_strings);
channel_combo.set_value_in_list (true, false);
channel_combo.set_name (X_("ChannelCountSelector"));
channel_combo.get_entry()->set_name (X_("ChannelCountSelector"));
channel_combo.get_popwin()->set_name (X_("ChannelCountSelector"));
VBox *vbcc = manage (new VBox);
vbcc->set_spacing (6);
vbcc->pack_start (*(manage (new Label ("Channel configuration"))), false, false);
vbcc->pack_start (channel_combo, false, false);
#if NOT_USEFUL_YET
HBox *hbnt = manage (new HBox);
hbnt->pack_start (*(manage (new Label (_("Name (template)")))), false, false);
hbnt->pack_start (name_template_entry, true, true);
#endif
HBox* hbbut = manage (new HBox);
set_usize_to_display_given_text (ok_button, _("Cancel"), 20, 15); // this is cancel on purpose
set_usize_to_display_given_text (cancel_button, _("Cancel"), 20, 15);
hbbut->set_homogeneous (true);
hbbut->set_spacing (6);
hbbut->pack_end (cancel_button, false, false);
hbbut->pack_end (ok_button, false, false);
HBox* hbbutouter = manage (new HBox);
hbbutouter->set_border_width (12);
hbbutouter->pack_end (*hbbut, false, false);
VBox* vb2 = manage (new VBox);
vb2->set_border_width (12);
vb2->set_spacing (6);
vb2->pack_start (*hbrb, false, false);
vb2->pack_start (*vbcc, false, false);
#if NOT_USEFUL_YET
vb2->pack_start (*hbnt, false, false);
#endif
vb2->pack_start (*hbbutouter, false, false);
add (*vb2);
delete_event.connect (slot (*this, &ArdourDialog::wm_close_event));
ok_button.clicked.connect (bind (slot (*this, &ArdourDialog::stop), 0));
cancel_button.clicked.connect (bind (slot (*this, &ArdourDialog::stop), 1));
}
AddRouteDialog::~AddRouteDialog ()
{
}
bool
AddRouteDialog::track ()
{
return track_button.get_active ();
}
string
AddRouteDialog::name_template ()
{
return name_template_entry.get_text ();
}
int
AddRouteDialog::count ()
{
return (int) floor (routes_adjustment.get_value ());
}
int
AddRouteDialog::channels ()
{
return channel_combo_get_channel_count (channel_combo);
}

View File

@@ -0,0 +1,39 @@
#ifndef __gtk_ardour_add_route_dialog_h__
#define __gtk_ardour_add_route_dialog_h__
#include <string>
#include <gtk--/entry.h>
#include <gtk--/radiobutton.h>
#include <gtk--/adjustment.h>
#include <gtk--/spinbutton.h>
#include <gtk--/button.h>
#include <gtkmmext/click_box.h>
#include "ardour_dialog.h"
class AddRouteDialog : public ArdourDialog
{
public:
AddRouteDialog ();
~AddRouteDialog ();
bool track ();
std::string name_template ();
int channels ();
int count ();
Gtk::Button ok_button;
Gtk::Button cancel_button;
private:
Gtk::Entry name_template_entry;
Gtk::RadioButton track_button;
Gtk::RadioButton bus_button;
Gtk::Adjustment routes_adjustment;
Gtk::SpinButton routes_spinner;
Gtk::Combo channel_combo;
};
#endif /* __gtk_ardour_add_route_dialog_h__ */

12
gtk2_ardour/ardbg Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/sh
if [ -x ./ardour.bin ] ; then
# scons executable
export LD_LIBRARY_PATH=../libs/ardour
exec gdb ./ardour.bin
else
# autofoo/make executable
export LD_LIBRARY_PATH=../libs/ardour/.libs
exec gdb ./ardour
fi

13
gtk2_ardour/ardev Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
if [ -x ./ardour.bin ] ; then
# scons executable
export LD_LIBRARY_PATH=../libs/ardour
exec ./ardour.bin --novst $*
else
# autofoo/make executable
export LD_LIBRARY_PATH=../libs/ardour
exec ./ardour --novst $*
fi

View File

@@ -0,0 +1,169 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <iostream>
#include <gtkmmext/doi.h>
#include "ardour_dialog.h"
#include "keyboard.h"
#include "ardour_ui.h"
ArdourDialog::ArdourDialog (string name)
: Gtk::Window (GTK_WINDOW_TOPLEVEL),
KeyboardTarget (*this, name)
{
session = 0;
kbd_input = false;
running = false;
_run_status = 0;
_within_hiding = false;
hide_on_stop = true;
}
ArdourDialog::~ArdourDialog ()
{
}
gint
ArdourDialog::enter_notify_event_impl (GdkEventCrossing *ev)
{
if (ev->detail != GDK_NOTIFY_INFERIOR) {
Keyboard::the_keyboard().set_current_dialog (this);
}
return FALSE;
}
gint
ArdourDialog::leave_notify_event_impl (GdkEventCrossing *ev)
{
if (ev->detail != GDK_NOTIFY_INFERIOR) {
Keyboard::the_keyboard().set_current_dialog (0);
}
return FALSE;
}
gint
ArdourDialog::unmap_event_impl (GdkEventAny *ev)
{
_within_hiding = true;
Hiding (); /* EMIT_SIGNAL */
_within_hiding = false;
return Gtk::Window::unmap_event_impl (ev);
}
void
ArdourDialog::wm_close()
{
stop (-1);
ARDOUR_UI::instance()->allow_focus(false);
}
void
ArdourDialog::wm_doi ()
{
if (!hide_on_stop) {
Hiding (); /* EMIT_SIGNAL */
}
stop (-1);
delete_when_idle (this);
}
gint
ArdourDialog::wm_close_event (GdkEventAny* ev)
{
wm_close ();
return TRUE;
}
gint
ArdourDialog::wm_doi_event (GdkEventAny* ev)
{
wm_doi ();
return TRUE;
}
gint
ArdourDialog::wm_doi_event_stop (GdkEventAny* ev)
{
stop (-1);
return TRUE;
}
void
ArdourDialog::set_hide_on_stop (bool yn)
{
hide_on_stop = yn;
}
void
ArdourDialog::close ()
{
hide_all ();
if (kbd_input) {
ARDOUR_UI::instance()->allow_focus (false);
}
}
void
ArdourDialog::stop (int rr)
{
_run_status = rr;
if (hide_on_stop) {
Hiding (); /* EMIT_SIGNAL */
hide_all ();
if (kbd_input) {
ARDOUR_UI::instance()->allow_focus (false);
}
}
if (running) {
Gtk::Main::quit ();
running = false;
}
}
void
ArdourDialog::run ()
{
show_all ();
if (kbd_input) {
ARDOUR_UI::instance()->allow_focus (true);
}
running = true;
Gtk::Main::run ();
}
void
ArdourDialog::set_keyboard_input (bool yn)
{
kbd_input = yn;
}
int
ArdourDialog::run_status ()
{
return _run_status;
}

View File

@@ -0,0 +1,81 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_dialog_h__
#define __ardour_dialog_h__
#include <ardour/ardour.h>
#include <gtk--/window.h>
#include "keyboard_target.h"
namespace ARDOUR {
class Session;
};
/*
* This virtual parent class is so that each dialog box uses the
* same mechanism to declare its closing, and to have a common
* method of connecting and disconnecting from a Session.
*/
class ArdourDialog : public Gtk::Window, public KeyboardTarget
{
public:
ArdourDialog (string name);
~ArdourDialog();
bool within_hiding() const { return _within_hiding; }
void run ();
void stop (int);
void close ();
void set_keyboard_input (bool yn);
void set_hide_on_stop (bool yn);
int run_status();
gint enter_notify_event_impl (GdkEventCrossing*);
gint leave_notify_event_impl (GdkEventCrossing*);
gint unmap_event_impl (GdkEventAny *);
ARDOUR::Session *session;
virtual void set_session (ARDOUR::Session* s) {
session = s;
}
virtual void session_gone () {
set_session (0);
}
void quit ();
void wm_close();
void wm_doi ();
gint wm_close_event (GdkEventAny *);
gint wm_doi_event (GdkEventAny *);
gint wm_doi_event_stop (GdkEventAny *);
private:
int _run_status;
bool _within_hiding;
bool kbd_input;
bool running;
bool hide_on_stop;
};
#endif // __ardour_dialog_h__

View File

@@ -0,0 +1,167 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_image_comp_h__
#define __ardour_image_comp_h__
#include <string>
namespace ardourvis
{
/** Simple version number */
const int32_t MSG_VERSION = 1 ;
/** the default port we use */
const int32_t DEFAULT_PORT = 30000 ;
/** the maximum buffer size we will use to send receive a message (image data handled differently) */
const int32_t MAX_MSG_SIZE = 256 ;
/** the number of characters used for a value describing the characters within a textual data element */
const int32_t TEXT_SIZE_CHARS = 3 ;
/** the number of characters we use for time values within a message */
const int32_t TIME_VALUE_CHARS = 10 ;
/** the number of charachters we use for other value data, ie image width/height values */
const int32_t IMAGE_SIZE_CHARS = 3 ;
/** the number of characters used to for the size of the image data message */
const int32_t IMAGE_DATA_MESSAGE_SIZE_CHARS = 32 ;
// ------------------------------------------------------------------------- //
// Main Actions
// we join the action chars with items to create the message
// with the exception of the return values, all messages begin with one
// of these message parts
/** Insert an Item */
const std::string INSERT_ITEM = "IN" ;
/** Remove an Item */
const std::string REMOVE_ITEM = "RM" ;
/** Rename a named item */
const std::string RENAME_ITEM = "MV" ;
/** Request some aditional data */
const std::string REQUEST_DATA = "RQ" ;
/** Return of a data request */
const std::string RETURN_DATA = "RD" ;
/** Update a item */
const std::string ITEM_UPDATE = "IU" ;
/** Select an Item */
const std::string ITEM_SELECTED = "IS" ;
/** Sesion Action */
const std::string SESSION_ACTION = "SA" ;
/** Sesion Action */
const std::string SHUTDOWN = "SD" ;
// ------------------------------------------------------------------------- //
// Return values
const std::string RETURN_TRUE = "RT1" ;
const std::string RETURN_FALSE = "RT0" ;
// ------------------------------------------------------------------------- //
// Updateable attributes
/** Update the position of a time axis item */
const std::string POSITION_CHANGE = "PC" ;
/** Update the duration of a time axis item */
const std::string DURATION_CHANGE = "DC" ;
/** Enable the position lock constraint no a time axis item */
const std::string POSITION_LOCK_CHANGE = "PL" ;
/** Enable the duration lock constraint no a time axis item */
const std::string DURATION_LOCK_CHANGE = "PL" ;
/** Update the Maximum duration of a time axis item (_Upper _Duration) */
const std::string MAX_DURATION_CHANGE = "UD" ;
/** Enable the Maximum duration constraint of a time axis item (_Enable _Upper (Duration)) */
const std::string MAX_DURATION_ENABLE_CHANGE = "EU" ;
/** Update the Minimum duration of a time axis item (_Lowerr _Duration) */
const std::string MIN_DURATION_CHANGE = "LD" ;
/** Enable the Minimum duration constraint of a time axis item (_Enable _Lower (Duration)) */
const std::string MIN_DURATION_ENABLE_CHANGE = "EL" ;
/** Refresh the image data of an imageframe item (original image has been altered?) */
const std::string IMAGE_REFRESH = "IR" ;
/** the session sample rate has changed */
const std::string SAMPLE_RATE_CHANGE = "RC" ;
// ------------------------------------------------------------------------- //
// Requestable data items
/** RGB data of the iamge */
// this is probably a bad choice of string !
const std::string IMAGE_RGB_DATA = "ID" ;
/** the (path) name of the Ardour session */
const std::string SESSION_NAME = "SN" ;
/** the current sample rate */
const std::string SAMPLE_RATE = "SR" ;
/** the (path) name of the image compositor session */
const std::string COMPOSITOR_SESSION = "CS" ;
// ------------------------------------------------------------------------- //
// Session Actions - follwed by session path
/** Close a session */
const std::string CLOSE_SESSION = "CS" ;
/** Open a session */
const std::string OPEN_SESSION = "OS" ;
// ------------------------------------------------------------------------- //
// Items
const std::string IMAGEFRAME_TIME_AXIS = "IT" ;
const std::string MARKER_TIME_AXIS = "MT" ;
const std::string IMAGEFRAME_ITEM = "II" ;
const std::string MARKER_ITEM = "MI" ;
/** or an ImageFrameTimeAxisGroup */
const std::string IMAGEFRAME_GROUP = "IG" ;
} /* namespace ardour_visual */
#endif /* __ardour_image_comp_socket_h__ */

View File

@@ -0,0 +1,73 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include "ardour_message.h"
#include "i18n.h"
using namespace std;
using namespace Gtk;
ArdourMessage::ArdourMessage (Gtk::Window* parent,
string name, string msg,
bool grab_focus, bool auto_run)
: ArdourDialog (name),
ok_button (_("OK"))
{
set_keyboard_input (true);
label.set_text (msg);
label.set_alignment (0.5, 0.5);
label.set_name (X_("PrompterLabel"));
ok_button.set_name ("EditorGTKButton");
ok_button.clicked.connect (bind (slot (*this, &ArdourDialog::stop), 1));
packer.set_spacing (10);
packer.set_border_width (10);
packer.pack_start (label);
packer.pack_start (ok_button);
set_name (X_("Prompter"));
set_position (GTK_WIN_POS_MOUSE);
set_modal (true);
add (packer);
show_all ();
realize();
get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
if (grab_focus) {
ok_button.grab_focus ();
}
if (parent) {
set_transient_for (*parent);
}
if (auto_run) {
run ();
}
}
ArdourMessage::~ArdourMessage()
{
}

View File

@@ -0,0 +1,49 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_message_h__
#define __ardour_message_h__
#include <string>
#include <gtk--/box.h>
#include <gtk--/button.h>
#include <gtk--/label.h>
#include "ardour_dialog.h"
class ArdourMessage : public ArdourDialog
{
public:
ArdourMessage (Gtk::Window* parent,
std::string name, std::string msg,
bool grabfocus = true,
bool autorun = true);
~ArdourMessage();
private:
Gtk::VBox packer;
Gtk::Button ok_button;
Gtk::Label label;
};
#endif // __ardour_message_h__

3385
gtk2_ardour/ardour_ui.cc Normal file

File diff suppressed because it is too large Load Diff

728
gtk2_ardour/ardour_ui.h Normal file
View File

@@ -0,0 +1,728 @@
/*
Copyright (C) 1999-2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_gui_h__
#define __ardour_gui_h__
/* need _BSD_SOURCE to get timersub macros */
#ifdef _BSD_SOURCE
#include <sys/time.h>
#else
#define _BSD_SOURCE
#include <sys/time.h>
#undef _BSD_SOURCE
#endif
#include <list>
#include <cmath>
#include <gtk-canvas.h>
#include <pbd/xml++.h>
#include <gtkmmext/gtk_ui.h>
#include <gtkmmext/pix.h>
#include <gtkmmext/spinner.h>
#include <gtkmmext/pixmap_button.h>
#include <gtkmmext/popup_selector.h>
#include <gtkmmext/click_box.h>
#include <gtkmmext/selector.h>
#include <ardour/ardour.h>
#include <ardour/session.h>
#include "audio_clock.h"
#include "ardour_dialog.h"
#include "editing.h"
class AudioClock;
class PublicEditor;
class Keyboard;
class MeterBridge;
class OptionEditor;
class Mixer_UI;
class ConnectionEditor;
class RouteParams_UI;
class SoundFileSelector;
class About;
class AddRouteDialog;
class NewSessionDialog;
class LocationUI;
namespace Gtkmmext {
class TearOff;
};
namespace ARDOUR {
class AudioEngine;
class Route;
class Port;
class IO;
};
namespace ALSA {
class MultiChannelDevice;
};
#define FRAME_NAME "BaseFrame"
class ARDOUR_UI : public Gtkmmext::UI
{
public:
ARDOUR_UI (int *argcp, char **argvp[], string rcfile);
~ARDOUR_UI();
void show ();
bool shown() { return shown_flag; }
void show_splash ();
void hide_splash ();
int load_session (string path, string snapshot, string* mix_template = 0);
bool session_loaded;
int build_session (string path, string snapshot,
uint32_t ctl_chns,
uint32_t master_chns,
ARDOUR::Session::AutoConnectOption input_connect,
ARDOUR::Session::AutoConnectOption output_connect,
uint32_t nphysin,
uint32_t nphysout,
jack_nframes_t initial_length);
bool session_is_new() const { return _session_is_new; }
ARDOUR::Session* the_session() { return session; }
bool will_create_new_session_automatically() const {
return _will_create_new_session_automatically;
}
void set_will_create_new_session_automatically (bool yn) {
_will_create_new_session_automatically = yn;
}
void new_session (bool startup = false, std::string path = string());
gint cmdline_new_session (std::string path);
int unload_session ();
void close_session() { unload_session(); }
int save_state_canfail (string state_name = "");
void save_state (string state_name = "");
void restore_state (string state_name = "");
static double gain_to_slider_position (ARDOUR::gain_t g);
static ARDOUR::gain_t slider_position_to_gain (double pos);
static ARDOUR_UI *instance () { return theArdourUI; }
PublicEditor& the_editor(){return *editor;}
Mixer_UI* the_mixer() { return mixer; }
void allow_focus (bool yn);
static gint generic_focus_in_event (GdkEventFocus *);
static gint generic_focus_out_event (GdkEventFocus *);
void toggle_location_window ();
void toggle_big_clock_window ();
void toggle_connection_editor ();
void toggle_route_params_window ();
void toggle_tempo_window ();
void toggle_sfdb_window ();
SoundFileSelector& get_sfdb_window();
gint32 select_diskstream (GdkEventButton *ev);
Gtk::Tooltips& tooltips() { return _tooltips; }
static SigC::Signal1<void,bool> Blink;
static SigC::Signal0<void> RapidScreenUpdate;
static SigC::Signal0<void> SuperRapidScreenUpdate;
static SigC::Signal1<void,jack_nframes_t> Clock;
/* this is a helper function to centralize the (complex) logic for
blinking rec-enable buttons.
*/
void rec_enable_button_blink (bool onoff, ARDOUR::DiskStream *, Gtk::Widget *w);
void name_io_setup (ARDOUR::AudioEngine&, string&, ARDOUR::IO& io, bool in);
void choose_io (ARDOUR::IO&, bool input);
static gint hide_and_quit (GdkEventAny *ev, ArdourDialog *);
XMLNode* editor_settings() const;
XMLNode* mixer_settings () const;
XMLNode* keyboard_settings () const;
void save_ardour_state ();
gboolean configure_handler (GdkEventConfigure* conf);
void do_transport_locate (jack_nframes_t position);
void halt_on_xrun_message ();
AudioClock primary_clock;
AudioClock secondary_clock;
AudioClock preroll_clock;
AudioClock postroll_clock;
void add_route ();
void session_add_audio_track (int input_channels, int32_t output_channels) {
session_add_audio_route (true, input_channels, output_channels);
}
void session_add_audio_bus (int input_channels, int32_t output_channels) {
session_add_audio_route (false, input_channels, output_channels);
}
void session_add_midi_track ();
void set_engine (ARDOUR::AudioEngine&);
gint exit_on_main_window_close (GdkEventAny *);
protected:
friend class PublicEditor;
void toggle_metering ();
void toggle_clocking ();
void toggle_auto_play ();
void toggle_auto_input ();
void toggle_punch_in ();
void toggle_punch_out ();
void toggle_auto_return ();
void toggle_click ();
void toggle_follow ();
void toggle_session_auto_loop ();
void toggle_session_punch_in ();
void toggle_options_window ();
private:
struct GlobalClickBox : public Gtk::VBox {
Gtkmmext::ClickBox *box;
Gtk::Frame frame;
Gtk::Label label;
vector<string> &strings;
Gtk::Adjustment adjustment;
static void printer (char buf[32], Gtk::Adjustment &adj, void *arg);
GlobalClickBox (const string &str, vector<string> &vs)
: strings (vs),
adjustment (0, 0, vs.size() - 1, 1, 1, 0) {
box = new Gtkmmext::ClickBox (&adjustment, "ClickButton");
label.set_text (str);
label.set_name ("GlobalButtonLabel");
frame.add (*box);
frame.set_shadow_type (GTK_SHADOW_IN);
pack_start (label);
pack_start (frame);
box->set_print_func (printer, this);
box->set_wrap (true);
};
};
ARDOUR::AudioEngine *engine;
ARDOUR::Session *session;
Gtk::Tooltips _tooltips;
void goto_editor_window ();
void goto_mixer_window ();
Gtk::Table adjuster_table;
Gtk::Frame adjuster_frame;
Gtk::Fixed adjuster_base;
GlobalClickBox *online_control_button;
vector<string> online_control_strings;
GlobalClickBox *crossfade_time_button;
vector<string> crossfade_time_strings;
GlobalClickBox *mmc_id_button;
vector<string> mmc_id_strings;
Gtk::ToggleButton preroll_button;
Gtk::ToggleButton postroll_button;
Gtk::Table transport_table;
Gtk::Table option_table;
static SoundFileSelector* sfdb_window;
int setup_windows ();
void setup_session_menu ();
void setup_transport ();
void setup_clock ();
void setup_session_info ();
void setup_adjustables ();
Gtk::MenuBar* make_menubar ();
static ARDOUR_UI *theArdourUI;
void startup ();
void shutdown ();
void finish();
int ask_about_saving_session (string why);
gint ask_about_save_deleted (GdkEventAny*);
void save_session_choice_made (int);
int save_the_session;
void queue_transport_change ();
void map_transport_state ();
int32_t do_engine_start ();
gint start_engine ();
void engine_halted ();
void engine_stopped ();
void engine_running ();
void map_some_session_state (Gtk::ToggleButton& button,
bool (ARDOUR::Session::*get)() const);
void toggle_some_session_state (Gtk::ToggleButton& button,
bool (ARDOUR::Session::*get)() const,
void (ARDOUR::Session::*set)(bool));
void map_button_state ();
void clear_meters ();
static gint _blink (void *);
void blink ();
gint blink_timeout_tag;
bool blink_on;
void start_blinking ();
void stop_blinking ();
void control_methods_adjusted ();
void mmc_device_id_adjusted ();
private:
Gtk::VBox top_packer;
SigC::Connection clock_signal_connection;
void update_clocks ();
void start_clocking ();
void stop_clocking ();
class BigClockWindow : public ArdourDialog
{
public:
BigClockWindow () : ArdourDialog ("big clock window") {};
};
AudioClock big_clock;
Gtk::Frame big_clock_frame;
BigClockWindow* big_clock_window;
void big_clock_size_event (GtkAllocation *alloc);
void big_clock_realize ();
/* Transport Control */
void detach_tearoff (Gtk::Box* parent, Gtk::Widget* contents);
void reattach_tearoff (Gtk::Box* parent, Gtk::Widget* contents, int32_t order);
Gtkmmext::TearOff* transport_tearoff;
Gtk::Frame transport_frame;
Gtk::HBox transport_tearoff_hbox;
Gtk::HBox transport_hbox;
Gtk::Fixed transport_base;
Gtk::Fixed transport_button_base;
Gtk::Frame transport_button_frame;
Gtk::HBox transport_button_hbox;
Gtk::VBox transport_button_vbox;
Gtk::HBox transport_option_button_hbox;
Gtk::VBox transport_option_button_vbox;
Gtk::HBox transport_clock_hbox;
Gtk::VBox transport_clock_vbox;
Gtk::HBox primary_clock_hbox;
Gtk::HBox secondary_clock_hbox;
Gtk::Button goto_start_button;
Gtk::Button goto_end_button;
Gtk::Button rewind_button;
Gtk::Button forward_button;
Gtk::Button stop_button;
enum ShuttleBehaviour {
Sprung,
Wheel
};
enum ShuttleUnits {
Percentage,
Semitones
};
Gtk::DrawingArea shuttle_box;
Gtk::EventBox speed_display_box;
Gtk::Label speed_display_label;
Gtk::Button shuttle_units_button;
Gtk::Button shuttle_style_button;
Gtk::Menu shuttle_unit_menu;
Gtk::Menu shuttle_style_menu;
ShuttleBehaviour shuttle_behaviour;
ShuttleUnits shuttle_units;
void shuttle_style_clicked ();
void shuttle_unit_clicked ();
void set_shuttle_behaviour (ShuttleBehaviour);
void set_shuttle_units (ShuttleUnits);
void update_speed_display ();
gint shuttle_box_button_press (GdkEventButton*);
gint shuttle_box_button_release (GdkEventButton*);
gint shuttle_box_motion (GdkEventMotion*);
gint shuttle_box_expose (GdkEventExpose*);
gint mouse_shuttle (double x, bool force);
void use_shuttle_fract (bool force);
bool shuttle_grabbed;
double shuttle_fract;
Gtk::ToggleButton auto_loop_button;
Gtk::ToggleButton play_selection_button;
Gtk::ToggleButton roll_button;
Gtk::ToggleButton rec_button;
Gtk::ToggleButton punch_in_button;
Gtk::ToggleButton punch_out_button;
Gtk::ToggleButton auto_return_button;
Gtk::ToggleButton auto_play_button;
Gtk::ToggleButton auto_input_button;
Gtk::ToggleButton click_button;
Gtk::ToggleButton follow_button;
Gtk::ToggleButton auditioning_alert_button;
Gtk::ToggleButton solo_alert_button;
Gtk::VBox alert_box;
void follow_changed ();
void solo_blink (bool);
void audition_blink (bool);
void soloing_changed (bool);
void auditioning_changed (bool);
void _auditioning_changed (bool);
void solo_alert_toggle ();
void audition_alert_toggle ();
void primary_clock_value_changed ();
void secondary_clock_value_changed ();
/* called by Blink signal */
void transport_rec_enable_blink (bool onoff);
/* These change where we accept control from:
MMC, X (local) or both.
*/
void allow_mmc_only ();
void allow_mmc_and_local ();
void allow_local_only ();
static void rate_printer (char buf[32], Gtk::Adjustment &, void *);
Gtk::Menu* session_popup_menu;
Gtk::CTree session_selector;
ArdourDialog* session_selector_window;
Gtk::FileSelection* open_session_selector;
void build_session_selector();
void session_selection (Gtk::CTree::Row, gint col);
struct RecentSessionsSorter {
bool operator() (std::pair<string,string> a, std::pair<string,string> b) const {
return cmp_nocase(a.first, b.first) == -1;
}
};
void redisplay_recent_sessions();
/* menu bar and associated stuff */
Gtk::MenuBar menu_bar;
Gtk::Fixed menu_bar_base;
Gtk::HBox menu_hbox;
void build_menu_bar ();
void pack_toplevel_controls();
/* handles on the menu bar items that need to
be sensitive to whether or not we have
a session loaded.
*/
Gtk::MenuItem *add_track_item;
Gtk::MenuItem *save_item;
Gtk::MenuItem *snapshot_item;
Gtk::MenuItem *save_as_item;
Gtk::MenuItem *save_template_item;
Gtk::MenuItem *export_item;
Gtk::MenuItem *close_item;
Gtk::CheckMenuItem *meter_bridge_dialog_check;
Gtk::CheckMenuItem *connection_editor_check;
Gtk::CheckMenuItem *route_params_check;
Gtk::CheckMenuItem *locations_dialog_check;
Gtk::CheckMenuItem *big_clock_check;
Gtk::CheckMenuItem *tempo_editor_check;
Gtk::CheckMenuItem *sfdb_check;
Gtk::CheckMenuItem *options_window_check;
/* <CMT Additions> */
Gtk::MenuItem *image_compositor_item ;
/* </CMT Additions> */
Gtk::Label wall_clock_label;
Gtk::EventBox wall_clock_box;
gint update_wall_clock ();
Gtk::Label disk_space_label;
Gtk::EventBox disk_space_box;
void update_disk_space ();
Gtk::Label cpu_load_label;
Gtk::EventBox cpu_load_box;
void update_cpu_load ();
Gtk::Label disk_rate_label;
Gtk::EventBox disk_rate_box;
void update_disk_rate();
Gtk::Label buffer_load_label;
Gtk::EventBox buffer_load_box;
void update_buffer_load ();
Gtk::Label sample_rate_label;
Gtk::EventBox sample_rate_box;
void update_sample_rate (jack_nframes_t);
gint every_second ();
gint every_point_one_seconds ();
gint every_point_zero_one_seconds ();
SigC::Connection second_connection;
SigC::Connection point_one_second_connection;
SigC::Connection point_zero_one_second_connection;
void diskstream_added (ARDOUR::DiskStream*);
gint session_menu (GdkEventButton *);
bool _will_create_new_session_automatically;
NewSessionDialog* new_session_window;
string template_name;
void new_session_ok_clicked ();
void new_session_template_choice (Gtkmmext::Selector *, Gtkmmext::SelectionResult*);
void hide_dialog (ArdourDialog *dialog);
void fs_cancel_clicked (Gtk::FileSelection*);
gint fs_delete_event (GdkEventAny*, Gtk::FileSelection*);
void open_session ();
void open_recent_session ();
void open_ok_clicked ();
void save_template ();
void session_add_audio_route (bool disk, int32_t input_channels, int32_t output_channels);
void add_diskstream_to_menu (ARDOUR::DiskStream&);
void diskstream_selected (gint32);
Gtk::Menu *diskstream_menu;
gint32 selected_dstream;
gint mouse_transport_goto_start (GdkEventButton *) {
transport_goto_start (); return TRUE;
}
gint mouse_transport_goto_end (GdkEventButton *) {
transport_goto_end (); return TRUE;
}
gint mouse_transport_record (GdkEventButton *) {
transport_record (); return TRUE;
}
gint mouse_transport_forward (GdkEventButton *) {
transport_forward (0); return TRUE;
}
gint mouse_transport_rewind (GdkEventButton *) {
transport_rewind (0); return TRUE;
}
gint mouse_transport_loop (GdkEventButton *) {
transport_loop (); return TRUE;
}
gint mouse_transport_play_selection (GdkEventButton *) {
transport_play_selection (); return TRUE;
}
gint mouse_transport_roll (GdkEventButton *);
gint mouse_transport_stop (GdkEventButton *);
void set_transport_sensitivity (bool);
void remove_last_capture ();
void transport_goto_start ();
void transport_goto_end ();
void transport_stop ();
void transport_stop_and_forget_capture ();
void transport_record ();
void transport_roll ();
void transport_play_selection();
void transport_forward (int option);
void transport_rewind (int option);
void transport_loop ();
void transport_locating ();
void transport_rolling ();
void transport_rewinding ();
void transport_forwarding ();
void transport_stopped ();
void send_all_midi_feedback ();
bool _session_is_new;
void connect_to_session (ARDOUR::Session *);
void connect_dependents_to_session (ARDOUR::Session *);
void we_have_dependents ();
void setup_keybindings ();
guint32 last_key_press_time;
void snapshot_session ();
void map_control_change (ARDOUR::Session::ControlType);
void queue_map_control_change (ARDOUR::Session::ControlType);
void map_record_state ();
void queue_map_record_state ();
Mixer_UI *mixer;
int create_mixer ();
PublicEditor *editor;
int create_editor ();
MeterBridge *meter_bridge;
int create_meter_bridge ();
RouteParams_UI *route_params;
int create_route_params ();
ConnectionEditor *connection_editor;
int create_connection_editor ();
LocationUI *location_ui;
int create_location_ui ();
void meter_bridge_hiding ();
void location_ui_hiding ();
void big_clock_hiding ();
void route_params_hiding ();
void connection_editor_hiding ();
void sfdb_hiding ();
void option_hiding ();
/* Various options */
void toggle_recording_plugins ();
/* Options window */
OptionEditor *option_editor;
/* route dialog */
AddRouteDialog *add_route_dialog;
void add_route_dialog_done (int status);
/* Keyboard Handling */
Keyboard* keyboard;
/* Keymap handling */
void install_keybindings ();
void test_binding_action (const char *);
void start_keyboard_prefix();
void toggle_record_enable (guint32);
void toggle_monitor_enable (guint32);
uint32_t rec_enabled_diskstreams;
void count_recenabled_diskstreams (ARDOUR::DiskStream&);
About* about;
bool shown_flag;
/* cleanup */
Gtk::MenuItem *cleanup_item;
void display_cleanup_results (ARDOUR::Session::cleanup_report& rep, const gchar* list_title, string msg);
void cleanup ();
void flush_trash ();
bool have_configure_timeout;
struct timeval last_configure_time;
gint configure_timeout ();
struct timeval last_peak_grab;
struct timeval last_shuttle_request;
void cannot_record_no_input (ARDOUR::DiskStream*);
void delete_sources_in_the_right_thread (list<ARDOUR::Source*>*);
void editor_display_control_changed (Editing::DisplayControl c);
bool have_disk_overrun_displayed;
bool have_disk_underrun_displayed;
void disk_overrun_message_gone ();
void disk_underrun_message_gone ();
void disk_overrun_handler ();
void disk_underrun_handler ();
int pending_state_dialog ();
void disconnect_from_jack ();
void reconnect_to_jack ();
void set_jack_buffer_size (jack_nframes_t);
Gtk::MenuItem* jack_disconnect_item;
Gtk::MenuItem* jack_reconnect_item;
Gtk::Menu* jack_bufsize_menu;
int make_session_clean ();
};
#endif /* __ardour_gui_h__ */

1976
gtk2_ardour/ardour_ui.rc Normal file

File diff suppressed because it is too large Load Diff

785
gtk2_ardour/ardour_ui2.cc Normal file
View File

@@ -0,0 +1,785 @@
/*
Copyright (C) 1999 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <cerrno>
#include <iostream>
#include <cmath>
#include <gtk--.h>
#include <pbd/error.h>
#include <pbd/basename.h>
#include <pbd/fastlog.h>
#include <gtkmmext/pix.h>
#include <gtkmmext/utils.h>
#include <gtkmmext/click_box.h>
#include <gtkmmext/tearoff.h>
#include <ardour/audioengine.h>
#include <ardour/ardour.h>
#include <ardour/route.h>
#include "ardour_ui.h"
#include "public_editor.h"
#include "audio_clock.h"
#include "extra_bind.h"
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace Gtkmmext;
using namespace Gtk;
using namespace SigC;
int
ARDOUR_UI::setup_windows ()
{
using namespace Menu_Helpers;
if (create_editor ()) {
error << _("UI: cannot setup editor") << endmsg;
return -1;
}
if (create_mixer ()) {
error << _("UI: cannot setup mixer") << endmsg;
return -1;
}
if (create_meter_bridge ()) {
error << _("UI: cannot setup meter_bridge") << endmsg;
return -1;
}
/* all other dialogs are created conditionally */
we_have_dependents ();
setup_clock ();
setup_transport();
setup_adjustables ();
build_menu_bar ();
top_packer.pack_start (menu_bar_base, false, false);
top_packer.pack_start (transport_frame, false, false);
editor->add_toplevel_controls (top_packer);
return 0;
}
void
ARDOUR_UI::setup_adjustables ()
{
adjuster_table.set_homogeneous (true);
online_control_strings.push_back (_("MMC + Local"));
online_control_strings.push_back (_("MMC"));
online_control_strings.push_back (_("Local"));
online_control_button = new GlobalClickBox ("CONTROL",
online_control_strings);
online_control_button->adjustment.value_changed.connect(slot (*this,&ARDOUR_UI::control_methods_adjusted));
mmc_id_strings.push_back ("1");
mmc_id_strings.push_back ("2");
mmc_id_strings.push_back ("3");
mmc_id_strings.push_back ("4");
mmc_id_strings.push_back ("5");
mmc_id_strings.push_back ("6");
mmc_id_strings.push_back ("7");
mmc_id_strings.push_back ("8");
mmc_id_strings.push_back ("9");
mmc_id_button = new GlobalClickBox (_("MMC ID"), mmc_id_strings);
mmc_id_button->adjustment.value_changed.connect (slot (*this,&ARDOUR_UI::mmc_device_id_adjusted));
adjuster_table.attach (*online_control_button, 0, 2, 1, 2, GTK_FILL|GTK_EXPAND, 0, 5, 5);
adjuster_table.attach (*mmc_id_button, 2, 3, 1, 2, 0, 0, 5, 5);
}
#include "transport_xpms"
void
ARDOUR_UI::transport_stopped ()
{
roll_button.set_active (false);
play_selection_button.set_active (false);
auto_loop_button.set_active (false);
shuttle_fract = 0;
shuttle_box.queue_draw ();
update_disk_space ();
}
static const double SHUTTLE_FRACT_SPEED1=0.48412291827; /* derived from A1,A2 */
void
ARDOUR_UI::transport_rolling ()
{
if (session->get_play_range()) {
play_selection_button.set_active (true);
roll_button.set_active (false);
auto_loop_button.set_active (false);
} else if (session->get_auto_loop ()) {
auto_loop_button.set_active (true);
play_selection_button.set_active (false);
roll_button.set_active (false);
} else {
roll_button.set_active (true);
play_selection_button.set_active (false);
auto_loop_button.set_active (false);
}
/* reset shuttle controller */
shuttle_fract = SHUTTLE_FRACT_SPEED1; /* speed = 1.0, believe it or not */
shuttle_box.queue_draw ();
}
void
ARDOUR_UI::transport_rewinding ()
{
roll_button.set_active (true);
play_selection_button.set_active (false);
auto_loop_button.set_active (false);
}
void
ARDOUR_UI::transport_forwarding ()
{
roll_button.set_active (true);
play_selection_button.set_active (false);
auto_loop_button.set_active (false);
}
void
ARDOUR_UI::setup_transport ()
{
transport_tearoff = manage (new TearOff (transport_tearoff_hbox));
transport_tearoff->set_name ("TransportBase");
transport_hbox.pack_start (*transport_tearoff, true, false);
transport_base.set_name ("TransportBase");
transport_base.add (transport_hbox);
transport_frame.set_shadow_type (GTK_SHADOW_OUT);
transport_frame.set_name ("BaseFrame");
transport_frame.add (transport_base);
transport_tearoff->Detach.connect (bind (slot (*this, &ARDOUR_UI::detach_tearoff), static_cast<Gtk::Box*>(&top_packer),
static_cast<Gtk::Widget*>(&transport_frame)));
transport_tearoff->Attach.connect (bind (slot (*this, &ARDOUR_UI::reattach_tearoff), static_cast<Gtk::Box*> (&top_packer),
static_cast<Gtk::Widget*> (&transport_frame), 1));
goto_start_button.add (*(manage (new Gtk::Pixmap (start_xpm))));
goto_end_button.add (*(manage (new Gtk::Pixmap (end_xpm))));
roll_button.add (*(manage (new Gtk::Pixmap (arrow_xpm))));
stop_button.add (*(manage (new Gtk::Pixmap (stop_xpm))));
play_selection_button.add (*(manage (new Gtk::Pixmap (play_selection_xpm))));
rec_button.add (*(manage (new Gtk::Pixmap (rec_xpm))));
auto_loop_button.add (*(manage (new Gtk::Pixmap (loop_xpm))));
ARDOUR_UI::instance()->tooltips().set_tip (roll_button, _("Play from playhead"));
ARDOUR_UI::instance()->tooltips().set_tip (stop_button, _("Stop playback"));
ARDOUR_UI::instance()->tooltips().set_tip (play_selection_button, _("Play range/selection"));
ARDOUR_UI::instance()->tooltips().set_tip (goto_start_button, _("Go to start of session"));
ARDOUR_UI::instance()->tooltips().set_tip (goto_end_button, _("Go to end of session"));
ARDOUR_UI::instance()->tooltips().set_tip (auto_loop_button, _("Play loop range"));
ARDOUR_UI::instance()->tooltips().set_tip (auto_return_button, _("Return to last playback start when stopped"));
ARDOUR_UI::instance()->tooltips().set_tip (auto_play_button, _("Start playback after any locate"));
ARDOUR_UI::instance()->tooltips().set_tip (auto_input_button, _("Be sensible about input monitoring"));
ARDOUR_UI::instance()->tooltips().set_tip (punch_in_button, _("Start recording at auto-punch start"));
ARDOUR_UI::instance()->tooltips().set_tip (punch_out_button, _("Stop recording at auto-punch end"));
ARDOUR_UI::instance()->tooltips().set_tip (click_button, _("Enable/Disable audio click"));
ARDOUR_UI::instance()->tooltips().set_tip (follow_button, _("Enable/Disable follow playhead"));
ARDOUR_UI::instance()->tooltips().set_tip (shuttle_box, _("Shuttle speed control"));
ARDOUR_UI::instance()->tooltips().set_tip (shuttle_units_button, _("Select semitones or %%-age for speed display"));
ARDOUR_UI::instance()->tooltips().set_tip (shuttle_style_button, _("Select sprung or wheel behaviour"));
ARDOUR_UI::instance()->tooltips().set_tip (speed_display_box, _("Current transport speed"));
shuttle_box.set_flags (GTK_CAN_FOCUS);
shuttle_box.set_events (shuttle_box.get_events() | GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK);
shuttle_box.set_usize (100, 15);
shuttle_box.set_name ("TransportButton");
goto_start_button.set_name ("TransportButton");
goto_end_button.set_name ("TransportButton");
roll_button.set_name ("TransportButton");
stop_button.set_name ("TransportButton");
play_selection_button.set_name ("TransportButton");
rec_button.set_name ("TransportRecButton");
auto_loop_button.set_name ("TransportButton");
auto_return_button.set_name ("TransportButton");
auto_play_button.set_name ("TransportButton");
auto_input_button.set_name ("TransportButton");
punch_in_button.set_name ("TransportButton");
punch_out_button.set_name ("TransportButton");
click_button.set_name ("TransportButton");
follow_button.set_name ("TransportButton");
goto_start_button.unset_flags (GTK_CAN_FOCUS);
goto_end_button.unset_flags (GTK_CAN_FOCUS);
roll_button.unset_flags (GTK_CAN_FOCUS);
stop_button.unset_flags (GTK_CAN_FOCUS);
play_selection_button.unset_flags (GTK_CAN_FOCUS);
rec_button.unset_flags (GTK_CAN_FOCUS);
auto_loop_button.unset_flags (GTK_CAN_FOCUS);
auto_return_button.unset_flags (GTK_CAN_FOCUS);
auto_play_button.unset_flags (GTK_CAN_FOCUS);
auto_input_button.unset_flags (GTK_CAN_FOCUS);
punch_out_button.unset_flags (GTK_CAN_FOCUS);
punch_in_button.unset_flags (GTK_CAN_FOCUS);
click_button.unset_flags (GTK_CAN_FOCUS);
follow_button.unset_flags (GTK_CAN_FOCUS);
goto_start_button.set_events (goto_start_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
goto_end_button.set_events (goto_end_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
roll_button.set_events (roll_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
stop_button.set_events (stop_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
play_selection_button.set_events (play_selection_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
rec_button.set_events (rec_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
auto_loop_button.set_events (auto_loop_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
auto_return_button.set_events (auto_return_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
auto_play_button.set_events (auto_play_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
auto_input_button.set_events (auto_input_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
click_button.set_events (click_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
follow_button.set_events (click_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
punch_in_button.set_events (punch_in_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
punch_out_button.set_events (punch_out_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
goto_start_button.clicked.connect (slot (*this,&ARDOUR_UI::transport_goto_start));
goto_end_button.clicked.connect (slot (*this,&ARDOUR_UI::transport_goto_end));
roll_button.button_release_event.connect (slot (*this,&ARDOUR_UI::mouse_transport_roll));
play_selection_button.button_release_event.connect (slot (*this,&ARDOUR_UI::mouse_transport_play_selection));
auto_loop_button.button_release_event.connect (slot (*this,&ARDOUR_UI::mouse_transport_loop));
stop_button.button_release_event.connect (slot (*this,&ARDOUR_UI::mouse_transport_stop));
rec_button.button_release_event.connect (slot (*this,&ARDOUR_UI::mouse_transport_record));
shuttle_box.button_press_event.connect (slot (*this, &ARDOUR_UI::shuttle_box_button_press));
shuttle_box.button_release_event.connect (slot (*this, &ARDOUR_UI::shuttle_box_button_release));
shuttle_box.motion_notify_event.connect (slot (*this, &ARDOUR_UI::shuttle_box_motion));
shuttle_box.expose_event.connect (slot (*this, &ARDOUR_UI::shuttle_box_expose));
/* clocks, etc. */
ARDOUR_UI::Clock.connect (bind (slot (primary_clock, &AudioClock::set), false));
ARDOUR_UI::Clock.connect (bind (slot (secondary_clock, &AudioClock::set), false));
primary_clock.set_mode (AudioClock::SMPTE);
primary_clock.set_name ("TransportClockDisplay");
secondary_clock.set_mode (AudioClock::BBT);
secondary_clock.set_name ("TransportClockDisplay");
primary_clock.ValueChanged.connect (slot (*this, &ARDOUR_UI::primary_clock_value_changed));
secondary_clock.ValueChanged.connect (slot (*this, &ARDOUR_UI::secondary_clock_value_changed));
ARDOUR_UI::instance()->tooltips().set_tip (primary_clock, _("Primary clock"));
ARDOUR_UI::instance()->tooltips().set_tip (secondary_clock, _("secondary clock"));
/* options */
auto_return_button.toggled.connect (slot (*this,&ARDOUR_UI::toggle_auto_return));
auto_play_button.toggled.connect (slot (*this,&ARDOUR_UI::toggle_auto_play));
auto_input_button.toggled.connect (slot (*this,&ARDOUR_UI::toggle_auto_input));
click_button.toggled.connect (slot (*this,&ARDOUR_UI::toggle_click));
follow_button.toggled.connect (slot (*this,&ARDOUR_UI::toggle_follow));
punch_in_button.toggled.connect (slot (*this,&ARDOUR_UI::toggle_punch_in));
punch_out_button.toggled.connect (slot (*this,&ARDOUR_UI::toggle_punch_out));
preroll_button.unset_flags (GTK_CAN_FOCUS);
preroll_button.set_events (preroll_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
preroll_button.set_name ("TransportButton");
postroll_button.unset_flags (GTK_CAN_FOCUS);
postroll_button.set_events (postroll_button.get_events() & ~(GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK));
postroll_button.set_name ("TransportButton");
preroll_clock.set_mode (AudioClock::MinSec);
preroll_clock.set_name ("TransportClockDisplay");
postroll_clock.set_mode (AudioClock::MinSec);
postroll_clock.set_name ("TransportClockDisplay");
/* alerts */
/* CANNOT bind these to clicked or toggled, must use pressed or released */
solo_alert_button.set_name ("TransportSoloAlert");
solo_alert_button.pressed.connect (slot (*this,&ARDOUR_UI::solo_alert_toggle));
auditioning_alert_button.set_name ("TransportAuditioningAlert");
auditioning_alert_button.pressed.connect (slot (*this,&ARDOUR_UI::audition_alert_toggle));
alert_box.pack_start (solo_alert_button);
alert_box.pack_start (auditioning_alert_button);
transport_tearoff_hbox.set_border_width (5);
transport_tearoff_hbox.pack_start (goto_start_button, false, false);
transport_tearoff_hbox.pack_start (goto_end_button, false, false);
Gtk::Frame* sframe = manage (new Frame);
Gtk::VBox* svbox = manage (new VBox);
Gtk::HBox* shbox = manage (new HBox);
sframe->set_shadow_type (GTK_SHADOW_IN);
sframe->add (shuttle_box);
shuttle_box.set_name (X_("ShuttleControl"));
speed_display_box.add (speed_display_label);
set_usize_to_display_given_text (speed_display_box, _("stopped"), 2, 2);
speed_display_box.set_name (X_("ShuttleDisplay"));
shuttle_units_button.set_name (X_("ShuttleButton"));
shuttle_units_button.clicked.connect (slot (*this, &ARDOUR_UI::shuttle_unit_clicked));
shuttle_style_button.set_name (X_("ShuttleButton"));
shuttle_style_button.clicked.connect (slot (*this, &ARDOUR_UI::shuttle_style_clicked));
Gtk::Frame* sdframe = manage (new Frame);
sdframe->set_shadow_type (GTK_SHADOW_IN);
sdframe->add (speed_display_box);
shbox->pack_start (*sdframe, false, false);
shbox->pack_start (shuttle_units_button, true, true);
shbox->pack_start (shuttle_style_button, false, false);
svbox->pack_start (*sframe, false, false);
svbox->pack_start (*shbox, false, false);
transport_tearoff_hbox.pack_start (*svbox, false, false, 5);
transport_tearoff_hbox.pack_start (auto_loop_button, false, false);
transport_tearoff_hbox.pack_start (play_selection_button, false, false);
transport_tearoff_hbox.pack_start (roll_button, false, false);
transport_tearoff_hbox.pack_start (stop_button, false, false);
transport_tearoff_hbox.pack_start (rec_button, false, false, 10);
transport_tearoff_hbox.pack_start (primary_clock, false, false, 5);
transport_tearoff_hbox.pack_start (secondary_clock, false, false, 5);
transport_tearoff_hbox.pack_start (punch_in_button, false, false);
transport_tearoff_hbox.pack_start (punch_out_button, false, false);
transport_tearoff_hbox.pack_start (auto_input_button, false, false);
transport_tearoff_hbox.pack_start (auto_return_button, false, false);
transport_tearoff_hbox.pack_start (auto_play_button, false, false);
transport_tearoff_hbox.pack_start (click_button, false, false);
transport_tearoff_hbox.pack_start (follow_button, false, false);
/* desensitize */
set_transport_sensitivity (false);
/* catch up with editor state */
follow_changed ();
// transport_tearoff_hbox.pack_start (preroll_button, false, false);
// transport_tearoff_hbox.pack_start (preroll_clock, false, false);
// transport_tearoff_hbox.pack_start (postroll_button, false, false);
// transport_tearoff_hbox.pack_start (postroll_clock, false, false);
transport_tearoff_hbox.pack_start (alert_box, false, false, 5);
}
void
ARDOUR_UI::setup_clock ()
{
ARDOUR_UI::Clock.connect (bind (slot (big_clock, &AudioClock::set), false));
big_clock_window = new BigClockWindow;
big_clock_window->set_border_width (0);
big_clock_window->add (big_clock);
big_clock_window->set_title (_("ardour: clock"));
big_clock_window->delete_event.connect (bind (slot (just_hide_it), static_cast<Gtk::Window*>(big_clock_window)));
big_clock_window->realize.connect (slot (*this, &ARDOUR_UI::big_clock_realize));
big_clock_window->size_allocate.connect (slot (*this, &ARDOUR_UI::big_clock_size_event));
big_clock_window->Hiding.connect (slot (*this, &ARDOUR_UI::big_clock_hiding));
}
void
ARDOUR_UI::big_clock_size_event (GtkAllocation *alloc)
{
return;
}
void
ARDOUR_UI::big_clock_realize ()
{
big_clock_window->get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH|GDK_DECOR_MAXIMIZE|GDK_DECOR_MINIMIZE));
}
void
ARDOUR_UI::detach_tearoff (Gtk::Box* b, Gtk::Widget* w)
{
editor->ensure_float (*transport_tearoff->tearoff_window());
b->remove (*w);
}
void
ARDOUR_UI::reattach_tearoff (Gtk::Box* b, Gtk::Widget* w, int32_t n)
{
b->pack_start (*w);
b->reorder_child (*w, n);
}
void
ARDOUR_UI::soloing_changed (bool onoff)
{
if (solo_alert_button.get_active() != onoff) {
solo_alert_button.set_active (onoff);
}
}
void
ARDOUR_UI::_auditioning_changed (bool onoff)
{
if (auditioning_alert_button.get_active() != onoff) {
auditioning_alert_button.set_active (onoff);
set_transport_sensitivity (!onoff);
}
}
void
ARDOUR_UI::auditioning_changed (bool onoff)
{
Gtkmmext::UI::instance()->call_slot(bind (slot (*this, &ARDOUR_UI::_auditioning_changed), onoff));
}
void
ARDOUR_UI::audition_alert_toggle ()
{
if (session) {
session->cancel_audition();
}
}
void
ARDOUR_UI::solo_alert_toggle ()
{
if (session) {
session->set_all_solo (!session->soloing());
}
}
void
ARDOUR_UI::solo_blink (bool onoff)
{
if (session == 0) {
return;
}
if (session->soloing()) {
if (onoff) {
solo_alert_button.set_state (GTK_STATE_ACTIVE);
} else {
solo_alert_button.set_state (GTK_STATE_NORMAL);
}
} else {
solo_alert_button.set_active (false);
solo_alert_button.set_state (GTK_STATE_NORMAL);
}
}
void
ARDOUR_UI::audition_blink (bool onoff)
{
if (session == 0) {
return;
}
if (session->is_auditioning()) {
if (onoff) {
auditioning_alert_button.set_state (GTK_STATE_ACTIVE);
} else {
auditioning_alert_button.set_state (GTK_STATE_NORMAL);
}
} else {
auditioning_alert_button.set_active (false);
auditioning_alert_button.set_state (GTK_STATE_NORMAL);
}
}
gint
ARDOUR_UI::shuttle_box_button_press (GdkEventButton* ev)
{
if (!session) {
return TRUE;
}
switch (ev->button) {
case 1:
Gtk::Main::grab_add (shuttle_box);
shuttle_grabbed = true;
mouse_shuttle (ev->x, true);
break;
case 2:
case 3:
return TRUE;
break;
case 4:
break;
case 5:
break;
}
return TRUE;
}
gint
ARDOUR_UI::shuttle_box_button_release (GdkEventButton* ev)
{
if (!session) {
return TRUE;
}
switch (ev->button) {
case 1:
mouse_shuttle (ev->x, true);
shuttle_grabbed = false;
Gtk::Main::grab_remove (shuttle_box);
if (shuttle_behaviour == Sprung) {
shuttle_fract = SHUTTLE_FRACT_SPEED1;
session->request_transport_speed (1.0);
shuttle_box.queue_draw ();
}
return TRUE;
case 2:
if (session->transport_rolling()) {
shuttle_fract = SHUTTLE_FRACT_SPEED1;
session->request_transport_speed (1.0);
} else {
shuttle_fract = 0;
}
shuttle_box.queue_draw ();
return TRUE;
case 3:
return TRUE;
case 4:
shuttle_fract += 0.005;
break;
case 5:
shuttle_fract -= 0.005;
break;
}
use_shuttle_fract (true);
return TRUE;
}
gint
ARDOUR_UI::shuttle_box_motion (GdkEventMotion* ev)
{
if (!session || !shuttle_grabbed) {
return TRUE;
}
return mouse_shuttle (ev->x, false);
}
gint
ARDOUR_UI::mouse_shuttle (double x, bool force)
{
double half_width = shuttle_box.width() / 2.0;
double distance = x - half_width;
if (distance > 0) {
distance = min (distance, half_width);
} else {
distance = max (distance, -half_width);
}
shuttle_fract = distance / half_width;
use_shuttle_fract (force);
return TRUE;
}
void
ARDOUR_UI::use_shuttle_fract (bool force)
{
struct timeval now;
struct timeval diff;
/* do not attempt to submit a motion-driven transport speed request
more than once per process cycle.
*/
gettimeofday (&now, 0);
timersub (&now, &last_shuttle_request, &diff);
if (!force && (diff.tv_usec + (diff.tv_sec * 1000000)) < engine->usecs_per_cycle()) {
return;
}
last_shuttle_request = now;
bool neg = (shuttle_fract < 0.0);
double fract = 1 - sqrt (1 - (shuttle_fract * shuttle_fract)); // Formula A1
if (neg) {
fract = -fract;
}
session->request_transport_speed (8.0 * fract); // Formula A2
shuttle_box.queue_draw ();
}
gint
ARDOUR_UI::shuttle_box_expose (GdkEventExpose* event)
{
gint x;
Gdk_Window win (shuttle_box.get_window());
/* redraw the background */
win.draw_rectangle (shuttle_box.get_style()->get_bg_gc (shuttle_box.get_state()),
true,
event->area.x, event->area.y,
event->area.width, event->area.height);
x = (gint) floor ((shuttle_box.width() / 2.0) + (0.5 * (shuttle_box.width() * shuttle_fract)));
/* draw line */
win.draw_line (shuttle_box.get_style()->get_fg_gc (shuttle_box.get_state()),
x,
0,
x,
shuttle_box.height());
return TRUE;
}
void
ARDOUR_UI::shuttle_style_clicked ()
{
shuttle_style_menu.popup (1, 0);
}
void
ARDOUR_UI::shuttle_unit_clicked ()
{
shuttle_unit_menu.popup (1, 0);
}
void
ARDOUR_UI::set_shuttle_units (ShuttleUnits u)
{
switch ((shuttle_units = u)) {
case Percentage:
static_cast<Gtk::Label*>(shuttle_units_button.get_child())->set_text ("% ");
break;
case Semitones:
static_cast<Gtk::Label*>(shuttle_units_button.get_child())->set_text (_("st"));
break;
}
}
void
ARDOUR_UI::set_shuttle_behaviour (ShuttleBehaviour b)
{
switch ((shuttle_behaviour = b)) {
case Sprung:
static_cast<Gtk::Label*>(shuttle_style_button.get_child())->set_text (_("sprung"));
shuttle_fract = 0.0;
shuttle_box.queue_draw ();
if (session) {
if (session->transport_rolling()) {
shuttle_fract = SHUTTLE_FRACT_SPEED1;
session->request_transport_speed (1.0);
}
}
break;
case Wheel:
static_cast<Gtk::Label*>(shuttle_style_button.get_child())->set_text (_("wheel"));
break;
}
}
void
ARDOUR_UI::update_speed_display ()
{
if (!session) {
speed_display_label.set_text (_("stopped"));
return;
}
char buf[32];
float x = session->transport_speed ();
if (x != 0) {
if (shuttle_units == Percentage) {
snprintf (buf, sizeof (buf), "%.4f", x);
} else {
if (x < 0) {
snprintf (buf, sizeof (buf), "< %.1f", 12.0 * fast_log2 (-x));
} else {
snprintf (buf, sizeof (buf), "> %.1f", 12.0 * fast_log2 (x));
}
}
speed_display_label.set_text (buf);
} else {
speed_display_label.set_text (_("stopped"));
}
}
void
ARDOUR_UI::set_transport_sensitivity (bool yn)
{
goto_start_button.set_sensitive (yn);
goto_end_button.set_sensitive (yn);
roll_button.set_sensitive (yn);
stop_button.set_sensitive (yn);
play_selection_button.set_sensitive (yn);
rec_button.set_sensitive (yn);
auto_loop_button.set_sensitive (yn);
shuttle_box.set_sensitive (yn);
}

View File

@@ -0,0 +1,109 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
/* this file exists solely to break compilation dependencies that
would connect changes to the mixer or editor objects.
*/
#include <cstdio>
#include <pbd/error.h>
#include "ardour_ui.h"
#include "public_editor.h"
#include "mixer_ui.h"
#include "meter_bridge.h"
#include "keyboard.h"
#include "route_params_ui.h"
#include "i18n.h"
using namespace SigC;
namespace ARDOUR {
class Session;
class Route;
}
void
ARDOUR_UI::shutdown ()
{
if (session) {
delete session;
session = 0;
}
}
void
ARDOUR_UI::we_have_dependents ()
{
setup_keybindings ();
}
void
ARDOUR_UI::setup_keybindings ()
{
/* install default bindings */
KeyboardTarget *defaults = new KeyboardTarget (editor->window(), X_("default"));
XMLNode* keynode = ARDOUR::Config->get_keys();
if (keynode != 0) {
defaults->set_binding_state (*keynode);
editor->set_binding_state (*keynode);
mixer->set_binding_state (*keynode);
meter_bridge->set_binding_state (*keynode);
} else {
error << _("keyboard_target: error setting binding state: invalid node") << endmsg;
}
/* use the default keyboard target for now */
keyboard->set_default_target (defaults);
}
void
ARDOUR_UI::connect_dependents_to_session (ARDOUR::Session *s)
{
editor->connect_to_session (s);
mixer->connect_to_session (s);
meter_bridge->set_session (s);
}
void
ARDOUR_UI::goto_editor_window ()
{
editor->show_window ();
editor->window().get_window().raise ();
}
void
ARDOUR_UI::goto_mixer_window ()
{
mixer->show_window ();
mixer->get_window().raise ();
}
gint
ARDOUR_UI::exit_on_main_window_close (GdkEventAny *ev)
{
finish();
return TRUE;
}

View File

@@ -0,0 +1,454 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* This file contains any ARDOUR_UI methods that require knowledge of
the various dialog boxes, and exists so that no compilation dependency
exists between the main ARDOUR_UI modules and their respective classes.
This is to cut down on the compile times. It also helps with my sanity.
*/
#include <ardour/session.h>
#include "ardour_ui.h"
#include "mixer_ui.h"
#include "meter_bridge.h"
#include "connection_editor.h"
#include "public_editor.h"
#include "option_editor.h"
#include "location_ui.h"
#include "route_params_ui.h"
#include "library_ui.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace Gtk;
using namespace Gtkmmext;
void
ARDOUR_UI::connect_to_session (Session *s)
{
session = s;
session->HaltOnXrun.connect (slot (*this, &ARDOUR_UI::halt_on_xrun_message));
/* sensitize menu bar options that are now valid */
// save_as_item->set_sensitive (true);
save_template_item->set_sensitive (true);
snapshot_item->set_sensitive (true);
save_item->set_sensitive (true);
add_track_item->set_sensitive (true);
export_item->set_sensitive (true);
close_item->set_sensitive (true);
locations_dialog_check->set_sensitive (true);
route_params_check->set_sensitive (true);
connection_editor_check->set_sensitive (true);
cleanup_item->set_sensitive (true);
/* sensitize transport bar */
goto_start_button.set_sensitive (true);
goto_end_button.set_sensitive (true);
roll_button.set_sensitive (true);
stop_button.set_sensitive (true);
play_selection_button.set_sensitive (true);
rec_button.set_sensitive (true);
auto_loop_button.set_sensitive (true);
shuttle_box.set_sensitive (true);
/* <CMT Additions> */
if (image_compositor_item) {
image_compositor_item->set_sensitive(true) ;
}
/* </CMT Additions> */
if (session->n_diskstreams()) {
// meter_bridge_dialog_check->set_sensitive (true);
} else {
session->DiskStreamAdded.connect (slot (*this, &ARDOUR_UI::diskstream_added));
}
if (connection_editor) {
connection_editor->set_session (s);
}
if (location_ui) {
location_ui->set_session(s);
}
if (route_params) {
route_params->set_session (s);
}
if (option_editor) {
option_editor->set_session (s);
}
Blink.connect (slot (*this, &ARDOUR_UI::transport_rec_enable_blink));
Blink.connect (slot (*this, &ARDOUR_UI::solo_blink));
Blink.connect (slot (*this, &ARDOUR_UI::audition_blink));
/* these are all need to be handled in an RT-safe and MT way, so don't
do any GUI work, just queue it for handling by the GUI thread.
*/
session->TransportStateChange.connect (slot (*this, &ARDOUR_UI::queue_transport_change));
session->ControlChanged.connect (slot (*this, &ARDOUR_UI::queue_map_control_change));
/* alert the user to these things happening */
session->AuditionActive.connect (slot (*this, &ARDOUR_UI::auditioning_changed));
session->SoloActive.connect (slot (*this, &ARDOUR_UI::soloing_changed));
solo_alert_button.set_active (session->soloing());
/* can't be auditioning here */
primary_clock.set_session (s);
secondary_clock.set_session (s);
big_clock.set_session (s);
preroll_clock.set_session (s);
postroll_clock.set_session (s);
/* Clocks are on by default after we are connected to a session, so show that here.
*/
map_button_state ();
connect_dependents_to_session (s);
start_clocking ();
start_blinking ();
if (editor) {
editor->window().realize();
}
transport_stopped ();
second_connection = Main::timeout.connect (slot (*this, &ARDOUR_UI::every_second), 1000);
point_one_second_connection = Main::timeout.connect (slot (*this, &ARDOUR_UI::every_point_one_seconds), 100);
point_zero_one_second_connection = Main::timeout.connect (slot (*this, &ARDOUR_UI::every_point_zero_one_seconds), 40);
}
int
ARDOUR_UI::unload_session ()
{
if (session && session->dirty()) {
switch (ask_about_saving_session (_("close session"))) {
case -1:
return 1;
case 1:
session->save_state ("");
break;
}
}
second_connection.disconnect ();
point_one_second_connection.disconnect ();
point_zero_one_second_connection.disconnect();
/* desensitize menu bar options that are now invalid */
// save_as_item->set_sensitive (false);
save_template_item->set_sensitive (false);
snapshot_item->set_sensitive (false);
save_item->set_sensitive (false);
add_track_item->set_sensitive (false);
export_item->set_sensitive (false);
close_item->set_sensitive (false);
// meter_bridge_dialog_check->set_sensitive (false);
connection_editor_check->set_sensitive (false);
locations_dialog_check->set_sensitive (false);
// meter_bridge_dialog_check->set_active(false);
connection_editor_check->set_active(false);
locations_dialog_check->set_active(false);
route_params_check->set_sensitive (false);
/* desensitize transport bar */
goto_start_button.set_sensitive (false);
goto_end_button.set_sensitive (false);
roll_button.set_sensitive (false);
stop_button.set_sensitive (false);
play_selection_button.set_sensitive (false);
rec_button.set_sensitive (false);
auto_loop_button.set_sensitive (false);
shuttle_box.set_sensitive (false);
stop_blinking ();
stop_clocking ();
/* drop everything attached to the blink signal */
Blink.clear ();
primary_clock.set_session (0);
secondary_clock.set_session (0);
big_clock.set_session (0);
preroll_clock.set_session (0);
postroll_clock.set_session (0);
if (option_editor) {
option_editor->set_session (0);
}
if (mixer) {
mixer->hide_all ();
}
delete session;
session = 0;
update_buffer_load ();
// update_disk_rate ();
return 0;
}
int
ARDOUR_UI::create_meter_bridge ()
{
if (meter_bridge == 0) {
meter_bridge = new MeterBridge ();
meter_bridge->Hiding.connect (slot (*this, &ARDOUR_UI::meter_bridge_hiding));
}
return 0;
}
void
ARDOUR_UI::meter_bridge_hiding()
{
// meter_bridge_dialog_check->set_active(false);
}
int
ARDOUR_UI::create_connection_editor ()
{
if (connection_editor == 0) {
connection_editor = new ConnectionEditor ();
connection_editor->Hiding.connect (slot (*this, &ARDOUR_UI::connection_editor_hiding));
}
if (session) {
connection_editor->set_session (session);
}
return 0;
}
void
ARDOUR_UI::toggle_connection_editor ()
{
if (create_connection_editor()) {
return;
}
if (connection_editor->within_hiding()) {
return;
}
if (connection_editor_check->get_active()){
connection_editor->show_all();
} else {
connection_editor->hide_all();
}
}
void
ARDOUR_UI::connection_editor_hiding()
{
connection_editor_check->set_active(false);
}
void
ARDOUR_UI::big_clock_hiding()
{
big_clock_check->set_active(false);
}
void
ARDOUR_UI::toggle_big_clock_window ()
{
if (big_clock_window->within_hiding()) {
return;
}
if (big_clock_window->is_visible()) {
big_clock_window->hide_all ();
} else {
big_clock_window->show_all ();
}
}
void
ARDOUR_UI::toggle_options_window ()
{
if (option_editor == 0) {
option_editor = new OptionEditor (*this, *editor, *mixer);
option_editor->Hiding.connect(slot(*this, &ARDOUR_UI::option_hiding));
option_editor->set_session (session);
} else if (option_editor->within_hiding()) {
return;
}
if (option_editor->is_visible()) {
option_editor->hide_all ();
} else {
option_editor->show_all ();
}
}
void
ARDOUR_UI::option_hiding ()
{
options_window_check->set_active(false);
}
void
ARDOUR_UI::toggle_auto_input ()
{
toggle_some_session_state (auto_input_button,
&Session::get_auto_input,
&Session::set_auto_input);
meter_bridge->clear_all_meters ();
}
void
ARDOUR_UI::toggle_metering ()
{
#if 0
if (global_meter_button.get_active()) {
meter_bridge->toggle_metering ();
}
#endif
}
int
ARDOUR_UI::create_location_ui ()
{
if (location_ui == 0) {
location_ui = new LocationUI ();
location_ui->set_session (session);
location_ui->Hiding.connect (slot (*this, &ARDOUR_UI::location_ui_hiding));
}
return 0;
}
void
ARDOUR_UI::toggle_location_window ()
{
if (create_location_ui()) {
return;
}
if (location_ui->within_hiding()) {
return;
}
if (location_ui->is_visible()) {
location_ui->hide_all();
} else {
location_ui->show_all();
}
}
void
ARDOUR_UI::location_ui_hiding()
{
locations_dialog_check->set_active(false);
}
int
ARDOUR_UI::create_route_params ()
{
if (route_params == 0) {
route_params = new RouteParams_UI (*engine);
route_params->set_session (session);
route_params->Hiding.connect (slot (*this, &ARDOUR_UI::route_params_hiding));
}
return 0;
}
void
ARDOUR_UI::toggle_route_params_window ()
{
if (create_route_params ()) {
return;
}
if (route_params->within_hiding()) {
return;
}
if (route_params->is_visible ()) {
route_params->hide_all ();
} else {
route_params->show_all ();
}
}
void
ARDOUR_UI::route_params_hiding ()
{
route_params_check->set_active (false);
}
SoundFileSelector&
ARDOUR_UI::get_sfdb_window ()
{
if (sfdb_window == 0) {
sfdb_window = new SoundFileSelector ();
sfdb_window->Hiding.connect (slot (*this, &ARDOUR_UI::sfdb_hiding));
sfdb_window->hide_all ();
}
return *sfdb_window;
}
void
ARDOUR_UI::toggle_sfdb_window ()
{
get_sfdb_window ();
if (sfdb_window->within_hiding()) {
return;
}
if (sfdb_window->is_visible ()) {
sfdb_window->hide_all ();
} else {
sfdb_window->show_all ();
sfdb_window->hide_import_stuff();
}
}
void
ARDOUR_UI::sfdb_hiding ()
{
sfdb_check->set_active (false);
}

315
gtk2_ardour/ardour_ui_ed.cc Normal file
View File

@@ -0,0 +1,315 @@
/*
Copyright (C) 20002-2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
/* This file contains any ARDOUR_UI methods that require knowledge of
the editor, and exists so that no compilation dependency exists
between the main ARDOUR_UI modules and the PublicEditor class. This
is to cut down on the nasty compile times for both these classes.
*/
#include <pbd/pathscanner.h>
#include "ardour_ui.h"
#include "public_editor.h"
#include "audio_clock.h"
#include "editor.h"
#include <ardour/session.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace Gtk;
using namespace Gtkmmext;
int
ARDOUR_UI::create_editor ()
{
try {
editor = new Editor (*engine);
}
catch (failed_constructor& err) {
return -1;
}
editor->DisplayControlChanged.connect (slot (*this, &ARDOUR_UI::editor_display_control_changed));
return 0;
}
void
ARDOUR_UI::build_menu_bar ()
{
using namespace Menu_Helpers;
menu_bar.set_name ("MainMenuBar");
MenuList& items = menu_bar.items();
/* file menu */
Menu *session_menu = manage (new Menu);
MenuList& session_items = session_menu->items();
session_menu->set_name ("ArdourContextMenu");
session_items.push_back (MenuElem (_("New"), bind (slot (*this, &ARDOUR_UI::new_session), false, string ())));
session_items.push_back (MenuElem (_("Open"), slot (*this, &ARDOUR_UI::open_session)));
session_items.push_back (MenuElem (_("Recent"), slot (*this, &ARDOUR_UI::open_recent_session)));
session_items.push_back (MenuElem (_("Close"), slot (*this, &ARDOUR_UI::close_session)));
close_item = session_items.back();
close_item->set_sensitive (false);
session_items.push_back (SeparatorElem());
session_items.push_back (MenuElem (_("Add Track/Bus"), slot (*this, &ARDOUR_UI::add_route)));
add_track_item = session_items.back ();
add_track_item->set_sensitive (false);
session_items.push_back (SeparatorElem());
/* <CMT Additions> */
PathScanner scanner;
vector<string*>* results = scanner (getenv ("PATH"), "AniComp", false, false);
if (results && !results->empty()) {
Menu* image_compositor_menu = manage(new Menu());
MenuList& image_compositor_items = image_compositor_menu->items();
image_compositor_menu->set_name ("ArdourContextMenu");
image_compositor_items.push_back(MenuElem (_("Connect"), (slot (editor, &PublicEditor::connect_to_image_compositor)))) ;
session_items.push_back(MenuElem (_("Image Compositor"), *image_compositor_menu)) ;
image_compositor_item = session_items.back() ;
image_compositor_item->set_sensitive(false) ;
session_items.push_back (SeparatorElem());
} else {
image_compositor_item = 0;
}
if (results) {
delete results;
}
/* </CMT Additions> */
session_items.push_back (MenuElem (_("Save"), bind (slot (*this, &ARDOUR_UI::save_state), string(""))));
save_item = session_items.back();
save_item->set_sensitive (false);
session_items.push_back (MenuElem (_("Snapshot"), slot (*this, &ARDOUR_UI::snapshot_session)));
snapshot_item = session_items.back();
snapshot_item->set_sensitive (false);
/*
session_items.push_back (MenuElem (_("Save as...")));
save_as_item = session_items.back();
save_as_item->set_sensitive (false);
*/
session_items.push_back (MenuElem (_("Save Template..."), slot (*this, &ARDOUR_UI::save_template)));
save_template_item = session_items.back();
save_template_item->set_sensitive (false);
Menu *export_menu = manage (new Menu);
MenuList& export_items = export_menu->items();
export_menu->set_name ("ArdourContextMenu");
export_items.push_back (MenuElem (_("Export session to audiofile..."), slot (*editor, &PublicEditor::export_session)));
export_items.push_back (MenuElem (_("Export range to audiofile..."), slot (*editor, &PublicEditor::export_selection)));
// export_items.back()->set_sensitive (false);
session_items.push_back (MenuElem (_("Export"), *export_menu));
export_item = session_items.back();
export_item->set_sensitive (false);
session_items.push_back (SeparatorElem());
Menu *cleanup_menu = manage (new Menu);
MenuList& cleanup_items = cleanup_menu->items();
cleanup_menu->set_name ("ArdourContextMenu");
cleanup_items.push_back (MenuElem (_("Cleanup unused sources"), slot (*(ARDOUR_UI::instance()), &ARDOUR_UI::cleanup)));
cleanup_items.push_back (MenuElem (_("Flush wastebasket"), slot (*(ARDOUR_UI::instance()), &ARDOUR_UI::flush_trash)));
session_items.push_back (MenuElem (_("Cleanup"), *cleanup_menu));
cleanup_item = session_items.back ();
cleanup_item->set_sensitive (false);
session_items.push_back (SeparatorElem());
session_items.push_back (MenuElem (_("Quit"), slot (*(ARDOUR_UI::instance()), &ARDOUR_UI::finish)));
items.push_back (MenuElem (_("Session"), *session_menu));
/* edit menu; the editor is responsible for the contents */
Menu *edit_menu = manage (new Menu);
editor->set_edit_menu (*edit_menu);
items.push_back (MenuElem (_("Edit"), *edit_menu));
edit_menu->set_name ("ArdourContextMenu");
/* JACK menu for controlling ... JACK */
Menu* jack_menu = manage (new Menu);
MenuList& jack_items = jack_menu->items();
jack_menu->set_name ("ArdourContextMenu");
jack_items.push_back (MenuElem (_("Disconnect"), slot (*(ARDOUR_UI::instance()), &ARDOUR_UI::disconnect_from_jack)));
jack_disconnect_item = jack_items.back();
jack_disconnect_item->set_sensitive (false);
jack_items.push_back (MenuElem (_("Reconnect"), slot (*(ARDOUR_UI::instance()), &ARDOUR_UI::reconnect_to_jack)));
jack_reconnect_item = jack_items.back();
jack_reconnect_item->set_sensitive (false);
jack_bufsize_menu = manage (new Menu);
MenuList& jack_bufsize_items = jack_bufsize_menu->items();
jack_bufsize_menu->set_name ("ArdourContextMenu");
jack_bufsize_items.push_back (MenuElem (X_("32"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 32)));
jack_bufsize_items.push_back (MenuElem (X_("64"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 64)));
jack_bufsize_items.push_back (MenuElem (X_("128"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 128)));
jack_bufsize_items.push_back (MenuElem (X_("256"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 256)));
jack_bufsize_items.push_back (MenuElem (X_("512"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 512)));
jack_bufsize_items.push_back (MenuElem (X_("1024"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 1024)));
jack_bufsize_items.push_back (MenuElem (X_("2048"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 2048)));
jack_bufsize_items.push_back (MenuElem (X_("4096"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 4096)));
jack_bufsize_items.push_back (MenuElem (X_("8192"), bind (slot (*this, &ARDOUR_UI::set_jack_buffer_size), (jack_nframes_t) 8192)));
jack_items.push_back (MenuElem (_("Latency"), *jack_bufsize_menu));
jack_bufsize_menu->set_sensitive (false);
items.push_back (MenuElem (_("JACK"), *jack_menu));
/* windows menu */
Menu *window_menu = new Menu();
MenuList& window_items = window_menu->items();
window_menu->set_name ("ArdourContextMenu");
window_items.push_back (TearoffMenuElem());
window_items.push_back (MenuElem (_("Editor"), slot (*this, &ARDOUR_UI::goto_editor_window)));
window_items.push_back (MenuElem (_("Mixer"), slot (*this, &ARDOUR_UI::goto_mixer_window)));
window_items.push_back (SeparatorElem());
window_items.push_back
(CheckMenuElem
(_("Options Editor"),
slot (*this, &ARDOUR_UI::toggle_options_window)));
options_window_check = dynamic_cast<CheckMenuItem*>(window_items.back());
// options_window_check->set_sensitive (false);
window_items.push_back
(CheckMenuElem
(_("Audio Library"),
slot (*this, &ARDOUR_UI::toggle_sfdb_window)));
sfdb_check = dynamic_cast<CheckMenuItem*>(window_items.back());
window_items.push_back
(CheckMenuElem
(_("Track/Bus Inspector"),
slot (*this, &ARDOUR_UI::toggle_route_params_window)));
route_params_check = dynamic_cast<CheckMenuItem*>(window_items.back());
route_params_check->set_sensitive (false);
window_items.push_back
(CheckMenuElem
(_("Connections"),
slot (*this, &ARDOUR_UI::toggle_connection_editor)));
connection_editor_check = dynamic_cast<CheckMenuItem*>(window_items.back());
connection_editor_check->set_sensitive (false);
#if 0
window_items.push_back
(CheckMenuElem
(_("Meter Bridge"),
slot (*this, &ARDOUR_UI::toggle_meter_bridge_window)));
meter_bridge_dialog_check = dynamic_cast<CheckMenuItem*>(window_items.back());
meter_bridge_dialog_check->set_sensitive (false);
#endif
window_items.push_back
(CheckMenuElem
(_("Locations"),
slot (*this, &ARDOUR_UI::toggle_location_window)));
locations_dialog_check = dynamic_cast<CheckMenuItem*>(window_items.back());
locations_dialog_check->set_sensitive (false);
window_items.push_back
(CheckMenuElem
(_("Big Clock"),
slot (*this, &ARDOUR_UI::toggle_big_clock_window)));
big_clock_check = dynamic_cast<CheckMenuItem*>(window_items.back());
window_items.push_back (SeparatorElem());
window_items.push_back (MenuElem (_("About"), slot (*this, &ARDOUR_UI::show_splash)));
items.push_back (MenuElem (_("Windows"), *window_menu));
wall_clock_box.add (wall_clock_label);
wall_clock_box.set_name ("WallClock");
wall_clock_label.set_name ("WallClock");
disk_space_box.add (disk_space_label);
disk_space_box.set_name ("WallClock");
disk_space_label.set_name ("WallClock");
cpu_load_box.add (cpu_load_label);
cpu_load_box.set_name ("CPULoad");
cpu_load_label.set_name ("CPULoad");
buffer_load_box.add (buffer_load_label);
buffer_load_box.set_name ("BufferLoad");
buffer_load_label.set_name ("BufferLoad");
// disk_rate_box.add (disk_rate_label);
// disk_rate_box.set_name ("DiskRate");
// disk_rate_label.set_name ("DiskRate");
sample_rate_box.add (sample_rate_label);
sample_rate_box.set_name ("SampleRate");
sample_rate_label.set_name ("SampleRate");
menu_hbox.pack_start (menu_bar, true, true);
menu_hbox.pack_end (wall_clock_box, false, false, 10);
menu_hbox.pack_end (disk_space_box, false, false, 10);
menu_hbox.pack_end (cpu_load_box, false, false, 10);
// menu_hbox.pack_end (disk_rate_box, false, false, 10);
menu_hbox.pack_end (buffer_load_box, false, false, 10);
menu_hbox.pack_end (sample_rate_box, false, false, 10);
menu_bar_base.set_name ("MainMenuBar");
menu_bar_base.add (menu_hbox);
}
void
ARDOUR_UI::editor_display_control_changed (Editing::DisplayControl c)
{
switch (c) {
case Editing::FollowPlayhead:
follow_button.set_active (editor->follow_playhead ());
break;
default:
break;
}
}

View File

@@ -0,0 +1,45 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
/* This file contains any ARDOUR_UI methods that require knowledge of
the mixer, and exists so that no compilation dependency exists
between the main ARDOUR_UI modules and the mixer classes. This
is to cut down on the nasty compile times for these classes.
*/
#include "ardour_ui.h"
#include "mixer_ui.h"
using namespace ARDOUR;
int
ARDOUR_UI::create_mixer ()
{
try {
mixer = new Mixer_UI (*engine);
}
catch (failed_constructor& err) {
return -1;
}
return 0;
}

9
gtk2_ardour/arprof Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
if [ gprofhelper.c -nt gprofhelper.so ] ; then
echo "Recompiling gprof helper ..."
gcc -shared -nostdlib -fPIC gprofhelper.c -o gprofhelper.so -lpthread -ldl || exit 1
fi
export LD_LIBRARY_PATH=../libs/ardour/.libs
LDPRELOAD=./gprofhelper.so ./ardour $*

4
gtk2_ardour/arval Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
export LD_LIBRARY_PATH=../libs/ardour
exec valgrind --num-callers=12 --tool=memcheck ./ardour.bin --novst $*

1698
gtk2_ardour/audio_clock.cc Normal file

File diff suppressed because it is too large Load Diff

176
gtk2_ardour/audio_clock.h Normal file
View File

@@ -0,0 +1,176 @@
/*
Copyright (C) 1999 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __audio_clock_h__
#define __audio_clock_h__
#include <gtk--.h>
#include <ardour/ardour.h>
namespace ARDOUR {
class Session;
};
class AudioClock : public Gtk::HBox
{
public:
enum Mode {
SMPTE,
BBT,
MinSec,
Frames,
Off,
};
AudioClock (const string& name, bool editable, bool is_duration = false, bool with_tempo_meter = false);
Mode mode() const { return _mode; }
void set (jack_nframes_t, bool force = false);
void set_mode (Mode);
jack_nframes_t current_time (jack_nframes_t position = 0) const;
jack_nframes_t current_duration (jack_nframes_t position = 0) const;
void set_session (ARDOUR::Session *s);
SigC::Signal0<void> ValueChanged;
private:
ARDOUR::Session *session;
Mode _mode;
uint32_t key_entry_state;
bool is_duration;
bool editable;
Gtk::Menu *ops_menu;
Gtk::HBox smpte_packer_hbox;
Gtk::HBox smpte_packer;
Gtk::HBox minsec_packer_hbox;
Gtk::HBox minsec_packer;
Gtk::HBox bbt_packer_hbox;
Gtk::HBox bbt_packer;
Gtk::HBox frames_packer_hbox;
enum Field {
SMPTE_Hours,
SMPTE_Minutes,
SMPTE_Seconds,
SMPTE_Frames,
MS_Hours,
MS_Minutes,
MS_Seconds,
Bars,
Beats,
Ticks,
AudioFrames,
};
Gtk::EventBox audio_frames_ebox;
Gtk::Label audio_frames_label;
Gtk::EventBox hours_ebox;
Gtk::EventBox minutes_ebox;
Gtk::EventBox seconds_ebox;
Gtk::EventBox frames_ebox;
Gtk::EventBox ms_hours_ebox;
Gtk::EventBox ms_minutes_ebox;
Gtk::EventBox ms_seconds_ebox;
Gtk::EventBox bars_ebox;
Gtk::EventBox beats_ebox;
Gtk::EventBox ticks_ebox;
Gtk::Label hours_label;
Gtk::Label minutes_label;
Gtk::Label seconds_label;
Gtk::Label frames_label;
Gtk::Label colon1, colon2, colon3;
Gtk::Label ms_hours_label;
Gtk::Label ms_minutes_label;
Gtk::Label ms_seconds_label;
Gtk::Label colon4, colon5;
Gtk::Label bars_label;
Gtk::Label beats_label;
Gtk::Label ticks_label;
Gtk::Label b1;
Gtk::Label b2;
Gtk::Label* tempo_label;
Gtk::Label* meter_label;
Gtk::VBox tempo_meter_box;
Gtk::EventBox clock_base;
Gtk::Frame clock_frame;
jack_nframes_t last_when;
long last_hrs;
long last_mins;
long last_secs;
long last_frames;
bool last_negative;
long ms_last_hrs;
long ms_last_mins;
float ms_last_secs;
bool dragging;
double drag_start_y;
double drag_y;
double drag_accum;
void realize_impl ();
gint field_motion_notify_event (GdkEventMotion *ev, Field);
gint field_button_press_event (GdkEventButton *ev, Field);
gint field_button_release_event (GdkEventButton *ev, Field);
gint field_key_release_event (GdkEventKey *, Field);
gint field_focus_in_event (GdkEventFocus *, Field);
gint field_focus_out_event (GdkEventFocus *, Field);
void set_smpte (jack_nframes_t, bool);
void set_bbt (jack_nframes_t, bool);
void set_minsec (jack_nframes_t, bool);
void set_frames (jack_nframes_t, bool);
jack_nframes_t get_frames (Field,jack_nframes_t pos = 0,int dir=1);
void smpte_sanitize_display();
jack_nframes_t smpte_frame_from_display () const;
jack_nframes_t bbt_frame_from_display (jack_nframes_t) const;
jack_nframes_t bbt_frame_duration_from_display (jack_nframes_t) const;
jack_nframes_t minsec_frame_from_display () const;
jack_nframes_t audio_frame_from_display () const;
void build_ops_menu ();
void setup_events ();
static const uint32_t field_length[(int)AudioFrames+1];
};
#endif /* __audio_clock_h__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,331 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_trackview_h__
#define __ardour_trackview_h__
#include <gtk--.h>
#include <gtk-canvas.h>
#include <gtkmmext/selector.h>
#include <gtkmmext/popup_selector.h>
#include <list>
#include <ardour/types.h>
#include <ardour/region.h>
#include "ardour_dialog.h"
#include "route_ui.h"
#include "enums.h"
#include "time_axis_view.h"
namespace ALSA {
class MultiChannelDevice;
}
namespace ARDOUR {
class Session;
class DiskStream;
class RouteGroup;
class Redirect;
class Insert;
class Location;
class AudioPlaylist;
}
namespace LADSPA {
class Manager;
class Plugin;
}
class PublicEditor;
class AudioThing;
class StreamView;
class Selection;
class Selectable;
class AudioRegionView;
class AutomationLine;
class AutomationGainLine;
class AutomationPanLine;
class RedirectAutomationLine;
class TimeSelection;
class AutomationTimeAxisView;
class AudioTimeAxisView : public RouteUI, public TimeAxisView
{
public:
AudioTimeAxisView (PublicEditor&, ARDOUR::Session&, ARDOUR::Route&, Gtk::Widget *canvas);
virtual ~AudioTimeAxisView ();
void show_selection (TimeSelection&);
void automation_control_point_changed (ARDOUR::AutomationType);
void set_samples_per_unit (double);
void set_height (TimeAxisView::TrackHeight);
void set_show_waveforms (bool yn);
void set_show_waveforms_recording (bool yn);
void show_timestretch (jack_nframes_t start, jack_nframes_t end);
void hide_timestretch ();
void selection_click (GdkEventButton*);
void set_selected_regionviews (AudioRegionSelection&);
void set_selected_points (PointSelection&);
void get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable *>&);
void get_inverted_selectables (Selection&, list<Selectable*>&);
void show_all_xfades ();
void hide_all_xfades ();
void hide_dependent_views (TimeAxisViewItem&);
void reveal_dependent_views (TimeAxisViewItem&);
ARDOUR::Region* find_next_region (jack_nframes_t pos, ARDOUR::RegionPoint, int32_t dir);
string name() const;
ARDOUR::RouteGroup* edit_group() const;
void build_playlist_menu (Gtk::Menu *);
ARDOUR::Playlist* playlist() const;
/* overridden from parent to store display state */
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
void hide ();
/* need accessors/mutators */
StreamView *view;
/* editing operations */
bool cut_copy_clear (Selection&, Editing::CutCopyOp);
bool paste (jack_nframes_t, float times, Selection&, size_t nth);
list<TimeAxisView*>get_child_list();
void set_state (const XMLNode&);
XMLNode* get_child_xml_node (std::string childname);
private:
friend class StreamView;
friend class AudioRegionView;
Gtk::Widget* parent_canvas;
bool no_redraw;
AutomationTimeAxisView *gain_track;
AutomationTimeAxisView *pan_track;
void update_automation_view (ARDOUR::AutomationType);
void reset_redirect_automation_curves ();
Gtk::HBox other_button_hbox;
Gtk::Table button_table;
Gtk::Button redirect_button;
Gtk::Button edit_group_button;
Gtk::Button playlist_button;
Gtk::Button size_button;
Gtk::Button automation_button;
Gtk::Button hide_button;
Gtk::Button visual_button;
void route_active_changed ();
void diskstream_changed (void *src);
void update_diskstream_display ();
gint edit_click (GdkEventButton *);
/* Redirect handling */
ArdourDialog redirect_window;
Gtk::CList redirect_display;
Gtk::Button redirect_add_button;
Gtk::Button redirect_remove_button;
Gtk::Button redirect_up_button;
Gtk::Button redirect_down_button;
Gtk::Button redirect_edit_button;
Gtk::HBox redirect_button_box;
Gtk::VBox redirect_vpacker;
Gtk::HBox redirect_display_hpacker;
int redirect_selected_row;
// variables to get the context menu
// automation buttons correctly initialized
bool show_gain_automation;
bool show_pan_automation;
void build_redirect_window ();
void redirect_click ();
void redirect_add ();
void redirect_remove ();
void redirect_edit ();
void redirect_relist ();
void redirect_row_selected (gint row, gint col, GdkEvent *ev);
void add_to_redirect_display (ARDOUR::Redirect *);
void redirects_changed (void *);
SigC::Connection modified_connection;
SigC::Connection state_changed_connection;
void take_name_changed (void *);
void route_name_changed (void *);
void name_entry_activated ();
void name_entry_changed ();
gint name_entry_focus_out_handler (GdkEventFocus*);
gint name_entry_key_release_handler (GdkEventKey*);
gint name_entry_button_release_handler (GdkEventButton*);
gint name_entry_button_press_handler (GdkEventButton*);
void on_area_realize ();
virtual void label_view ();
Gtk::Menu edit_group_menu;
Gtk::RadioMenuItem::Group edit_group_menu_radio_group;
void add_edit_group_menu_item (ARDOUR::RouteGroup *);
void set_edit_group_from_menu (ARDOUR::RouteGroup *);
void reset_samples_per_unit ();
void select_track_color();
virtual void build_display_menu ();
Gtk::CheckMenuItem* waveform_item;
Gtk::RadioMenuItem* traditional_item;
Gtk::RadioMenuItem* rectified_item;
Gtk::RadioMenuItem* align_existing_item;
Gtk::RadioMenuItem* align_capture_item;
void align_style_changed ();
void set_align_style (ARDOUR::AlignStyle);
void toggle_show_waveforms ();
void set_waveform_shape (WaveformShape);
void toggle_waveforms ();
Gtk::Menu *playlist_menu;
Gtk::Menu *playlist_action_menu;
Gtk::MenuItem *playlist_item;
/* playlist */
void set_playlist (ARDOUR::AudioPlaylist *);
void playlist_click ();
void show_playlist_selector ();
void playlist_changed ();
void playlist_state_changed (ARDOUR::Change);
void playlist_modified ();
void add_playlist_to_playlist_menu (ARDOUR::Playlist*);
void playlist_selected (ARDOUR::AudioPlaylist*);
void use_new_playlist ();
void use_copy_playlist ();
void clear_playlist ();
void rename_current_playlist ();
/* automation stuff */
Gtk::Menu* automation_action_menu;
Gtk::CheckMenuItem* gain_automation_item;
Gtk::CheckMenuItem* pan_automation_item;
void automation_click ();
void clear_automation ();
void hide_all_automation ();
void show_all_automation ();
void show_existing_automation ();
struct RedirectAutomationNode {
uint32_t what;
Gtk::CheckMenuItem* menu_item;
AutomationTimeAxisView* view;
AudioTimeAxisView& parent;
RedirectAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, AudioTimeAxisView& p)
: what (w), menu_item (mitem), view (0), parent (p) {}
~RedirectAutomationNode ();
};
struct RedirectAutomationInfo {
ARDOUR::Redirect* redirect;
bool valid;
Gtk::Menu* menu;
vector<RedirectAutomationNode*> lines;
RedirectAutomationInfo (ARDOUR::Redirect* r)
: redirect (r), valid (true) {}
~RedirectAutomationInfo ();
};
list<RedirectAutomationInfo*> redirect_automation;
RedirectAutomationNode* find_redirect_automation_node (ARDOUR::Redirect *redirect, uint32_t what);
Gtk::Menu subplugin_menu;
void add_redirect_to_subplugin_menu (ARDOUR::Redirect *);
void remove_ran (RedirectAutomationNode* ran);
void redirect_menu_item_toggled (AudioTimeAxisView::RedirectAutomationInfo*,
AudioTimeAxisView::RedirectAutomationNode*);
void redirect_automation_track_hidden (RedirectAutomationNode*, ARDOUR::Redirect*);
vector<RedirectAutomationLine*> redirect_automation_curves;
RedirectAutomationLine *find_redirect_automation_curve (ARDOUR::Redirect*,uint32_t);
void add_redirect_automation_curve (ARDOUR::Redirect*, uint32_t);
void add_existing_redirect_automation_curves (ARDOUR::Redirect*);
GtkCanvasItem *timestretch_rect;
void timestretch (jack_nframes_t start, jack_nframes_t end);
void visual_click ();
void hide_click ();
gint when_displayed (GdkEventAny*);
void speed_changed ();
void add_gain_automation_child ();
void add_pan_automation_child ();
void add_parameter_automation_child ();
void toggle_gain_track ();
void toggle_pan_track ();
void gain_hidden ();
void pan_hidden ();
void update_pans ();
void region_view_added (AudioRegionView*);
void add_ghost_to_redirect (AudioRegionView*, AutomationTimeAxisView*);
void map_frozen ();
};
#endif /* __ardour_trackview_h__ */

View File

@@ -0,0 +1,60 @@
/*
Copyright (C) 2000-2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <sigc++/signal_system.h>
#include <ardour/curve.h>
#include <pbd/fastlog.h>
#include "public_editor.h"
#include "automation_gain_line.h"
#include "utils.h"
#include <ardour/session.h>
using namespace std;
using namespace ARDOUR;
AutomationGainLine::AutomationGainLine (string name, Session& s, TimeAxisView& tv, GtkCanvasItem* parent,
Curve& c,
gint (*point_callback)(GtkCanvasItem*, GdkEvent*, gpointer),
gint (*line_callback)(GtkCanvasItem*, GdkEvent*, gpointer))
: AutomationLine (name, tv, parent, c, point_callback, line_callback),
session (s)
{
set_verbose_cursor_uses_gain_mapping (true);
}
void
AutomationGainLine::view_to_model_y (double& y)
{
y = slider_position_to_gain (y);
y = max (0.0, y);
y = min (2.0, y);
}
void
AutomationGainLine::model_to_view_y (double& y)
{
y = gain_to_slider_position (y);
}

View File

@@ -0,0 +1,36 @@
#ifndef __ardour_gtk_automation_gain_line_h__
#define __ardour_gtk_automation_gain_line_h__
#include <ardour/ardour.h>
#include <gtk-canvas.h>
#include <gtk--.h>
#include "automation_line.h"
namespace ARDOUR {
class Session;
}
class TimeAxisView;
class AutomationGainLine : public AutomationLine
{
public:
AutomationGainLine (string name, ARDOUR::Session&, TimeAxisView&, GtkCanvasItem* parent,
ARDOUR::Curve&,
gint (*point_callback)(GtkCanvasItem*, GdkEvent*, gpointer),
gint (*line_callback)(GtkCanvasItem*, GdkEvent*, gpointer));
void view_to_model_y (double&);
void model_to_view_y (double&);
private:
ARDOUR::Session& session;
};
#endif /* __ardour_gtk_automation_gain_line_h__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,223 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_automation_line_h__
#define __ardour_automation_line_h__
#include <vector>
#include <list>
#include <string>
#include <sys/types.h>
#include <gtk--.h>
#include <gtk-canvas.h>
#include <sigc++/signal_system.h>
#include <pbd/undo.h>
#include <ardour/automation_event.h>
using std::vector;
using std::string;
class AutomationLine;
class ControlPoint;
class PointSelection;
class TimeAxisView;
class AutomationTimeAxisView;
class Selectable;
class Selection;
class ControlPoint
{
public:
ControlPoint (AutomationLine& al, gint (*event_handler)(GtkCanvasItem*, GdkEvent*, gpointer));
ControlPoint (const ControlPoint&, bool dummy_arg_to_force_special_copy_constructor);
~ControlPoint ();
enum ShapeType {
Full,
Start,
End
};
void move_to (double x, double y, ShapeType);
void reset (double x, double y, ARDOUR::AutomationList::iterator, uint32_t, ShapeType);
double get_x() const { return _x; }
double get_y() const { return _y; }
void hide ();
void show ();
void show_color (bool entered, bool hide_too);
void set_size (double);
void set_visible (bool);
GtkCanvasItem* item;
AutomationLine& line;
uint32_t view_index;
ARDOUR::AutomationList::iterator model;
bool can_slide;
bool selected;
private:
double _x;
double _y;
double _size;
ShapeType _shape;
};
class AutomationLine : public SigC::Object
{
public:
AutomationLine (string name, TimeAxisView&, GtkCanvasItem *, ARDOUR::AutomationList&,
gint (*point_event_handler)(GtkCanvasItem*, GdkEvent*, gpointer),
gint (*line_event_handler)(GtkCanvasItem*, GdkEvent*, gpointer));
virtual ~AutomationLine ();
void queue_reset ();
void reset ();
void clear();
void set_selected_points (PointSelection&);
void get_selectables (jack_nframes_t& start, jack_nframes_t& end,
double botfrac, double topfrac,
list<Selectable*>& results);
void get_inverted_selectables (Selection&, list<Selectable*>& results);
virtual void remove_point (ControlPoint&);
bool control_points_adjacent (double xval, uint32_t& before, uint32_t& after);
/* dragging API */
virtual void start_drag (ControlPoint*, float fraction);
virtual void point_drag(ControlPoint&, jack_nframes_t x, float, bool with_push);
virtual void end_drag (ControlPoint*);
virtual void line_drag(uint32_t i1, uint32_t i2, float, bool with_push);
ControlPoint* nth (uint32_t);
uint32_t npoints() const { return control_points.size(); }
string name() const { return _name; }
bool visible() const { return _visible; }
guint32 height() const { return _height; }
void set_line_color (uint32_t);
uint32_t get_line_color() const { return _line_color; }
void show ();
void hide ();
void set_height (guint32);
void set_verbose_cursor_uses_gain_mapping (bool yn);
TimeAxisView& trackview;
GtkCanvasGroup* canvas_group() const { return GTK_CANVAS_GROUP(group); }
GtkCanvasItem* parent_group() const { return _parent_group; }
GtkCanvasItem* grab_item() const { return line; }
void show_selection();
void hide_selection ();
void set_point_size (double size);
static void invalidate_point (GtkCanvasPoints*, uint32_t index);
static bool invalid_point (GtkCanvasPoints*, uint32_t index);
virtual string get_verbose_cursor_string (float);
virtual void view_to_model_y (double&) = 0;
virtual void model_to_view_y (double&) = 0;
ARDOUR::AutomationList& the_list() const { return alist; }
void show_all_control_points ();
void hide_all_but_selected_control_points ();
bool is_last_point (ControlPoint &);
bool is_first_point (ControlPoint &);
protected:
string _name;
guint32 _height;
uint32_t _line_color;
ARDOUR::AutomationList& alist;
bool _visible : 1;
bool _vc_uses_gain_mapping : 1;
bool terminal_points_can_slide : 1;
bool update_pending : 1;
bool no_draw : 1;
bool points_visible : 1;
GtkCanvasItem* _parent_group;
GtkCanvasItem* group;
GtkCanvasItem* line; /* line */
GtkCanvasPoints* point_coords; /* coordinates for canvas line */
vector<ControlPoint*> control_points; /* visible control points */
gint (*point_callback)(GtkCanvasItem*, GdkEvent*, gpointer);
void determine_visible_control_points (GtkCanvasPoints*);
void sync_model_from (ControlPoint&);
void sync_model_with_view_point (ControlPoint&);
void sync_model_with_view_line (uint32_t, uint32_t);
void modify_view (ControlPoint&, double, double, bool with_push);
virtual void change_model (ARDOUR::AutomationList::iterator, double x, double y);
virtual void change_model_range (ARDOUR::AutomationList::iterator,ARDOUR::AutomationList::iterator, double delta, float ydelta);
void reset_callback (const ARDOUR::AutomationList&);
void list_changed (ARDOUR::Change);
UndoAction get_memento();
private:
uint32_t drags;
double first_drag_fraction;
double last_drag_fraction;
uint32_t line_drag_cp1;
uint32_t line_drag_cp2;
void modify_view_point(ControlPoint&, double, double, bool with_push);
void reset_line_coords (ControlPoint&);
void update_line ();
struct ModelRepresentation {
ARDOUR::AutomationList::iterator start;
ARDOUR::AutomationList::iterator end;
jack_nframes_t xpos;
double ypos;
jack_nframes_t xmin;
double ymin;
jack_nframes_t xmax;
double ymax;
jack_nframes_t xval;
double yval;
};
void model_representation (ControlPoint&, ModelRepresentation&);
friend class AudioRegionGainLine;
};
#endif /* __ardour_automation_line_h__ */

View File

@@ -0,0 +1,57 @@
/*
Copyright (C) 2000-2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <sigc++/signal_system.h>
#include <ardour/curve.h>
#include "public_editor.h"
#include "automation_pan_line.h"
#include "utils.h"
#include <cmath>
#include <ardour/session.h>
using namespace ARDOUR;
AutomationPanLine::AutomationPanLine (string name, Session& s, TimeAxisView& tv, GtkCanvasItem* parent,
Curve& c,
gint (*point_callback)(GtkCanvasItem*, GdkEvent*, gpointer),
gint (*line_callback)(GtkCanvasItem*, GdkEvent*, gpointer))
: AutomationLine (name, tv, parent, c, point_callback, line_callback),
session (s)
{
}
void
AutomationPanLine::view_to_model_y (double& y)
{
// vertical coordinate axis reversal
y = 1.0 - y;
}
void
AutomationPanLine::model_to_view_y (double& y)
{
// vertical coordinate axis reversal
y = 1.0 - y;
}

View File

@@ -0,0 +1,35 @@
#ifndef __ardour_gtk_automation_pan_line_h__
#define __ardour_gtk_automation_pan_line_h__
#include <ardour/ardour.h>
#include <gtk-canvas.h>
#include <gtk--.h>
#include "automation_line.h"
namespace ARDOUR {
class Session;
}
class TimeAxisView;
class AutomationPanLine : public AutomationLine
{
public:
AutomationPanLine (string name, ARDOUR::Session&, TimeAxisView&, GtkCanvasItem* parent,
ARDOUR::Curve&,
gint (*point_callback)(GtkCanvasItem*, GdkEvent*, gpointer),
gint (*line_callback)(GtkCanvasItem*, GdkEvent*, gpointer));
void view_to_model_y (double&);
void model_to_view_y (double&);
private:
ARDOUR::Session& session;
vector<GtkCanvasItem*> lines;
};
#endif /* __ardour_gtk_automation_pan_line_h__ */

View File

@@ -0,0 +1,21 @@
#ifndef __ardour_gtk_automation_selectable_h__
#define __ardour_gtk_automation_selectable_h__
#include <ardour/types.h>
#include "selectable.h"
class TimeAxisView;
struct AutomationSelectable : public Selectable
{
jack_nframes_t start;
jack_nframes_t end;
double low_fract;
double high_fract;
TimeAxisView& track;
AutomationSelectable (jack_nframes_t s, jack_nframes_t e, double l, double h, TimeAxisView& atv)
: start (s), end (e), low_fract (l), high_fract (h), track (atv) {}
};
#endif /* __ardour_gtk_automation_selectable_h__ */

View File

@@ -0,0 +1,12 @@
#ifndef __ardour_gtk_automation_selection_h__
#define __ardour_gtk_automation_selection_h__
#include <list>
namespace ARDOUR {
class AutomationList;
}
struct AutomationSelection : list<ARDOUR::AutomationList*> {};
#endif /* __ardour_gtk_automation_selection_h__ */

View File

@@ -0,0 +1,796 @@
#include <ardour/route.h>
#include "ardour_ui.h"
#include "automation_time_axis.h"
#include "automation_line.h"
#include "public_editor.h"
#include "canvas-simplerect.h"
#include "canvas-waveview.h"
#include "selection.h"
#include "ghostregion.h"
#include "rgb_macros.h"
#include "automation_selectable.h"
#include "point_selection.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace Gtk;
using namespace Editing;
static const gchar * small_x_xpm[] = {
"11 11 2 1",
" c None",
". c #000000",
" ",
" ",
" . . ",
" . . ",
" . . ",
" . ",
" . . ",
" . . ",
" . . ",
" ",
" "};
AutomationTimeAxisView::AutomationTimeAxisView (Session& s, Route& r, PublicEditor& e, TimeAxisView& rent, Widget* p, std::string nom, std::string state_name, std::string nomparent)
: AxisView (s),
TimeAxisView (s, e, &rent, p),
route (r),
_name (nom),
_state_name (state_name),
height_button (_("h")),
clear_button (_("clear")),
auto_button (X_("")) /* force addition of a label */
{
automation_menu = 0;
in_destructor = false;
auto_off_item = 0;
auto_touch_item = 0;
auto_write_item = 0;
auto_play_item = 0;
ignore_state_request = false;
base_rect = gtk_canvas_item_new (GTK_CANVAS_GROUP(canvas_display),
gtk_canvas_simplerect_get_type(),
"x1", 0.0,
"y1", 0.0,
"x2", 1000000.0,
"outline_color_rgba", color_map[cAutomationTrackOutline],
/* outline ends and bottom */
"outline_what", (guint32) (0x1|0x2|0x8),
"fill_color_rgba", color_map[cAutomationTrackFill],
NULL);
gtk_object_set_data (GTK_OBJECT(base_rect), "trackview", this);
gtk_signal_connect (GTK_OBJECT(base_rect), "event",
(GtkSignalFunc) PublicEditor::canvas_automation_track_event,
this);
hide_button.add (*(manage (new Pixmap (small_x_xpm))));
height_button.set_name ("TrackSizeButton");
auto_button.set_name ("TrackVisualButton");
clear_button.set_name ("TrackVisualButton");
hide_button.set_name ("TrackRemoveButton");
ARDOUR_UI::instance()->tooltips().set_tip(height_button, _("track height"));
ARDOUR_UI::instance()->tooltips().set_tip(auto_button, _("automation state"));
ARDOUR_UI::instance()->tooltips().set_tip(clear_button, _("clear track"));
ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("hide track"));
/* rearrange the name display */
/* we never show these for automation tracks, so make
life easier and remove them.
*/
name_hbox.remove (name_entry);
/* move the name label over a bit */
string shortpname = _name;
bool shortened = false;
if (_name.length()) {
if (shortpname.length() > 18) {
shortpname = shortpname.substr (0, 16);
shortpname += "...";
shortened = true;
}
}
name_label.set_text (shortpname);
name_label.set_alignment (1.0, 0.5);
if (nomparent.length()) {
/* limit the plug name string */
string pname = nomparent;
if (pname.length() > 14) {
pname = pname.substr (0, 11);
pname += "...";
shortened = true;
}
plugname = new Label (pname);
plugname->set_name (X_("TrackPlugName"));
plugname->set_alignment (1.0, 0.5);
name_label.set_name (X_("TrackParameterName"));
controls_table.remove (name_hbox);
controls_table.attach (*plugname, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
plugname_packed = true;
controls_table.attach (name_hbox, 1, 6, 1, 2, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
} else {
plugname = 0;
plugname_packed = false;
}
if (shortened) {
string tipname = nomparent;
if (!tipname.empty()) {
tipname += ": ";
}
tipname += _name;
ARDOUR_UI::instance()->tooltips().set_tip(controls_ebox, tipname);
}
/* add the buttons */
controls_table.attach (hide_button, 0, 1, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
controls_table.attach (height_button, 0, 1, 1, 2, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
controls_table.attach (auto_button, 7, 9, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
controls_table.attach (clear_button, 7, 9, 1, 2, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
controls_table.show_all ();
height_button.clicked.connect (slot (*this, &AutomationTimeAxisView::height_clicked));
clear_button.clicked.connect (slot (*this, &AutomationTimeAxisView::clear_clicked));
hide_button.clicked.connect (slot (*this, &AutomationTimeAxisView::hide_clicked));
auto_button.clicked.connect (slot (*this, &AutomationTimeAxisView::auto_clicked));
controls_base_selected_name = X_("AutomationTrackControlsBaseSelected");
controls_base_unselected_name = X_("AutomationTrackControlsBase");
controls_ebox.set_name (controls_base_unselected_name);
controls_frame.set_shadow_type (GTK_SHADOW_ETCHED_OUT);
XMLNode* xml_node = get_parent_with_state()->get_child_xml_node (_state_name);
set_state (*xml_node);
/* make sure labels etc. are correct */
automation_state_changed ();
}
AutomationTimeAxisView::~AutomationTimeAxisView ()
{
in_destructor = true;
for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
delete *i;
}
}
void
AutomationTimeAxisView::auto_clicked ()
{
using namespace Menu_Helpers;
if (automation_menu == 0) {
automation_menu = manage (new Menu);
automation_menu->set_name ("ArdourContextMenu");
MenuList& items (automation_menu->items());
items.push_back (MenuElem (_("off"),
bind (slot (*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
items.push_back (MenuElem (_("play"),
bind (slot (*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
items.push_back (MenuElem (_("write"),
bind (slot (*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
items.push_back (MenuElem (_("touch"),
bind (slot (*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
}
automation_menu->popup (1, 0);
}
void
AutomationTimeAxisView::automation_state_changed ()
{
AutoState state;
/* update button label */
if (lines.empty()) {
state = Off;
} else {
state = lines.front()->the_list().automation_state ();
}
switch (state & (Off|Play|Touch|Write)) {
case Off:
static_cast<Gtk::Label*>(auto_button.get_child())->set_text (_("off"));
if (auto_off_item) {
ignore_state_request = true;
auto_off_item->set_active (true);
auto_play_item->set_active (false);
auto_touch_item->set_active (false);
auto_write_item->set_active (false);
ignore_state_request = false;
}
break;
case Play:
static_cast<Gtk::Label*>(auto_button.get_child())->set_text (_("play"));
if (auto_play_item) {
ignore_state_request = true;
auto_play_item->set_active (true);
auto_off_item->set_active (false);
auto_touch_item->set_active (false);
auto_write_item->set_active (false);
ignore_state_request = false;
}
break;
case Write:
static_cast<Gtk::Label*>(auto_button.get_child())->set_text (_("write"));
if (auto_write_item) {
ignore_state_request = true;
auto_write_item->set_active (true);
auto_off_item->set_active (false);
auto_play_item->set_active (false);
auto_touch_item->set_active (false);
ignore_state_request = false;
}
break;
case Touch:
static_cast<Gtk::Label*>(auto_button.get_child())->set_text (_("touch"));
if (auto_touch_item) {
ignore_state_request = true;
auto_touch_item->set_active (true);
auto_off_item->set_active (false);
auto_play_item->set_active (false);
auto_write_item->set_active (false);
ignore_state_request = false;
}
break;
default:
static_cast<Gtk::Label*>(auto_button.get_child())->set_text (_("???"));
break;
}
}
void
AutomationTimeAxisView::height_clicked ()
{
popup_size_menu (0);
}
void
AutomationTimeAxisView::clear_clicked ()
{
_session.begin_reversible_command (_("clear automation"));
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->clear ();
}
_session.commit_reversible_command ();
}
void
AutomationTimeAxisView::set_height (TrackHeight h)
{
bool changed = (height != (uint32_t) h);
TimeAxisView* state_parent = get_parent_with_state ();
XMLNode* xml_node = state_parent->get_child_xml_node (_state_name);
controls_table.show_all ();
TimeAxisView::set_height (h);
gtk_object_set (GTK_OBJECT(base_rect), "y2", (double) h, NULL);
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->set_height (h);
}
for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
(*i)->set_height ();
}
switch (height) {
case Largest:
xml_node->add_property ("track_height", "largest");
controls_table.remove (name_hbox);
if (plugname) {
if (plugname_packed) {
controls_table.remove (*plugname);
plugname_packed = false;
}
controls_table.attach (*plugname, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
plugname_packed = true;
controls_table.attach (name_hbox, 1, 6, 1, 2, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
} else {
controls_table.attach (name_hbox, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
}
controls_table.show_all ();
name_label.show ();
break;
case Large:
xml_node->add_property ("track_height", "large");
controls_table.remove (name_hbox);
if (plugname) {
if (plugname_packed) {
controls_table.remove (*plugname);
plugname_packed = false;
}
controls_table.attach (*plugname, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
plugname_packed = true;
} else {
controls_table.attach (name_hbox, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
}
controls_table.show_all ();
name_label.show ();
break;
case Larger:
xml_node->add_property ("track_height", "larger");
controls_table.remove (name_hbox);
if (plugname) {
if (plugname_packed) {
controls_table.remove (*plugname);
plugname_packed = false;
}
controls_table.attach (*plugname, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
plugname_packed = true;
} else {
controls_table.attach (name_hbox, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
}
controls_table.show_all ();
name_label.show ();
break;
case Normal:
xml_node->add_property ("track_height", "normal");
controls_table.remove (name_hbox);
if (plugname) {
if (plugname_packed) {
controls_table.remove (*plugname);
plugname_packed = false;
}
controls_table.attach (*plugname, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
plugname_packed = true;
controls_table.attach (name_hbox, 1, 6, 1, 2, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
} else {
controls_table.attach (name_hbox, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
}
controls_table.show_all ();
name_label.show ();
break;
case Smaller:
xml_node->add_property ("track_height", "smaller");
controls_table.remove (name_hbox);
if (plugname) {
if (plugname_packed) {
controls_table.remove (*plugname);
plugname_packed = false;
}
}
controls_table.attach (name_hbox, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
controls_table.hide_all ();
name_hbox.show_all ();
controls_table.show ();
break;
case Small:
xml_node->add_property ("track_height", "small");
controls_table.remove (name_hbox);
if (plugname) {
if (plugname_packed) {
controls_table.remove (*plugname);
plugname_packed = false;
}
}
controls_table.attach (name_hbox, 1, 6, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND);
controls_table.hide_all ();
name_hbox.show_all ();
controls_table.show ();
break;
}
if (changed) {
/* only emit the signal if the height really changed */
route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
}
}
void
AutomationTimeAxisView::set_samples_per_unit (double spu)
{
TimeAxisView::set_samples_per_unit (editor.get_current_zoom());
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->reset ();
}
}
void
AutomationTimeAxisView::hide_clicked ()
{
set_marked_for_display (false);
hide ();
}
void
AutomationTimeAxisView::build_display_menu ()
{
using namespace Menu_Helpers;
/* get the size menu ready */
build_size_menu ();
/* prepare it */
TimeAxisView::build_display_menu ();
/* now fill it with our stuff */
MenuList& items = display_menu->items();
items.push_back (MenuElem (_("Height"), *size_menu));
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Hide"), slot (*this, &AutomationTimeAxisView::hide_clicked)));
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Clear"), slot (*this, &AutomationTimeAxisView::clear_clicked)));
items.push_back (SeparatorElem());
Menu* auto_state_menu = manage (new Menu);
auto_state_menu->set_name ("ArdourContextMenu");
MenuList& as_items = auto_state_menu->items();
as_items.push_back (CheckMenuElem (_("off"),
bind (slot (*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Off)));
auto_off_item = dynamic_cast<CheckMenuItem*>(as_items.back());
as_items.push_back (CheckMenuElem (_("play"),
bind (slot (*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Play)));
auto_play_item = dynamic_cast<CheckMenuItem*>(as_items.back());
as_items.push_back (CheckMenuElem (_("write"),
bind (slot (*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Write)));
auto_write_item = dynamic_cast<CheckMenuItem*>(as_items.back());
as_items.push_back (CheckMenuElem (_("touch"),
bind (slot (*this, &AutomationTimeAxisView::set_automation_state), (AutoState) Touch)));
auto_touch_item = dynamic_cast<CheckMenuItem*>(as_items.back());
items.push_back (MenuElem (_("State"), *auto_state_menu));
/* make sure the automation menu state is correct */
automation_state_changed ();
}
bool
AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
{
bool ret = false;
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
ret = cut_copy_clear_one ((**i), selection, op);
}
return ret;
}
bool
AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
{
AutomationList* what_we_got = 0;
AutomationList& alist (line.the_list());
bool ret = false;
_session.add_undo (alist.get_memento());
switch (op) {
case Cut:
if ((what_we_got = alist.cut (selection.time.front().start, selection.time.front().end)) != 0) {
editor.get_cut_buffer().add (what_we_got);
_session.add_redo_no_execute (alist.get_memento());
ret = true;
}
break;
case Copy:
if ((what_we_got = alist.copy (selection.time.front().start, selection.time.front().end)) != 0) {
editor.get_cut_buffer().add (what_we_got);
}
break;
case Clear:
if ((what_we_got = alist.cut (selection.time.front().start, selection.time.front().end)) != 0) {
_session.add_redo_no_execute (alist.get_memento());
delete what_we_got;
what_we_got = 0;
ret = true;
}
break;
}
if (what_we_got) {
for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
double foo = (*x)->value;
line.model_to_view_y (foo);
(*x)->value = foo;
}
}
return ret;
}
bool
AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
{
bool ret = false;
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
ret = cut_copy_clear_objects_one ((**i), selection, op);
}
return ret;
}
bool
AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
{
AutomationList* what_we_got = 0;
AutomationList& alist (line.the_list());
bool ret = false;
_session.add_undo (alist.get_memento());
for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
if (&(*i).track != this) {
continue;
}
switch (op) {
case Cut:
if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) {
editor.get_cut_buffer().add (what_we_got);
_session.add_redo_no_execute (alist.get_memento());
ret = true;
}
break;
case Copy:
if ((what_we_got = alist.copy ((*i).start, (*i).end)) != 0) {
editor.get_cut_buffer().add (what_we_got);
}
break;
case Clear:
if ((what_we_got = alist.cut ((*i).start, (*i).end)) != 0) {
_session.add_redo_no_execute (alist.get_memento());
delete what_we_got;
what_we_got = 0;
ret = true;
}
break;
}
}
if (what_we_got) {
for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
double foo = (*x)->value;
line.model_to_view_y (foo);
(*x)->value = foo;
}
}
return ret;
}
bool
AutomationTimeAxisView::paste (jack_nframes_t pos, float times, Selection& selection, size_t nth)
{
bool ret = true;
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
ret = paste_one (**i, pos, times, selection, nth);
}
return ret;
}
bool
AutomationTimeAxisView::paste_one (AutomationLine& line, jack_nframes_t pos, float times, Selection& selection, size_t nth)
{
AutomationSelection::iterator p;
AutomationList& alist (line.the_list());
for (p = selection.lines.begin(); p != selection.lines.end() && nth; ++p, --nth);
if (p == selection.lines.end()) {
return false;
}
/* Make a copy of the list because we have to scale the
values from view coordinates to model coordinates, and we're
not supposed to modify the points in the selection.
*/
AutomationList copy (**p);
for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
double foo = (*x)->value;
line.view_to_model_y (foo);
(*x)->value = foo;
}
_session.add_undo (alist.get_memento());
alist.paste (copy, pos, times);
_session.add_redo_no_execute (alist.get_memento());
return true;
}
void
AutomationTimeAxisView::add_ghost (GhostRegion* gr)
{
ghosts.push_back (gr);
gr->GoingAway.connect (slot (*this, &AutomationTimeAxisView::remove_ghost));
}
void
AutomationTimeAxisView::remove_ghost (GhostRegion* gr)
{
if (in_destructor) {
return;
}
list<GhostRegion*>::iterator i;
for (i = ghosts.begin(); i != ghosts.end(); ++i) {
if ((*i) == gr) {
ghosts.erase (i);
break;
}
}
}
void
AutomationTimeAxisView::get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable*>& results)
{
if (!lines.empty() && touched (top, bot)) {
double topfrac;
double botfrac;
/* remember: this is X Window - coordinate space starts in upper left and moves down.
y_position is the "origin" or "top" of the track.
*/
double mybot = y_position + height; // XXX need to include Editor::track_spacing;
if (y_position >= top && mybot <= bot) {
/* y_position is below top, mybot is above bot, so we're fully
covered vertically.
*/
topfrac = 1.0;
botfrac = 0.0;
} else {
/* top and bot are within y_position .. mybot */
topfrac = 1.0 - ((top - y_position) / height);
botfrac = 1.0 - ((bot - y_position) / height);
}
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->get_selectables (start, end, botfrac, topfrac, results);
}
}
}
void
AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
{
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->get_inverted_selectables (sel, result);
}
}
void
AutomationTimeAxisView::set_selected_points (PointSelection& points)
{
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->set_selected_points (points);
}
}
void
AutomationTimeAxisView::clear_lines ()
{
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
delete *i;
}
lines.clear ();
automation_connection.disconnect ();
}
void
AutomationTimeAxisView::add_line (AutomationLine& line)
{
bool get = false;
if (lines.empty()) {
/* first line is the Model for automation state */
automation_connection = line.the_list().automation_state_changed.connect
(slot (*this, &AutomationTimeAxisView::automation_state_changed));
get = true;
}
lines.push_back (&line);
line.set_height (height);
if (get) {
/* pick up the current state */
automation_state_changed ();
}
}
void
AutomationTimeAxisView::show_all_control_points ()
{
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->show_all_control_points ();
}
}
void
AutomationTimeAxisView::hide_all_but_selected_control_points ()
{
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
(*i)->hide_all_but_selected_control_points ();
}
}
void
AutomationTimeAxisView::entered()
{
show_all_control_points ();
}
void
AutomationTimeAxisView::exited ()
{
hide_all_but_selected_control_points ();
}
void
AutomationTimeAxisView::set_state (const XMLNode& node)
{
TimeAxisView::set_state (node);
}
XMLNode*
AutomationTimeAxisView::get_state_node ()
{
TimeAxisView* state_parent = get_parent_with_state ();
if (state_parent) {
return state_parent->get_child_xml_node (_state_name);
} else {
return 0;
}
}

View File

@@ -0,0 +1,121 @@
#ifndef __ardour_gtk_automation_time_axis_h__
#define __ardour_gtk_automation_time_axis_h__
#include <vector>
#include <list>
#include <string>
#include <ardour/types.h>
#include "time_axis_view.h"
using std::vector;
using std::list;
using std::string;
namespace ARDOUR {
class Session;
class Route;
}
namespace Gtk {
class Widget;
}
class PublicEditor;
class TimeSelection;
class AudioRegionSelection;
class PointSelection;
class AutomationLine;
class GhostRegion;
class Selection;
class Selectable;
class AutomationTimeAxisView : public TimeAxisView {
public:
AutomationTimeAxisView (ARDOUR::Session&,
ARDOUR::Route&,
PublicEditor&,
TimeAxisView& parent,
Gtk::Widget* parent,
std::string name, /* translatable */
std::string state_name, /* not translatable */
std::string plug_name = "");
~AutomationTimeAxisView();
void set_height (TimeAxisView::TrackHeight);
void set_samples_per_unit (double);
std::string name() const { return _name; }
virtual void add_automation_event (GtkCanvasItem *item, GdkEvent *event, jack_nframes_t, double) = 0;
void clear_lines ();
void add_line (AutomationLine&);
vector<AutomationLine*> lines;
void set_selected_points (PointSelection&);
void get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable *>&);
void get_inverted_selectables (Selection&, list<Selectable*>& results);
void show_timestretch (jack_nframes_t start, jack_nframes_t end) {}
void hide_timestretch () {}
/* editing operations */
bool cut_copy_clear (Selection&, Editing::CutCopyOp);
bool cut_copy_clear_objects (PointSelection&, Editing::CutCopyOp);
bool paste (jack_nframes_t, float times, Selection&, size_t nth);
void add_ghost (GhostRegion*);
void remove_ghost (GhostRegion*);
void show_all_control_points ();
void hide_all_but_selected_control_points ();
void set_state (const XMLNode&);
XMLNode* get_state_node ();
protected:
ARDOUR::Route& route;
GtkCanvasItem* base_rect;
string _name;
string _state_name;
bool in_destructor;
Gtk::Button hide_button;
Gtk::Button height_button;
Gtk::Button clear_button;
Gtk::Button auto_button;
Gtk::Menu* automation_menu;
Gtk::Label* plugname;
bool plugname_packed;
Gtk::CheckMenuItem* auto_off_item;
Gtk::CheckMenuItem* auto_play_item;
Gtk::CheckMenuItem* auto_touch_item;
Gtk::CheckMenuItem* auto_write_item;
void clear_clicked ();
void height_clicked ();
void hide_clicked ();
void auto_clicked ();
virtual void build_display_menu ();
list<GhostRegion*> ghosts;
bool cut_copy_clear_one (AutomationLine&, Selection&, Editing::CutCopyOp);
bool cut_copy_clear_objects_one (AutomationLine&, PointSelection&, Editing::CutCopyOp);
bool paste_one (AutomationLine&, jack_nframes_t, float times, Selection&, size_t nth);
virtual void set_automation_state (ARDOUR::AutoState) = 0;
bool ignore_state_request;
void automation_state_changed ();
SigC::Connection automation_connection;
void entered ();
void exited ();
};
#endif /* __ardour_gtk_automation_time_axis_h__ */

96
gtk2_ardour/axis_view.cc Normal file
View File

@@ -0,0 +1,96 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <list>
#include <pbd/error.h>
#include <gtkmmext/utils.h>
#include <gtkmmext/selector.h>
#include <gtkmmext/gtk_ui.h>
#include <ardour/session.h>
#include <ardour/utils.h>
#include "public_editor.h"
#include "axis_view.h"
#include "i18n.h"
using namespace Gtk;
using namespace Gtkmmext;
list<GdkColor> AxisView::used_colors;
AxisView::AxisView (ARDOUR::Session& sess) : _session(sess)
{
_selected = false;
}
AxisView::~AxisView()
{
}
GdkColor
AxisView::unique_random_color()
{
GdkColor newcolor;
while (1) {
/* avoid neon/glowing tones by limiting them to the
"inner section" (paler) of a color wheel/circle.
*/
const int32_t max_saturation = 48000; // 65535 would open up the whole color wheel
newcolor.red = random() % max_saturation;
newcolor.blue = random() % max_saturation;
newcolor.green = random() % max_saturation;
if (used_colors.size() == 0) {
used_colors.push_back (newcolor);
return newcolor;
}
for (list<GdkColor>::iterator i = used_colors.begin(); i != used_colors.end(); ++i) {
GdkColor c = *i;
float rdelta, bdelta, gdelta;
rdelta = newcolor.red - c.red;
bdelta = newcolor.blue - c.blue;
gdelta = newcolor.green - c.green;
if (sqrt (rdelta*rdelta + bdelta*bdelta + gdelta*gdelta) > 25.0) {
used_colors.push_back (newcolor);
return newcolor;
}
}
/* XXX need throttle here to make sure we don't spin for ever */
}
}

97
gtk2_ardour/axis_view.h Normal file
View File

@@ -0,0 +1,97 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_gtk_axis_view_h__
#define __ardour_gtk_axis_view_h__
#include <list>
#include <gtk--.h>
#include <pbd/xml++.h>
#include "prompter.h"
namespace ARDOUR {
class Session;
}
/**
* AxisView defines the abstract base class for time-axis trackviews and routes.
*
*/
class AxisView : public SigC::Object
{
public:
/**
* Returns the current 'Track' Color
*
* @return the current Track Color
*/
Gdk_Color color() const { return _color; }
ARDOUR::Session& session() const { return _session; }
virtual string name() const = 0;
virtual void set_selected (bool yn) {
if (yn != _selected) {
_selected = yn;
}
}
virtual bool marked_for_display() const { return _marked_for_display; }
virtual void set_marked_for_display (bool yn) {
if (yn != _marked_for_display) {
_marked_for_display = yn;
}
}
virtual bool selected() const { return _selected; }
SigC::Signal0<void> Hiding;
SigC::Signal0<void> GoingAway;
protected:
AxisView (ARDOUR::Session& sess);
virtual ~AxisView();
/**
* Generate a new random TrackView color, unique from those colors already used.
*
* @return the unique random color.
*/
static GdkColor unique_random_color();
ARDOUR::Session& _session;
Gdk_Color _color;
static list<GdkColor> used_colors;
Gtk::Label name_label;
bool _selected;
bool _marked_for_display;
}; /* class AxisView */
#endif /* __ardour_gtk_axis_view_h__ */

View File

@@ -0,0 +1,66 @@
/* gtk-canvas-curve.h: GtkCanvas item for constrained spline curves
*
* Copyright (C) 2003 Paul Davis <pbd@op.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef __GTK_CANVAS_CURVE_H__
#define __GTK_CANVAS_CURVE_H__
#include <gtk-canvas/gtk-canvas-defs.h>
#include "gtk-canvas/gtk-canvas.h"
BEGIN_GTK_CANVAS_DECLS
/* Wave viewer item for canvas.
*/
#define GTK_CANVAS_TYPE_CANVAS_CURVE (gtk_canvas_curve_get_type ())
#define GTK_CANVAS_CURVE(obj) (GTK_CHECK_CAST ((obj), GTK_CANVAS_TYPE_CANVAS_CURVE, GtkCanvasCurve))
#define GTK_CANVAS_CURVE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_CANVAS_TYPE_CANVAS_CURVE, GtkCanvasCurveClass))
#define GTK_CANVAS_IS_CANVAS_CURVE(obj) (GTK_CHECK_TYPE ((obj), GTK_CANVAS_TYPE_CANVAS_CURVE))
#define GTK_CANVAS_IS_CANVAS_CURVE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_CANVAS_TYPE_CANVAS_CURVE))
typedef struct _GtkCanvasCurve GtkCanvasCurve;
typedef struct _GtkCanvasCurveClass GtkCanvasCurveClass;
struct _GtkCanvasCurve
{
GtkCanvasItem item;
double x1, y1, x2, y2;
void* curve_arg;
float* vector;
size_t veclen;
uint32_t color;
/* cached values set during update/used during render */
unsigned char r, b, g, a;
guint32 bbox_ulx, bbox_uly;
guint32 bbox_lrx, bbox_lry;
};
struct _GtkCanvasCurveClass {
GtkCanvasItemClass parent_class;
};
GtkType gtk_canvas_curve_get_type (void);
END_GTK_CANVAS_DECLS
#endif /* __GTK_CANVAS_CURVE_H__ */

View File

@@ -0,0 +1,586 @@
/* Image item type for GtkCanvas widget
*
* GtkCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
* copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
*
* Copyright (C) 1998 The Free Software Foundation
*
* Author: Federico Mena <federico@nuclecu.unam.mx>
*/
#include <string.h> /* for memcpy() */
#include <math.h>
#include <stdio.h>
#include "libart_lgpl/art_misc.h"
#include "libart_lgpl/art_affine.h"
#include "libart_lgpl/art_pixbuf.h"
#include "libart_lgpl/art_rgb_pixbuf_affine.h"
#include "canvas-imageframe.h"
#include <gtk-canvas/gtk-canvas-util.h>
#include <gtk-canvas/gtk-canvastypebuiltins.h>
enum {
ARG_0,
ARG_PIXBUF,
ARG_X,
ARG_Y,
ARG_WIDTH,
ARG_HEIGHT,
ARG_DRAWWIDTH,
ARG_ANCHOR
};
static void gtk_canvas_imageframe_class_init(GtkCanvasImageFrameClass* class) ;
static void gtk_canvas_imageframe_init(GtkCanvasImageFrame* image) ;
static void gtk_canvas_imageframe_destroy(GtkObject* object) ;
static void gtk_canvas_imageframe_set_arg(GtkObject* object, GtkArg* arg, guint arg_id) ;
static void gtk_canvas_imageframe_get_arg(GtkObject* object, GtkArg* arg, guint arg_id) ;
static void gtk_canvas_imageframe_update(GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags) ;
static void gtk_canvas_imageframe_realize(GtkCanvasItem *item) ;
static void gtk_canvas_imageframe_unrealize(GtkCanvasItem *item) ;
static void gtk_canvas_imageframe_draw(GtkCanvasItem *item, GdkDrawable *drawable, int x, int y, int width, int height) ;
static double gtk_canvas_imageframe_point(GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item) ;
static void gtk_canvas_imageframe_translate(GtkCanvasItem *item, double dx, double dy) ;
static void gtk_canvas_imageframe_bounds(GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2) ;
static void gtk_canvas_imageframe_render(GtkCanvasItem *item, GtkCanvasBuf *buf) ;
static GtkCanvasItemClass *parent_class;
GtkType
gtk_canvas_imageframe_get_type (void)
{
static GtkType imageframe_type = 0;
if (!imageframe_type) {
GtkTypeInfo imageframe_info = {
"GtkCanvasImageFrame",
sizeof (GtkCanvasImageFrame),
sizeof (GtkCanvasImageFrameClass),
(GtkClassInitFunc) gtk_canvas_imageframe_class_init,
(GtkObjectInitFunc) gtk_canvas_imageframe_init,
NULL, /* reserved_1 */
NULL, /* reserved_2 */
(GtkClassInitFunc) NULL
};
imageframe_type = gtk_type_unique (gtk_canvas_item_get_type (), &imageframe_info);
}
return imageframe_type;
}
static void
gtk_canvas_imageframe_class_init (GtkCanvasImageFrameClass *class)
{
GtkObjectClass *object_class;
GtkCanvasItemClass *item_class;
object_class = (GtkObjectClass *) class;
item_class = (GtkCanvasItemClass *) class;
parent_class = gtk_type_class (gtk_canvas_item_get_type ());
gtk_object_add_arg_type ("GtkCanvasImageFrame::pixbuf", GTK_TYPE_BOXED, GTK_ARG_WRITABLE, ARG_PIXBUF);
gtk_object_add_arg_type ("GtkCanvasImageFrame::x", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X);
gtk_object_add_arg_type ("GtkCanvasImageFrame::y", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y);
gtk_object_add_arg_type ("GtkCanvasImageFrame::width", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_WIDTH);
gtk_object_add_arg_type ("GtkCanvasImageFrame::drawwidth", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_DRAWWIDTH);
gtk_object_add_arg_type ("GtkCanvasImageFrame::height", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_HEIGHT);
gtk_object_add_arg_type ("GtkCanvasImageFrame::anchor", GTK_TYPE_ANCHOR_TYPE, GTK_ARG_READWRITE, ARG_ANCHOR);
object_class->destroy = gtk_canvas_imageframe_destroy;
object_class->set_arg = gtk_canvas_imageframe_set_arg;
object_class->get_arg = gtk_canvas_imageframe_get_arg;
item_class->update = gtk_canvas_imageframe_update;
item_class->realize = gtk_canvas_imageframe_realize;
item_class->unrealize = gtk_canvas_imageframe_unrealize;
item_class->draw = gtk_canvas_imageframe_draw;
item_class->point = gtk_canvas_imageframe_point;
item_class->translate = gtk_canvas_imageframe_translate;
item_class->bounds = gtk_canvas_imageframe_bounds;
item_class->render = gtk_canvas_imageframe_render;
}
static void
gtk_canvas_imageframe_init (GtkCanvasImageFrame *image)
{
image->x = 0.0;
image->y = 0.0;
image->width = 0.0;
image->height = 0.0;
image->drawwidth = 0.0;
image->anchor = GTK_ANCHOR_CENTER;
GTK_CANVAS_ITEM(image)->object.flags |= GTK_CANVAS_ITEM_NO_AUTO_REDRAW;
}
static void
gtk_canvas_imageframe_destroy (GtkObject *object)
{
GtkCanvasImageFrame *image;
g_return_if_fail (object != NULL);
g_return_if_fail (GTK_CANVAS_IS_CANVAS_IMAGEFRAME (object));
image = GTK_CANVAS_IMAGEFRAME (object);
image->cwidth = 0;
image->cheight = 0;
if (image->pixbuf)
{
art_pixbuf_free (image->pixbuf);
image->pixbuf = NULL;
}
if(GTK_OBJECT_CLASS (parent_class)->destroy)
{
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
}
/* Get's the image bounds expressed as item-relative coordinates. */
static void
get_bounds_item_relative (GtkCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2)
{
GtkCanvasItem *item;
double x, y;
item = GTK_CANVAS_ITEM (image);
/* Get item coordinates */
x = image->x;
y = image->y;
/* Anchor image */
switch (image->anchor) {
case GTK_ANCHOR_NW:
case GTK_ANCHOR_W:
case GTK_ANCHOR_SW:
break;
case GTK_ANCHOR_N:
case GTK_ANCHOR_CENTER:
case GTK_ANCHOR_S:
x -= image->width / 2;
break;
case GTK_ANCHOR_NE:
case GTK_ANCHOR_E:
case GTK_ANCHOR_SE:
x -= image->width;
break;
}
switch (image->anchor) {
case GTK_ANCHOR_NW:
case GTK_ANCHOR_N:
case GTK_ANCHOR_NE:
break;
case GTK_ANCHOR_W:
case GTK_ANCHOR_CENTER:
case GTK_ANCHOR_E:
y -= image->height / 2;
break;
case GTK_ANCHOR_SW:
case GTK_ANCHOR_S:
case GTK_ANCHOR_SE:
y -= image->height;
break;
}
/* Bounds */
*px1 = x;
*py1 = y;
*px2 = x + image->width;
*py2 = y + image->height;
}
static void
get_bounds (GtkCanvasImageFrame *image, double *px1, double *py1, double *px2, double *py2)
{
GtkCanvasItem *item;
double i2c[6];
ArtDRect i_bbox, c_bbox;
item = GTK_CANVAS_ITEM (image);
gtk_canvas_item_i2c_affine (item, i2c);
get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1);
art_drect_affine_transform (&c_bbox, &i_bbox, i2c);
/* add a fudge factor */
*px1 = c_bbox.x0 - 1;
*py1 = c_bbox.y0 - 1;
*px2 = c_bbox.x1 + 1;
*py2 = c_bbox.y1 + 1;
}
/* deprecated */
static void
recalc_bounds (GtkCanvasImageFrame *image)
{
GtkCanvasItem *item;
item = GTK_CANVAS_ITEM (image);
get_bounds (image, &item->x1, &item->y1, &item->x2, &item->y2);
item->x1 = image->cx;
item->y1 = image->cy;
item->x2 = image->cx + image->cwidth;
item->y2 = image->cy + image->cheight;
gtk_canvas_group_child_bounds (GTK_CANVAS_GROUP (item->parent), item);
}
static void
gtk_canvas_imageframe_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GtkCanvasItem *item;
GtkCanvasImageFrame *image;
int update;
int calc_bounds;
item = GTK_CANVAS_ITEM (object);
image = GTK_CANVAS_IMAGEFRAME (object);
update = FALSE;
calc_bounds = FALSE;
switch (arg_id) {
case ARG_PIXBUF:
if (item->canvas->aa && GTK_VALUE_BOXED (*arg)) {
if (image->pixbuf != NULL)
art_pixbuf_free (image->pixbuf);
image->pixbuf = GTK_VALUE_BOXED (*arg);
}
update = TRUE;
break;
case ARG_X:
image->x = GTK_VALUE_DOUBLE (*arg);
update = TRUE;
break;
case ARG_Y:
image->y = GTK_VALUE_DOUBLE (*arg);
update = TRUE;
break;
case ARG_WIDTH:
image->width = fabs (GTK_VALUE_DOUBLE (*arg));
update = TRUE;
break;
case ARG_HEIGHT:
image->height = fabs (GTK_VALUE_DOUBLE (*arg));
update = TRUE;
break;
case ARG_DRAWWIDTH:
image->drawwidth = fabs (GTK_VALUE_DOUBLE (*arg));
update = TRUE;
break;
case ARG_ANCHOR:
image->anchor = GTK_VALUE_ENUM (*arg);
update = TRUE;
break;
default:
break;
}
#ifdef OLD_XFORM
if (update)
(* GTK_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0);
if (calc_bounds)
recalc_bounds (image);
#else
if (update)
gtk_canvas_item_request_update (item);
#endif
}
static void
gtk_canvas_imageframe_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GtkCanvasImageFrame *image;
image = GTK_CANVAS_IMAGEFRAME (object);
switch (arg_id) {
case ARG_X:
GTK_VALUE_DOUBLE (*arg) = image->x;
break;
case ARG_Y:
GTK_VALUE_DOUBLE (*arg) = image->y;
break;
case ARG_WIDTH:
GTK_VALUE_DOUBLE (*arg) = image->width;
break;
case ARG_HEIGHT:
GTK_VALUE_DOUBLE (*arg) = image->height;
break;
case ARG_DRAWWIDTH:
GTK_VALUE_DOUBLE (*arg) = image->drawwidth;
break;
case ARG_ANCHOR:
GTK_VALUE_ENUM (*arg) = image->anchor;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static void
gtk_canvas_imageframe_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
GtkCanvasImageFrame *image;
ArtDRect i_bbox, c_bbox;
int w = 0;
int h = 0;
image = GTK_CANVAS_IMAGEFRAME (item);
if (parent_class->update)
(* parent_class->update) (item, affine, clip_path, flags);
/* only works for non-rotated, non-skewed transforms */
image->cwidth = (int) (image->width * affine[0] + 0.5);
image->cheight = (int) (image->height * affine[3] + 0.5);
if (image->pixbuf) {
image->need_recalc = TRUE ;
}
#ifdef OLD_XFORM
recalc_bounds (image);
#else
get_bounds_item_relative (image, &i_bbox.x0, &i_bbox.y0, &i_bbox.x1, &i_bbox.y1);
art_drect_affine_transform (&c_bbox, &i_bbox, affine);
/* these values only make sense in the non-rotated, non-skewed case */
image->cx = c_bbox.x0;
image->cy = c_bbox.y0;
/* add a fudge factor */
c_bbox.x0--;
c_bbox.y0--;
c_bbox.x1++;
c_bbox.y1++;
gtk_canvas_update_bbox (item, c_bbox.x0, c_bbox.y0, c_bbox.x1, c_bbox.y1);
if (image->pixbuf) {
w = image->pixbuf->width;
h = image->pixbuf->height;
}
image->affine[0] = (affine[0] * image->width) / w;
image->affine[1] = (affine[1] * image->height) / h;
image->affine[2] = (affine[2] * image->width) / w;
image->affine[3] = (affine[3] * image->height) / h;
image->affine[4] = i_bbox.x0 * affine[0] + i_bbox.y0 * affine[2] + affine[4];
image->affine[5] = i_bbox.x0 * affine[1] + i_bbox.y0 * affine[3] + affine[5];
#endif
}
static void
gtk_canvas_imageframe_realize (GtkCanvasItem *item)
{
GtkCanvasImageFrame *image;
image = GTK_CANVAS_IMAGEFRAME (item);
if (parent_class->realize)
(* parent_class->realize) (item);
}
static void
gtk_canvas_imageframe_unrealize (GtkCanvasItem *item)
{
GtkCanvasImageFrame *image;
image = GTK_CANVAS_IMAGEFRAME(item);
if (parent_class->unrealize)
(* parent_class->unrealize) (item);
}
static void
recalc_if_needed (GtkCanvasImageFrame *image)
{}
static void
gtk_canvas_imageframe_draw (GtkCanvasItem *item, GdkDrawable *drawable,
int x, int y, int width, int height)
{
fprintf(stderr, "please don't use the CanvasImageFrame item in a non-aa Canvas\n") ;
abort() ;
}
static double
gtk_canvas_imageframe_point (GtkCanvasItem *item, double x, double y,
int cx, int cy, GtkCanvasItem **actual_item)
{
GtkCanvasImageFrame *image;
int x1, y1, x2, y2;
int dx, dy;
image = GTK_CANVAS_IMAGEFRAME (item);
*actual_item = item;
recalc_if_needed (image);
x1 = image->cx - item->canvas->close_enough;
y1 = image->cy - item->canvas->close_enough;
x2 = image->cx + image->cwidth - 1 + item->canvas->close_enough;
y2 = image->cy + image->cheight - 1 + item->canvas->close_enough;
/* Hard case: is point inside image's gravity region? */
//if ((cx >= x1) && (cy >= y1) && (cx <= x2) && (cy <= y2))
//return dist_to_mask (image, cx, cy) / item->canvas->pixels_per_unit;
/* Point is outside image */
x1 += item->canvas->close_enough;
y1 += item->canvas->close_enough;
x2 -= item->canvas->close_enough;
y2 -= item->canvas->close_enough;
if (cx < x1)
dx = x1 - cx;
else if (cx > x2)
dx = cx - x2;
else
dx = 0;
if (cy < y1)
dy = y1 - cy;
else if (cy > y2)
dy = cy - y2;
else
dy = 0;
return sqrt (dx * dx + dy * dy) / item->canvas->pixels_per_unit;
}
static void
gtk_canvas_imageframe_translate (GtkCanvasItem *item, double dx, double dy)
{
#ifdef OLD_XFORM
GtkCanvasImageFrame *image;
image = GTK_CANVAS_IMAGEFRAME (item);
image->x += dx;
image->y += dy;
recalc_bounds (image);
#endif
}
static void
gtk_canvas_imageframe_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
GtkCanvasImageFrame *image;
image = GTK_CANVAS_IMAGEFRAME (item);
*x1 = image->x;
*y1 = image->y;
switch (image->anchor) {
case GTK_ANCHOR_NW:
case GTK_ANCHOR_W:
case GTK_ANCHOR_SW:
break;
case GTK_ANCHOR_N:
case GTK_ANCHOR_CENTER:
case GTK_ANCHOR_S:
*x1 -= image->width / 2.0;
break;
case GTK_ANCHOR_NE:
case GTK_ANCHOR_E:
case GTK_ANCHOR_SE:
*x1 -= image->width;
break;
}
switch (image->anchor) {
case GTK_ANCHOR_NW:
case GTK_ANCHOR_N:
case GTK_ANCHOR_NE:
break;
case GTK_ANCHOR_W:
case GTK_ANCHOR_CENTER:
case GTK_ANCHOR_E:
*y1 -= image->height / 2.0;
break;
case GTK_ANCHOR_SW:
case GTK_ANCHOR_S:
case GTK_ANCHOR_SE:
*y1 -= image->height;
break;
}
*x2 = *x1 + image->width;
*y2 = *y1 + image->height;
}
static void
gtk_canvas_imageframe_render (GtkCanvasItem *item, GtkCanvasBuf *buf)
{
GtkCanvasImageFrame *image;
image = GTK_CANVAS_IMAGEFRAME (item);
gtk_canvas_buf_ensure_buf (buf);
#ifdef VERBOSE
{
char str[128];
art_affine_to_string (str, image->affine);
g_print ("gtk_canvas_imageframe_render %s\n", str);
}
#endif
art_rgb_pixbuf_affine (buf->buf,
buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
buf->buf_rowstride,
image->pixbuf,
image->affine,
ART_FILTER_NEAREST, NULL);
buf->is_bg = 0;
}

View File

@@ -0,0 +1,80 @@
/* Image item type for GtkCanvas widget
*
* GtkCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
* copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
*
* Copyright (C) 1998 The Free Software Foundation
*
* Author: Federico Mena <federico@nuclecu.unam.mx>
*/
#ifndef __GTK_CANVAS_IMAGEFRAME_H__
#define __GTK_CANVAS_IMAGEFRAME_H__
#include <stdint.h>
#include <gtk-canvas/gtk-canvas-defs.h>
#include <gtk/gtkpacker.h> /* why the hell is GtkAnchorType here and not in gtkenums.h? */
#include <libart_lgpl/art_misc.h>
#include <libart_lgpl/art_pixbuf.h>
#include "gtk-canvas/gtk-canvas.h"
BEGIN_GTK_CANVAS_DECLS
/* Image item for the canvas. Images are positioned by anchoring them to a point.
* The following arguments are available:
*
* name type read/write description
* ------------------------------------------------------------------------------------------
* pixbuf ArtPixBuf* W Pointer to an ArtPixBuf (aa-mode)
* x double RW X coordinate of anchor point
* y double RW Y coordinate of anchor point
* width double RW Width to scale image to, in canvas units
* height double RW Height to scale image to, in canvas units
* drawwidth double RW Width to scale image to, in canvas units
* anchor GtkAnchorType RW Anchor side for the image
*/
#define GTK_CANVAS_TYPE_CANVAS_IMAGEFRAME (gtk_canvas_imageframe_get_type ())
#define GTK_CANVAS_IMAGEFRAME(obj) (GTK_CHECK_CAST ((obj), GTK_CANVAS_TYPE_CANVAS_IMAGEFRAME, GtkCanvasImageFrame))
#define GTK_CANVAS_IMAGEFRAME_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_CANVAS_TYPE_CANVAS_IMAGEFRAME, GtkCanvasImageFrameClass))
#define GTK_CANVAS_IS_CANVAS_IMAGEFRAME(obj) (GTK_CHECK_TYPE ((obj), GTK_CANVAS_TYPE_CANVAS_IMAGEFRAME))
#define GTK_CANVAS_IS_CANVAS_IMAGEFRAME_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_CANVAS_TYPE_CANVAS_IMAGEFRAME))
typedef struct _GtkCanvasImageFrame GtkCanvasImageFrame;
typedef struct _GtkCanvasImageFrameClass GtkCanvasImageFrameClass;
struct _GtkCanvasImageFrame {
GtkCanvasItem item;
double x, y; /* Position at anchor, item relative */
double width, height; /* Size of image, item relative */
double drawwidth ; /* the amount of the image we draw width-wise (0-drawwidth)*/
GtkAnchorType anchor; /* Anchor side for image */
int cx, cy; /* Top-left canvas coordinates for display */
int cwidth, cheight; /* Rendered size in pixels */
uint32_t need_recalc : 1; /* Do we need to rescale the image? */
ArtPixBuf *pixbuf; /* A pixbuf, for aa rendering */
double affine[6]; /* The item -> canvas affine */
};
struct _GtkCanvasImageFrameClass {
GtkCanvasItemClass parent_class;
};
/* Standard Gtk function */
GtkType gtk_canvas_imageframe_get_type (void);
END_GTK_CANVAS_DECLS
#endif

381
gtk2_ardour/canvas-ruler.c Normal file
View File

@@ -0,0 +1,381 @@
#include <stdio.h>
#include <math.h>
#include <gtk-canvas.h>
#include "canvas-ruler.h"
#include "rgb_macros.h"
enum {
ARG_0,
ARG_X1,
ARG_Y1,
ARG_X2,
ARG_Y2,
ARG_FRAMES_PER_UNIT,
ARG_FILL_COLOR,
ARG_TICK_COLOR
};
static void gtk_canvas_ruler_class_init (GtkCanvasRulerClass *class);
static void gtk_canvas_ruler_init (GtkCanvasRuler *ruler);
static void gtk_canvas_ruler_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_canvas_ruler_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_canvas_ruler_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
static void gtk_canvas_ruler_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
static double gtk_canvas_ruler_point (GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item);
static void gtk_canvas_ruler_render (GtkCanvasItem *item, GtkCanvasBuf *buf);
static void gtk_canvas_ruler_draw (GtkCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h);
static GtkCanvasItemClass *parent_class;
GtkType
gtk_canvas_ruler_get_type (void)
{
static GtkType ruler_type = 0;
if (!ruler_type) {
GtkTypeInfo ruler_info = {
"GtkCanvasRuler",
sizeof (GtkCanvasRuler),
sizeof (GtkCanvasRulerClass),
(GtkClassInitFunc) gtk_canvas_ruler_class_init,
(GtkObjectInitFunc) gtk_canvas_ruler_init,
NULL, /* reserved_1 */
NULL, /* reserved_2 */
(GtkClassInitFunc) NULL
};
ruler_type = gtk_type_unique (gtk_canvas_item_get_type (), &ruler_info);
}
return ruler_type;
}
static void
gtk_canvas_ruler_class_init (GtkCanvasRulerClass *class)
{
GtkObjectClass *object_class;
GtkCanvasItemClass *item_class;
object_class = (GtkObjectClass *) class;
item_class = (GtkCanvasItemClass *) class;
parent_class = gtk_type_class (gtk_canvas_item_get_type ());
gtk_object_add_arg_type ("GtkCanvasRuler::x1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X1);
gtk_object_add_arg_type ("GtkCanvasRuler::y1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y1);
gtk_object_add_arg_type ("GtkCanvasRuler::x2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X2);
gtk_object_add_arg_type ("GtkCanvasRuler::y2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y2);
gtk_object_add_arg_type ("GtkCanvasRuler::frames_per_unit", GTK_TYPE_LONG, GTK_ARG_READWRITE, ARG_FRAMES_PER_UNIT);
gtk_object_add_arg_type ("GtkCanvasRuler::fill_color", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_FILL_COLOR);
gtk_object_add_arg_type ("GtkCanvasRuler::tick_color", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_TICK_COLOR);
object_class->set_arg = gtk_canvas_ruler_set_arg;
object_class->get_arg = gtk_canvas_ruler_get_arg;
item_class->update = gtk_canvas_ruler_update;
item_class->bounds = gtk_canvas_ruler_bounds;
item_class->point = gtk_canvas_ruler_point;
item_class->render = gtk_canvas_ruler_render;
item_class->draw = gtk_canvas_ruler_draw;
}
static void
gtk_canvas_ruler_init (GtkCanvasRuler *ruler)
{
ruler->x1 = 0.0;
ruler->y1 = 0.0;
ruler->x2 = 0.0;
ruler->y2 = 0.0;
ruler->frames_per_unit = 1;
ruler->fill_color = 0;
ruler->tick_color = 0;
GTK_CANVAS_ITEM(ruler)->object.flags |= GTK_CANVAS_ITEM_NO_AUTO_REDRAW;
}
static void
gtk_canvas_ruler_reset_bounds (GtkCanvasItem *item)
{
double x1, x2, y1, y2;
ArtPoint i1, i2;
ArtPoint w1, w2;
int Ix1, Ix2, Iy1, Iy2;
double i2w[6];
gtk_canvas_ruler_bounds (item, &x1, &y1, &x2, &y2);
i1.x = x1;
i1.y = y1;
i2.x = x2;
i2.y = y2;
gtk_canvas_item_i2w_affine (item, i2w);
art_affine_point (&w1, &i1, i2w);
art_affine_point (&w2, &i2, i2w);
Ix1 = (int) rint(w1.x);
Ix2 = (int) rint(w2.x);
Iy1 = (int) rint(w1.y);
Iy2 = (int) rint(w2.y);
gtk_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
}
/*
* CANVAS CALLBACKS
*/
static void
gtk_canvas_ruler_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GtkCanvasItem *item;
GtkCanvasRuler *ruler;
int redraw;
int calc_bounds;
item = GTK_CANVAS_ITEM (object);
ruler = GTK_CANVAS_RULER (object);
redraw = FALSE;
calc_bounds = FALSE;
switch (arg_id) {
case ARG_X1:
if (ruler->x1 != GTK_VALUE_DOUBLE (*arg)) {
ruler->x1 = GTK_VALUE_DOUBLE (*arg);
calc_bounds = TRUE;
}
break;
case ARG_Y1:
if (ruler->y1 != GTK_VALUE_DOUBLE (*arg)) {
ruler->y1 = GTK_VALUE_DOUBLE (*arg);
calc_bounds = TRUE;
}
break;
case ARG_X2:
if (ruler->x2 != GTK_VALUE_DOUBLE (*arg)) {
ruler->x2 = GTK_VALUE_DOUBLE (*arg);
calc_bounds = TRUE;
}
break;
case ARG_Y2:
if (ruler->y2 != GTK_VALUE_DOUBLE (*arg)) {
ruler->y2 = GTK_VALUE_DOUBLE (*arg);
calc_bounds = TRUE;
}
break;
case ARG_FRAMES_PER_UNIT:
if (ruler->frames_per_unit != GTK_VALUE_LONG(*arg)) {
ruler->frames_per_unit = GTK_VALUE_LONG(*arg);
redraw = TRUE;
}
break;
case ARG_FILL_COLOR:
if (ruler->fill_color != GTK_VALUE_INT(*arg)) {
ruler->fill_color = GTK_VALUE_INT(*arg);
redraw = TRUE;
}
break;
case ARG_TICK_COLOR:
if (ruler->tick_color != GTK_VALUE_INT(*arg)) {
ruler->tick_color = GTK_VALUE_INT(*arg);
redraw = TRUE;
}
break;
default:
break;
}
if (calc_bounds) {
gtk_canvas_ruler_reset_bounds (item);
}
if (redraw) {
gtk_canvas_item_request_update (item);
}
}
static void
gtk_canvas_ruler_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GtkCanvasRuler *ruler;
ruler = GTK_CANVAS_RULER (object);
switch (arg_id) {
case ARG_X1:
GTK_VALUE_DOUBLE (*arg) = ruler->x1;
break;
case ARG_Y1:
GTK_VALUE_DOUBLE (*arg) = ruler->y1;
break;
case ARG_X2:
GTK_VALUE_DOUBLE (*arg) = ruler->x2;
break;
case ARG_Y2:
GTK_VALUE_DOUBLE (*arg) = ruler->y2;
break;
case ARG_FRAMES_PER_UNIT:
GTK_VALUE_LONG (*arg) = ruler->frames_per_unit;
break;
case ARG_FILL_COLOR:
GTK_VALUE_INT (*arg) = ruler->fill_color;
break;
case ARG_TICK_COLOR:
GTK_VALUE_INT (*arg) = ruler->tick_color;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static void
gtk_canvas_ruler_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
GtkCanvasRuler *ruler;
double x;
double y;
ruler = GTK_CANVAS_RULER (item);
if (parent_class->update)
(* parent_class->update) (item, affine, clip_path, flags);
gtk_canvas_ruler_reset_bounds (item);
x = ruler->x1;
y = ruler->y1;
gtk_canvas_item_i2w (item, &x, &y);
gtk_canvas_w2c (GTK_CANVAS(item->canvas), x, y, &ruler->bbox_ulx, &ruler->bbox_uly);
x = ruler->x2;
y = ruler->y2;
gtk_canvas_item_i2w (item, &x, &y);
gtk_canvas_w2c (GTK_CANVAS(item->canvas), x, y, &ruler->bbox_lrx, &ruler->bbox_lry);
UINT_TO_RGB (ruler->tick_color, &ruler->tick_r, &ruler->tick_g, &ruler->tick_b);
UINT_TO_RGB (ruler->fill_color, &ruler->fill_r, &ruler->fill_g, &ruler->fill_b);
}
static void
gtk_canvas_ruler_render (GtkCanvasItem *item,
GtkCanvasBuf *buf)
{
GtkCanvasRuler *ruler;
int end, begin;
ruler = GTK_CANVAS_RULER (item);
if (parent_class->render) {
(*parent_class->render) (item, buf);
}
if (buf->is_bg) {
gtk_canvas_buf_ensure_buf (buf);
buf->is_bg = FALSE;
}
begin = MAX(ruler->bbox_ulx,buf->rect.x0);
if (ruler->bbox_lrx >= 0) {
end = MIN(ruler->bbox_lrx,buf->rect.x1);
} else {
end = buf->rect.x1;
}
if (begin == end) {
return;
}
PAINT_BOX (buf, ruler->fill_r, ruler->fill_g, ruler->fill_b, 255, begin, ruler->bbox_uly, end, ruler->bbox_lry - 1);
PAINT_HORIZ (buf, ruler->tick_r, ruler->tick_g, ruler->tick_b, begin, end, ruler->bbox_lry - 1);
}
static void
gtk_canvas_ruler_draw (GtkCanvasItem *item,
GdkDrawable *drawable,
int x, int y,
int width, int height)
{
GtkCanvasRuler *ruler;
ruler = GTK_CANVAS_RULER (item);
if (parent_class->draw) {
(* parent_class->draw) (item, drawable, x, y, width, height);
}
fprintf (stderr, "please don't use the CanvasRuler item in a non-aa Canvas\n");
abort ();
}
static void
gtk_canvas_ruler_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
GtkCanvasRuler *ruler = GTK_CANVAS_RULER (item);
*x1 = ruler->x1;
*y1 = ruler->y1;
*x2 = ruler->x2;
*y2 = ruler->y2;
}
static double
gtk_canvas_ruler_point (GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item)
{
GtkCanvasRuler *ruler;
double x1, y1, x2, y2;
double dx, dy;
ruler = GTK_CANVAS_RULER (item);
*actual_item = item;
/* Find the bounds for the rectangle plus its outline width */
gtk_canvas_ruler_bounds (item, &x1, &y1, &x2, &y2);
/* Is point inside rectangle */
if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
return 0.0;
}
/* Point is outside rectangle */
if (x < x1)
dx = x1 - x;
else if (x > x2)
dx = x - x2;
else
dx = 0.0;
if (y < y1)
dy = y1 - y;
else if (y > y2)
dy = y - y2;
else
dy = 0.0;
return sqrt (dx * dx + dy * dy);
}

View File

@@ -0,0 +1,68 @@
/* gtk-canvas-ruler.h: GtkCanvas item for simple rects
*
* Copyright (C) 2001 Paul Davis <pbd@op.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef __GTK_CANVAS_RULER_H__
#define __GTK_CANVAS_RULER_H__
#include <stdint.h>
#include <gtk-canvas/gtk-canvas-defs.h>
#include "gtk-canvas/gtk-canvas.h"
BEGIN_GTK_CANVAS_DECLS
/* Wave viewer item for canvas.
*/
#define GTK_CANVAS_TYPE_CANVAS_RULER (gtk_canvas_ruler_get_type ())
#define GTK_CANVAS_RULER(obj) (GTK_CHECK_CAST ((obj), GTK_CANVAS_TYPE_CANVAS_RULER, GtkCanvasRuler))
#define GTK_CANVAS_RULER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_CANVAS_TYPE_CANVAS_RULER, GtkCanvasRulerClass))
#define GTK_CANVAS_IS_CANVAS_RULER(obj) (GTK_CHECK_TYPE ((obj), GTK_CANVAS_TYPE_CANVAS_RULER))
#define GTK_CANVAS_IS_CANVAS_RULER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_CANVAS_TYPE_CANVAS_RULER))
typedef struct _GtkCanvasRuler GtkCanvasRuler;
typedef struct _GtkCanvasRulerClass GtkCanvasRulerClass;
struct _GtkCanvasRuler
{
GtkCanvasItem item;
double x1, y1, x2, y2;
uint32_t fill_color;
uint32_t tick_color;
uint32_t frames_per_unit;
/* cached values set during update/used during render */
unsigned char fill_r, fill_b, fill_g, fill_a;
unsigned char tick_r, tick_b, tick_g;
guint32 bbox_ulx, bbox_uly;
guint32 bbox_lrx, bbox_lry;
};
struct _GtkCanvasRulerClass {
GtkCanvasItemClass parent_class;
};
GtkType gtk_canvas_ruler_get_type (void);
END_GTK_CANVAS_DECLS
#endif /* __GTK_CANVAS_RULER_H__ */

View File

@@ -0,0 +1,371 @@
#include <stdio.h>
#include <math.h>
#include <gtk-canvas.h>
#include "canvas-simpleline.h"
#include "rgb_macros.h"
enum {
ARG_0,
ARG_X1,
ARG_Y1,
ARG_X2,
ARG_Y2,
ARG_COLOR_RGBA
};
static void gtk_canvas_simpleline_class_init (GtkCanvasSimpleLineClass *class);
static void gtk_canvas_simpleline_init (GtkCanvasSimpleLine *simpleline);
static void gtk_canvas_simpleline_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_canvas_simpleline_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_canvas_simpleline_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
static void gtk_canvas_simpleline_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
static double gtk_canvas_simpleline_point (GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item);
static void gtk_canvas_simpleline_render (GtkCanvasItem *item, GtkCanvasBuf *buf);
static void gtk_canvas_simpleline_draw (GtkCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h);
static GtkCanvasItemClass *parent_class;
GtkType
gtk_canvas_simpleline_get_type (void)
{
static GtkType simpleline_type = 0;
if (!simpleline_type) {
GtkTypeInfo simpleline_info = {
"GtkCanvasSimpleLine",
sizeof (GtkCanvasSimpleLine),
sizeof (GtkCanvasSimpleLineClass),
(GtkClassInitFunc) gtk_canvas_simpleline_class_init,
(GtkObjectInitFunc) gtk_canvas_simpleline_init,
NULL, /* reserved_1 */
NULL, /* reserved_2 */
(GtkClassInitFunc) NULL
};
simpleline_type = gtk_type_unique (gtk_canvas_item_get_type (), &simpleline_info);
}
return simpleline_type;
}
static void
gtk_canvas_simpleline_class_init (GtkCanvasSimpleLineClass *class)
{
GtkObjectClass *object_class;
GtkCanvasItemClass *item_class;
object_class = (GtkObjectClass *) class;
item_class = (GtkCanvasItemClass *) class;
parent_class = gtk_type_class (gtk_canvas_item_get_type ());
gtk_object_add_arg_type ("GtkCanvasSimpleLine::x1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X1);
gtk_object_add_arg_type ("GtkCanvasSimpleLine::y1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y1);
gtk_object_add_arg_type ("GtkCanvasSimpleLine::x2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X2);
gtk_object_add_arg_type ("GtkCanvasSimpleLine::y2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y2);
gtk_object_add_arg_type ("GtkCanvasSimpleLine::color_rgba", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_COLOR_RGBA);
object_class->set_arg = gtk_canvas_simpleline_set_arg;
object_class->get_arg = gtk_canvas_simpleline_get_arg;
item_class->update = gtk_canvas_simpleline_update;
item_class->bounds = gtk_canvas_simpleline_bounds;
item_class->point = gtk_canvas_simpleline_point;
item_class->render = gtk_canvas_simpleline_render;
item_class->draw = gtk_canvas_simpleline_draw;
}
static void
gtk_canvas_simpleline_init (GtkCanvasSimpleLine *simpleline)
{
simpleline->x1 = 0.0;
simpleline->y1 = 0.0;
simpleline->x2 = 0.0;
simpleline->y2 = 0.0;
simpleline->color = RGBA_TO_UINT(98,123,174,241);
simpleline->horizontal = TRUE; /* reset in the _update() method */
GTK_CANVAS_ITEM(simpleline)->object.flags |= GTK_CANVAS_ITEM_NO_AUTO_REDRAW;
}
static void
gtk_canvas_simpleline_bounds_world (GtkCanvasItem *item, int* ix1, int* iy1, int* ix2, int* iy2)
{
double x1, x2, y1, y2;
ArtPoint i1, i2;
ArtPoint w1, w2;
double i2w[6];
GtkCanvasSimpleLine *simpleline = GTK_CANVAS_SIMPLELINE(item);
gtk_canvas_simpleline_bounds (item, &x1, &y1, &x2, &y2);
i1.x = x1;
i1.y = y1;
i2.x = x2;
i2.y = y2;
gtk_canvas_item_i2w_affine (item, i2w);
art_affine_point (&w1, &i1, i2w);
art_affine_point (&w2, &i2, i2w);
*ix1 = (int) rint(w1.x);
*ix2 = (int) rint(w2.x);
*iy1 = (int) rint(w1.y);
*iy2 = (int) rint(w2.y);
/* the update rect has to be of non-zero width and height */
if (x1 == x2) {
simpleline->horizontal = FALSE;
*ix2 += 1;
} else {
simpleline->horizontal = TRUE;
*iy2 += 1;
}
}
static void
gtk_canvas_simpleline_reset_bounds (GtkCanvasItem *item)
{
int Ix1, Ix2, Iy1, Iy2;
gtk_canvas_simpleline_bounds_world (item, &Ix1, &Iy1, &Ix2, &Iy2);
gtk_canvas_update_bbox (item, Ix1, Iy1, Ix2, Iy2);
}
/*
* CANVAS CALLBACKS
*/
static void
gtk_canvas_simpleline_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GtkCanvasItem *item;
GtkCanvasSimpleLine *simpleline;
int redraw;
int calc_bounds;
item = GTK_CANVAS_ITEM (object);
simpleline = GTK_CANVAS_SIMPLELINE (object);
redraw = FALSE;
calc_bounds = FALSE;
switch (arg_id) {
case ARG_X1:
if (simpleline->x1 != GTK_VALUE_DOUBLE (*arg)) {
simpleline->x1 = GTK_VALUE_DOUBLE (*arg);
calc_bounds = TRUE;
}
break;
case ARG_Y1:
if (simpleline->y1 != GTK_VALUE_DOUBLE (*arg)) {
simpleline->y1 = GTK_VALUE_DOUBLE (*arg);
calc_bounds = TRUE;
}
break;
case ARG_X2:
if (simpleline->x2 != GTK_VALUE_DOUBLE (*arg)) {
simpleline->x2 = GTK_VALUE_DOUBLE (*arg);
calc_bounds = TRUE;
}
break;
case ARG_Y2:
if (simpleline->y2 != GTK_VALUE_DOUBLE (*arg)) {
simpleline->y2 = GTK_VALUE_DOUBLE (*arg);
calc_bounds = TRUE;
}
break;
case ARG_COLOR_RGBA:
if (simpleline->color != GTK_VALUE_INT(*arg)) {
simpleline->color = GTK_VALUE_INT(*arg);
UINT_TO_RGBA (simpleline->color, &simpleline->r, &simpleline->g, &simpleline->b, &simpleline->a);
redraw = TRUE;
}
break;
default:
break;
}
if (calc_bounds) {
gtk_canvas_item_request_update (item);
} else if (redraw) {
int Ix1, Ix2, Iy1, Iy2;
gtk_canvas_simpleline_bounds_world (item, &Ix1, &Iy1, &Ix2, &Iy2);
gtk_canvas_request_redraw (item->canvas, Ix1, Iy1, Ix2, Iy2);
}
}
static void
gtk_canvas_simpleline_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GtkCanvasSimpleLine *simpleline;
simpleline = GTK_CANVAS_SIMPLELINE (object);
switch (arg_id) {
case ARG_X1:
GTK_VALUE_DOUBLE (*arg) = simpleline->x1;
break;
case ARG_Y1:
GTK_VALUE_DOUBLE (*arg) = simpleline->y1;
break;
case ARG_X2:
GTK_VALUE_DOUBLE (*arg) = simpleline->x2;
break;
case ARG_Y2:
GTK_VALUE_DOUBLE (*arg) = simpleline->y2;
break;
case ARG_COLOR_RGBA:
GTK_VALUE_INT (*arg) = simpleline->color;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static void
gtk_canvas_simpleline_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
GtkCanvasSimpleLine *simpleline;
double x;
double y;
simpleline = GTK_CANVAS_SIMPLELINE (item);
if (parent_class->update)
(* parent_class->update) (item, affine, clip_path, flags);
gtk_canvas_simpleline_reset_bounds (item);
x = simpleline->x1;
y = simpleline->y1;
gtk_canvas_item_i2w (item, &x, &y);
gtk_canvas_w2c (GTK_CANVAS(item->canvas), x, y, &simpleline->bbox_ulx, &simpleline->bbox_uly);
x = simpleline->x2;
y = simpleline->y2;
gtk_canvas_item_i2w (item, &x, &y);
gtk_canvas_w2c (GTK_CANVAS(item->canvas), x, y, &simpleline->bbox_lrx, &simpleline->bbox_lry);
}
static void
gtk_canvas_simpleline_render (GtkCanvasItem *item,
GtkCanvasBuf *buf)
{
GtkCanvasSimpleLine *simpleline;
int end, begin;
simpleline = GTK_CANVAS_SIMPLELINE (item);
if (parent_class->render) {
(*parent_class->render) (item, buf);
}
if (buf->is_bg) {
gtk_canvas_buf_ensure_buf (buf);
buf->is_bg = FALSE;
}
// begin = MAX(simpleline->bbox_ulx,buf->rect.x0);
// end = MIN(simpleline->bbox_lrx,buf->rect.x1);
begin = simpleline->bbox_ulx;
end = simpleline->bbox_lrx;
if (simpleline->color != 0) {
if (simpleline->horizontal) {
PAINT_HORIZA(buf, simpleline->r, simpleline->g, simpleline->b, simpleline->a,
begin, end, simpleline->bbox_uly);
} else {
PAINT_VERTA(buf, simpleline->r, simpleline->g, simpleline->b, simpleline->a,
begin, simpleline->bbox_uly, simpleline->bbox_lry);
}
}
}
static void
gtk_canvas_simpleline_draw (GtkCanvasItem *item,
GdkDrawable *drawable,
int x, int y,
int width, int height)
{
GtkCanvasSimpleLine *simpleline;
simpleline = GTK_CANVAS_SIMPLELINE (item);
if (parent_class->draw) {
(* parent_class->draw) (item, drawable, x, y, width, height);
}
fprintf (stderr, "please don't use the CanvasSimpleLine item in a non-aa Canvas\n");
abort ();
}
static void
gtk_canvas_simpleline_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
GtkCanvasSimpleLine *simpleline = GTK_CANVAS_SIMPLELINE (item);
*x1 = simpleline->x1;
*y1 = simpleline->y1;
*x2 = simpleline->x2;
*y2 = simpleline->y2;
}
static double
gtk_canvas_simpleline_point (GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item)
{
GtkCanvasSimpleLine *simpleline;
double x1, y1, x2, y2;
double dx, dy;
simpleline = GTK_CANVAS_SIMPLELINE (item);
*actual_item = item;
/* Find the bounds for the rectangle plus its outline width */
gtk_canvas_simpleline_bounds (item, &x1, &y1, &x2, &y2);
/* Is point inside rectangle */
if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
return 0.0;
}
/* Point is outside rectangle */
if (x < x1)
dx = x1 - x;
else if (x > x2)
dx = x - x2;
else
dx = 0.0;
if (y < y1)
dy = y1 - y;
else if (y > y2)
dy = y - y2;
else
dy = 0.0;
return sqrt (dx * dx + dy * dy);
}

View File

@@ -0,0 +1,66 @@
/* gtk-canvas-simpleline.h: GtkCanvas item for simple rects
*
* Copyright (C) 2001 Paul Davis <pbd@op.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef __GTK_CANVAS_SIMPLELINE_H__
#define __GTK_CANVAS_SIMPLELINE_H__
#include <stdint.h>
#include <gtk-canvas/gtk-canvas-defs.h>
#include "gtk-canvas/gtk-canvas.h"
BEGIN_GTK_CANVAS_DECLS
/* Wave viewer item for canvas.
*/
#define GTK_CANVAS_TYPE_CANVAS_SIMPLELINE (gtk_canvas_simpleline_get_type ())
#define GTK_CANVAS_SIMPLELINE(obj) (GTK_CHECK_CAST ((obj), GTK_CANVAS_TYPE_CANVAS_SIMPLELINE, GtkCanvasSimpleLine))
#define GTK_CANVAS_SIMPLELINE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_CANVAS_TYPE_CANVAS_SIMPLELINE, GtkCanvasSimpleLineClass))
#define GTK_CANVAS_IS_CANVAS_SIMPLELINE(obj) (GTK_CHECK_TYPE ((obj), GTK_CANVAS_TYPE_CANVAS_SIMPLELINE))
#define GTK_CANVAS_IS_CANVAS_SIMPLELINE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_CANVAS_TYPE_CANVAS_SIMPLELINE))
typedef struct _GtkCanvasSimpleLine GtkCanvasSimpleLine;
typedef struct _GtkCanvasSimpleLineClass GtkCanvasSimpleLineClass;
struct _GtkCanvasSimpleLine
{
GtkCanvasItem item;
double x1, y1, x2, y2;
uint32_t color;
gboolean horizontal;
/* cached values set during update/used during render */
unsigned char r, b, g, a;
guint32 bbox_ulx, bbox_uly;
guint32 bbox_lrx, bbox_lry;
};
struct _GtkCanvasSimpleLineClass {
GtkCanvasItemClass parent_class;
};
GtkType gtk_canvas_simpleline_get_type (void);
END_GTK_CANVAS_DECLS
#endif /* __GTK_CANVAS_SIMPLELINE_H__ */

View File

@@ -0,0 +1,587 @@
#include <stdio.h>
#include <math.h>
#include <gtk-canvas.h>
#include "canvas-simplerect.h"
#include "rgb_macros.h"
enum {
ARG_0,
ARG_X1,
ARG_Y1,
ARG_X2,
ARG_Y2,
ARG_OUTLINE_PIXELS,
ARG_OUTLINE_WHAT,
ARG_FILL,
ARG_FILL_COLOR_RGBA,
ARG_OUTLINE_COLOR_RGBA,
ARG_DRAW
};
static void gtk_canvas_simplerect_class_init (GtkCanvasSimpleRectClass *class);
static void gtk_canvas_simplerect_init (GtkCanvasSimpleRect *simplerect);
static void gtk_canvas_simplerect_set_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_canvas_simplerect_get_arg (GtkObject *object,
GtkArg *arg,
guint arg_id);
static void gtk_canvas_simplerect_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
static void gtk_canvas_simplerect_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
static double gtk_canvas_simplerect_point (GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item);
static void gtk_canvas_simplerect_render (GtkCanvasItem *item, GtkCanvasBuf *buf);
static void gtk_canvas_simplerect_draw (GtkCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h);
static GtkCanvasItemClass *parent_class;
GtkType
gtk_canvas_simplerect_get_type (void)
{
static GtkType simplerect_type = 0;
if (!simplerect_type) {
GtkTypeInfo simplerect_info = {
"GtkCanvasSimpleRect",
sizeof (GtkCanvasSimpleRect),
sizeof (GtkCanvasSimpleRectClass),
(GtkClassInitFunc) gtk_canvas_simplerect_class_init,
(GtkObjectInitFunc) gtk_canvas_simplerect_init,
NULL, /* reserved_1 */
NULL, /* reserved_2 */
(GtkClassInitFunc) NULL
};
simplerect_type = gtk_type_unique (gtk_canvas_item_get_type (), &simplerect_info);
}
return simplerect_type;
}
static void
gtk_canvas_simplerect_class_init (GtkCanvasSimpleRectClass *class)
{
GtkObjectClass *object_class;
GtkCanvasItemClass *item_class;
object_class = (GtkObjectClass *) class;
item_class = (GtkCanvasItemClass *) class;
parent_class = gtk_type_class (gtk_canvas_item_get_type ());
gtk_object_add_arg_type ("GtkCanvasSimpleRect::x1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X1);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::y1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y1);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::x2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X2);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::y2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y2);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::fill", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_FILL);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::draw", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_DRAW);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::fill_color_rgba", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_FILL_COLOR_RGBA);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::outline_color_rgba", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_OUTLINE_COLOR_RGBA);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::outline_pixels", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_OUTLINE_PIXELS);
gtk_object_add_arg_type ("GtkCanvasSimpleRect::outline_what", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_OUTLINE_WHAT);
object_class->set_arg = gtk_canvas_simplerect_set_arg;
object_class->get_arg = gtk_canvas_simplerect_get_arg;
item_class->update = gtk_canvas_simplerect_update;
item_class->bounds = gtk_canvas_simplerect_bounds;
item_class->point = gtk_canvas_simplerect_point;
item_class->render = gtk_canvas_simplerect_render;
item_class->draw = gtk_canvas_simplerect_draw;
}
static void
gtk_canvas_simplerect_init (GtkCanvasSimpleRect *simplerect)
{
simplerect->x1 = 0.0;
simplerect->y1 = 0.0;
simplerect->x2 = 0.0;
simplerect->y2 = 0.0;
simplerect->fill = TRUE;
simplerect->draw = TRUE;
simplerect->full_draw_on_update = TRUE;
simplerect->fill_color = 0;
simplerect->outline_color = 0;
simplerect->outline_pixels = 1;
simplerect->outline_what = 0xf;
GTK_CANVAS_ITEM(simplerect)->object.flags |= GTK_CANVAS_ITEM_NO_AUTO_REDRAW;
}
static void
gtk_canvas_simplerect_bounds (GtkCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
{
GtkCanvasSimpleRect *simplerect = GTK_CANVAS_SIMPLERECT (item);
*x1 = simplerect->x1;
*y1 = simplerect->y1;
*x2 = simplerect->x2 + 1;
*y2 = simplerect->y2 + 1;
}
static void
gtk_canvas_simplerect_reset_bounds (GtkCanvasItem *item)
{
GtkCanvasSimpleRect* simplerect;
double x1, x2, y1, y2;
double old_x1, old_x2, old_y1, old_y2;
double a, b;
old_x1 = item->x1;
old_y1 = item->y1;
old_x2 = item->x2;
old_y2 = item->y2;
gtk_canvas_simplerect_bounds (item, &x1, &y1, &x2, &y2);
gtk_canvas_item_i2w (item, &x1, &y1);
gtk_canvas_item_i2w (item, &x2, &y2);
item->x1 = x1;
item->y1 = y1;
item->x2 = x2;
item->y2 = y2;
/* now compute bounding box in canvas units */
simplerect = GTK_CANVAS_SIMPLERECT (item);
gtk_canvas_w2c (GTK_CANVAS(item->canvas), x1, y1, &simplerect->bbox_ulx, &simplerect->bbox_uly);
gtk_canvas_w2c (GTK_CANVAS(item->canvas), x2, y2, &simplerect->bbox_lrx, &simplerect->bbox_lry);
/* now queue redraws for changed areas */
if (item->x1 != old_x1) {
/* left edge changed. redraw the area that altered */
a = MIN(item->x1, old_x1);
b = MAX(item->x1, old_x1);
gtk_canvas_request_redraw (item->canvas, a - 1, item->y1, b + 1, item->y2);
}
if (item->x2 != old_x2) {
/* right edge changed. redraw the area that altered */
a = MIN(item->x2, old_x2);
b = MAX(item->x2, old_x2);
gtk_canvas_request_redraw (item->canvas, a - 1, item->y1, b + 1, item->y2);
}
if (item->y1 != old_y1) {
/* top edge changed. redraw the area that altered */
a = MIN(item->y1, old_y1);
b = MAX(item->y1, old_y1);
gtk_canvas_request_redraw (item->canvas, item->x1, a - 1, item->x2, b + 1);
}
if (item->y2 != old_y2) {
/* lower edge changed. redraw the area that altered */
a = MIN(item->y2, old_y2);
b = MAX(item->y2, old_y2);
gtk_canvas_request_redraw (item->canvas, item->x1, a - 1, item->x2, b + 1);
}
}
/*
* CANVAS CALLBACKS
*/
static void
gtk_canvas_simplerect_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GtkCanvasItem *item;
GtkCanvasSimpleRect *simplerect;
int update;
int bounds_changed;
item = GTK_CANVAS_ITEM (object);
simplerect = GTK_CANVAS_SIMPLERECT (object);
update = FALSE;
bounds_changed = FALSE;
switch (arg_id) {
case ARG_X1:
if (simplerect->x1 != GTK_VALUE_DOUBLE (*arg)) {
simplerect->x1 = GTK_VALUE_DOUBLE (*arg);
bounds_changed = TRUE;
}
break;
case ARG_Y1:
if (simplerect->y1 != GTK_VALUE_DOUBLE (*arg)) {
simplerect->y1 = GTK_VALUE_DOUBLE (*arg);
bounds_changed = TRUE;
}
break;
case ARG_X2:
if (simplerect->x2 != GTK_VALUE_DOUBLE (*arg)) {
simplerect->x2 = GTK_VALUE_DOUBLE (*arg);
bounds_changed = TRUE;
}
break;
case ARG_Y2:
if (simplerect->y2 != GTK_VALUE_DOUBLE (*arg)) {
simplerect->y2 = GTK_VALUE_DOUBLE (*arg);
bounds_changed = TRUE;
}
break;
case ARG_DRAW:
if (simplerect->draw != GTK_VALUE_BOOL (*arg)) {
simplerect->draw = GTK_VALUE_BOOL (*arg);
update = TRUE;
}
break;
case ARG_FILL:
if (simplerect->fill != GTK_VALUE_BOOL (*arg)) {
simplerect->fill = GTK_VALUE_BOOL (*arg);
update = TRUE;
}
break;
case ARG_FILL_COLOR_RGBA:
if (simplerect->fill_color != GTK_VALUE_INT(*arg)) {
simplerect->fill_color = GTK_VALUE_INT(*arg);
update = TRUE;
}
break;
case ARG_OUTLINE_COLOR_RGBA:
if (simplerect->outline_color != GTK_VALUE_INT(*arg)) {
simplerect->outline_color = GTK_VALUE_INT(*arg);
update = TRUE;
}
break;
case ARG_OUTLINE_PIXELS:
if (simplerect->outline_pixels != GTK_VALUE_INT(*arg)) {
simplerect->outline_pixels = GTK_VALUE_INT(*arg);
update = TRUE;
}
break;
case ARG_OUTLINE_WHAT:
if (simplerect->outline_what != GTK_VALUE_INT(*arg)) {
simplerect->outline_what = GTK_VALUE_INT(*arg);
update = TRUE;
}
break;
default:
break;
}
simplerect->full_draw_on_update = update;
if (update || bounds_changed) {
gtk_canvas_item_request_update (item);
}
}
static void
gtk_canvas_simplerect_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
GtkCanvasSimpleRect *simplerect;
simplerect = GTK_CANVAS_SIMPLERECT (object);
switch (arg_id) {
case ARG_X1:
GTK_VALUE_DOUBLE (*arg) = simplerect->x1;
break;
case ARG_Y1:
GTK_VALUE_DOUBLE (*arg) = simplerect->y1;
break;
case ARG_X2:
GTK_VALUE_DOUBLE (*arg) = simplerect->x2;
break;
case ARG_Y2:
GTK_VALUE_DOUBLE (*arg) = simplerect->y2;
break;
case ARG_DRAW:
GTK_VALUE_BOOL (*arg) = simplerect->draw;
break;
case ARG_FILL:
GTK_VALUE_BOOL (*arg) = simplerect->fill;
break;
case ARG_FILL_COLOR_RGBA:
GTK_VALUE_INT (*arg) = simplerect->fill_color;
break;
case ARG_OUTLINE_COLOR_RGBA:
GTK_VALUE_INT (*arg) = simplerect->outline_color;
break;
case ARG_OUTLINE_PIXELS:
GTK_VALUE_INT (*arg) = simplerect->outline_pixels;
break;
case ARG_OUTLINE_WHAT:
GTK_VALUE_INT (*arg) = simplerect->outline_what;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
}
}
static void
gtk_canvas_simplerect_update (GtkCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
{
GtkCanvasSimpleRect *simplerect;
unsigned char foo;
simplerect = GTK_CANVAS_SIMPLERECT (item);
if (parent_class->update)
(* parent_class->update) (item, affine, clip_path, flags);
gtk_canvas_simplerect_reset_bounds (item);
if (simplerect->full_draw_on_update) {
gtk_canvas_request_redraw (item->canvas,
simplerect->bbox_ulx,
simplerect->bbox_uly,
simplerect->bbox_lrx+1,
simplerect->bbox_lry+1);
simplerect->full_draw_on_update = FALSE;
}
UINT_TO_RGBA (simplerect->fill_color, &simplerect->fill_r, &simplerect->fill_g, &simplerect->fill_b, &simplerect->fill_a);
UINT_TO_RGBA (simplerect->outline_color, &simplerect->outline_r, &simplerect->outline_g, &simplerect->outline_b, &foo);
}
#define SIMPLERECT_FAST_RENDERER
#ifdef SIMPLERECT_FAST_RENDERER
static void
gtk_canvas_simplerect_render (GtkCanvasItem *item,
GtkCanvasBuf *buf)
{
GtkCanvasSimpleRect *simplerect;
int end, begin;
int ey, sy;
unsigned int i;
ArtIRect intersection;
ArtIRect self;
simplerect = GTK_CANVAS_SIMPLERECT (item);
if (parent_class->render) {
(*parent_class->render) (item, buf);
}
if (buf->is_bg) {
// this can be useful for debugging/understanding how the canvas redraws
// stuff.
// gint randr, randg, randb;
// randr = random() % 255;
// randg = random() % 255;
// randb = random() % 255;
// PAINT_BOX(buf, randr, randg, randb, 255, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1);
gtk_canvas_buf_ensure_buf (buf);
buf->is_bg = FALSE;
}
if (!simplerect->draw) {
return;
}
self.x0 = simplerect->bbox_ulx;
self.y0 = simplerect->bbox_uly;
self.x1 = simplerect->bbox_lrx;
self.y1 = simplerect->bbox_lry;
art_irect_intersect (&intersection, &self, &buf->rect);
begin = MAX(simplerect->bbox_ulx, buf->rect.x0);
end = MIN((simplerect->bbox_lrx-1), buf->rect.x1);
sy = simplerect->bbox_uly;
ey = simplerect->bbox_lry-1;
if (simplerect->fill) {
// this can be useful for debugging/understanding how the canvas redraws
// stuff.
// gint randr, randg, randb;
// randr = random() % 255;
// randg = random() % 255;
// randb = random() % 255;
// PAINT_BOX(buf, randr, randg, randb, simplerect->fill_a, begin, sy, end, ey);
FAST_PAINT_BOX (buf, simplerect->fill_r, simplerect->fill_g, simplerect->fill_b, simplerect->fill_a,
intersection.x0, intersection.y0,
intersection.x1, intersection.y1);
}
for (i = 0; i < simplerect->outline_pixels; ++i) {
if (simplerect->outline_what & 0x1) {
if (begin == simplerect->bbox_ulx) {
PAINT_VERT(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin + i, sy, ey);
}
}
if (simplerect->outline_what & 0x2) {
if (end == (simplerect->bbox_lrx - 1)) {
PAINT_VERT(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, end - i, sy, ey + 1);
}
}
if (simplerect->outline_what & 0x4) {
PAINT_HORIZ(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin, end, sy+i);
}
if (simplerect->outline_what & 0x8) {
PAINT_HORIZ(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin, end + 1, ey-i);
}
}
}
#else /* SIMPLERECT_FAST_RENDERER */
static void
gtk_canvas_simplerect_render (GtkCanvasItem *item,
GtkCanvasBuf *buf)
{
GtkCanvasSimpleRect *simplerect;
int end, begin;
int ey, sy;
unsigned int i;
simplerect = GTK_CANVAS_SIMPLERECT (item);
if (parent_class->render) {
(*parent_class->render) (item, buf);
}
if (buf->is_bg) {
// this can be useful for debugging/understanding how the canvas redraws
// stuff.
// gint randr, randg, randb;
// randr = random() % 255;
// randg = random() % 255;
// randb = random() % 255;
// PAINT_BOX(buf, randr, randg, randb, 255, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1);
gtk_canvas_buf_ensure_buf (buf);
buf->is_bg = FALSE;
}
if (!simplerect->draw) {
return;
}
begin = MAX(simplerect->bbox_ulx,buf->rect.x0);
end = MIN((simplerect->bbox_lrx-1),buf->rect.x1);
sy = simplerect->bbox_uly;
ey = simplerect->bbox_lry-1;
if (simplerect->fill) {
// this can be useful for debugging/understanding how the canvas redraws
// stuff.
// gint randr, randg, randb;
// randr = random() % 255;
// randg = random() % 255;
// randb = random() % 255;
// PAINT_BOX(buf, randr, randg, randb, simplerect->fill_a, begin, sy, end, ey);
PAINT_BOX(buf, simplerect->fill_r, simplerect->fill_g, simplerect->fill_b, simplerect->fill_a, begin, sy, end, ey);
}
for (i = 0; i < simplerect->outline_pixels; ++i) {
if (simplerect->outline_what & 0x1) {
if (begin == simplerect->bbox_ulx) {
PAINT_VERT(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin + i, sy, ey);
}
}
if (simplerect->outline_what & 0x2) {
if (end == (simplerect->bbox_lrx - 1)) {
PAINT_VERT(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, end - i, sy, ey + 1);
}
}
if (simplerect->outline_what & 0x4) {
PAINT_HORIZ(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin, end, sy+i);
}
if (simplerect->outline_what & 0x8) {
PAINT_HORIZ(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, begin, end + 1, ey-i);
}
}
}
#endif /* SIMPLERECT_FAST_RENDERER */
static void
gtk_canvas_simplerect_draw (GtkCanvasItem *item,
GdkDrawable *drawable,
int x, int y,
int width, int height)
{
fprintf (stderr, "please don't use the CanvasSimpleRect item in a non-aa Canvas\n");
abort ();
}
static double
gtk_canvas_simplerect_point (GtkCanvasItem *item, double x, double y, int cx, int cy, GtkCanvasItem **actual_item)
{
GtkCanvasSimpleRect *simplerect;
double x1, y1, x2, y2;
double dx, dy;
simplerect = GTK_CANVAS_SIMPLERECT (item);
*actual_item = item;
/* Find the bounds for the rectangle plus its outline width */
gtk_canvas_simplerect_bounds (item, &x1, &y1, &x2, &y2);
/* Is point inside rectangle */
if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
return 0.0;
}
/* Point is outside rectangle */
if (x < x1)
dx = x1 - x;
else if (x > x2)
dx = x - x2;
else
dx = 0.0;
if (y < y1)
dy = y1 - y;
else if (y > y2)
dy = y - y2;
else
dy = 0.0;
return sqrt (dx * dx + dy * dy);
}

View File

@@ -0,0 +1,72 @@
/* gtk-canvas-simplerect.h: GtkCanvas item for simple rects
*
* Copyright (C) 2001 Paul Davis <pbd@op.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef __GTK_CANVAS_SIMPLERECT_H__
#define __GTK_CANVAS_SIMPLERECT_H__
#include <stdint.h>
#include <gtk-canvas/gtk-canvas-defs.h>
#include "gtk-canvas/gtk-canvas.h"
BEGIN_GTK_CANVAS_DECLS
/* Wave viewer item for canvas.
*/
#define GTK_CANVAS_TYPE_CANVAS_SIMPLERECT (gtk_canvas_simplerect_get_type ())
#define GTK_CANVAS_SIMPLERECT(obj) (GTK_CHECK_CAST ((obj), GTK_CANVAS_TYPE_CANVAS_SIMPLERECT, GtkCanvasSimpleRect))
#define GTK_CANVAS_SIMPLERECT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_CANVAS_TYPE_CANVAS_SIMPLERECT, GtkCanvasSimpleRectClass))
#define GTK_CANVAS_IS_CANVAS_SIMPLERECT(obj) (GTK_CHECK_TYPE ((obj), GTK_CANVAS_TYPE_CANVAS_SIMPLERECT))
#define GTK_CANVAS_IS_CANVAS_SIMPLERECT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_CANVAS_TYPE_CANVAS_SIMPLERECT))
typedef struct _GtkCanvasSimpleRect GtkCanvasSimpleRect;
typedef struct _GtkCanvasSimpleRectClass GtkCanvasSimpleRectClass;
struct _GtkCanvasSimpleRect
{
GtkCanvasItem item;
double x1, y1, x2, y2;
gboolean fill;
gboolean draw;
gboolean full_draw_on_update;
uint32_t fill_color;
uint32_t outline_color;
uint32_t outline_pixels;
/* cached values set during update/used during render */
unsigned char fill_r, fill_b, fill_g, fill_a;
unsigned char outline_r, outline_b, outline_g;
unsigned char outline_what;
guint32 bbox_ulx, bbox_uly;
guint32 bbox_lrx, bbox_lry;
};
struct _GtkCanvasSimpleRectClass {
GtkCanvasItemClass parent_class;
};
GtkType gtk_canvas_simplerect_get_type (void);
END_GTK_CANVAS_DECLS
#endif /* __GTK_CANVAS_SIMPLERECT_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,128 @@
/* gtk-canvas-waveview.h: GtkCanvas item for displaying wave data
*
* Copyright (C) 2001 Paul Davis <pbd@op.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef __GTK_CANVAS_WAVEVIEW_H__
#define __GTK_CANVAS_WAVEVIEW_H__
#include <stdint.h>
#include <gtk-canvas/gtk-canvas-defs.h>
#include "gtk-canvas/gtk-canvas.h"
BEGIN_GTK_CANVAS_DECLS
/* Wave viewer item for canvas.
*/
#define GTK_CANVAS_TYPE_CANVAS_WAVEVIEW (gtk_canvas_waveview_get_type ())
#define GTK_CANVAS_WAVEVIEW(obj) (GTK_CHECK_CAST ((obj), GTK_CANVAS_TYPE_CANVAS_WAVEVIEW, GtkCanvasWaveView))
#define GTK_CANVAS_WAVEVIEW_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_CANVAS_TYPE_CANVAS_WAVEVIEW, GtkCanvasWaveViewClass))
#define GTK_CANVAS_IS_CANVAS_WAVEVIEW(obj) (GTK_CHECK_TYPE ((obj), GTK_CANVAS_TYPE_CANVAS_WAVEVIEW))
#define GTK_CANVAS_IS_CANVAS_WAVEVIEW_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_CANVAS_TYPE_CANVAS_WAVEVIEW))
typedef struct _GtkCanvasWaveView GtkCanvasWaveView;
typedef struct _GtkCanvasWaveViewClass GtkCanvasWaveViewClass;
typedef struct _GtkCanvasWaveViewChannelInfo GtkCanvasWaveViewChannelInfo;
typedef struct _GtkCanvasWaveViewCacheEntry GtkCanvasWaveViewCacheEntry;
typedef struct _GtkCanvasWaveViewCache GtkCanvasWaveViewCache;
/* XXX this needs to be synced with ardour/source.h PeakData */
struct _GtkCanvasWaveViewCacheEntry
{
float min;
float max;
};
struct _GtkCanvasWaveViewCache
{
GtkCanvasWaveViewCacheEntry* data;
gint32 allocated;
gint32 data_size;
gulong start;
gulong end;
};
GtkCanvasWaveViewCache* gtk_canvas_waveview_cache_new ();
void gtk_canvas_waveview_cache_destroy (GtkCanvasWaveViewCache*);
struct _GtkCanvasWaveView
{
GtkCanvasItem item;
GtkCanvasWaveViewCache *cache;
gboolean cache_updater;
gint screen_width;
void *data_src;
guint32 channel;
void (*peak_function)(void*,gulong,gulong,gulong,gpointer,guint32,double);
gulong (*length_function)(void *);
gulong (*sourcefile_length_function)(void*);
void (*gain_curve_function)(void *arg, double start, double end, float* vector, guint32 veclen);
void *gain_src;
/* x-axis: samples per canvas unit. */
double samples_per_unit;
/* y-axis: amplitude_above_axis.
*
* the default is that an (scaled, normalized -1.0 ... +1.0) amplitude of 1.0
* corresponds to the top of the area assigned to the waveview.
*
* larger values will expand the vertical scale, cutting off the peaks/troughs.
* smaller values will decrease the vertical scale, moving peaks/troughs toward
* the middle of the area assigned to the waveview.
*/
double amplitude_above_axis;
double x;
double y;
double height;
double half_height;
uint32_t wave_color;
char rectified;
/* These are updated by the update() routine
to optimize the render() routine, which may
be called several times after a single update().
*/
int32_t bbox_ulx;
int32_t bbox_uly;
int32_t bbox_lrx;
int32_t bbox_lry;
unsigned char wave_r, wave_g, wave_b, wave_a;
uint32_t samples;
uint32_t region_start;
int32_t reload_cache_in_render;
};
struct _GtkCanvasWaveViewClass {
GtkCanvasItemClass parent_class;
};
GtkType gtk_canvas_waveview_get_type (void);
END_GTK_CANVAS_DECLS
#endif /* __GTK_CANVAS_WAVEVIEW_H__ */

50
gtk2_ardour/check_mark.h Normal file
View File

@@ -0,0 +1,50 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
static const gchar* check_xpm[] = {
"13 10 3 1",
" c None",
". c #000000",
"+ c #FFFFFF",
" .. ",
" ++++++++.++.",
" + .++. ",
" +. .++.+ ",
" .+. .++. + ",
".+++..++. + ",
" .+++++. + ",
" +.+++. + ",
" ++.+.++++++ ",
" . "};
static const gchar* empty_xpm[] = {
"13 10 2 1",
" c None",
"+ c #FFFFFF",
" ",
" +++++++++++ ",
" + + ",
" + + ",
" + + ",
" + + ",
" + + ",
" + + ",
" +++++++++++ ",
" ",};

View File

@@ -0,0 +1,692 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <stdint.h>
#include <gtkmmext/gtk_ui.h>
#include <gtkmmext/utils.h>
#include <sigc++/bind.h>
#include "connection_editor.h"
#include <ardour/session.h>
#include <ardour/session_connection.h>
#include <ardour/audioengine.h>
#include <ardour/connection.h>
#include "utils.h"
#include "keyboard.h"
#include "prompter.h"
#include "i18n.h"
#include <inttypes.h>
using namespace std;
using namespace ARDOUR;
using namespace Gtk;
using namespace SigC;
ConnectionEditor::ConnectionEditor ()
: ArdourDialog ("connection editor"),
input_connection_display (1),
output_connection_display (1),
input_frame (_("Input Connections")),
output_frame (_("Output Connections")),
new_input_connection_button (_("New Input")),
new_output_connection_button (_("New Output")),
delete_connection_button (_("Delete")),
clear_button (_("Clear")),
add_port_button (_("Add Port")),
ok_button (_("Close")),
cancel_button (_("Cancel")),
rescan_button (_("Rescan"))
{
add_events (GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK);
session = 0;
selected_port = -1;
current_connection = 0;
push_at_front = false;
set_name ("ConnectionEditorWindow");
ok_button.set_name ("ConnectionEditorButton");
cancel_button.set_name ("ConnectionEditorButton");
rescan_button.set_name ("ConnectionEditorButton");
new_input_connection_button.set_name ("ConnectionEditorButton");
new_output_connection_button.set_name ("ConnectionEditorButton");
clear_button.set_name ("ConnectionEditorButton");
button_frame.set_name ("ConnectionEditorFrame");
input_frame.set_name ("ConnectionEditorFrame");
output_frame.set_name ("ConnectionEditorFrame");
button_box.set_spacing (15);
button_box.set_border_width (5);
Gtkmmext::set_usize_to_display_given_text (ok_button, _("OK"), 40, 15);
button_box.pack_end (ok_button, false, false);
// button_box.pack_end (cancel_button, false, false);
cancel_button.hide();
button_frame.add (button_box);
ok_button.clicked.connect (slot (*this, &ConnectionEditor::accept));
cancel_button.clicked.connect (slot (*this, &ConnectionEditor::cancel));
cancel_button.clicked.connect (slot (*this, &ConnectionEditor::rescan));
notebook.set_name ("ConnectionEditorNotebook");
notebook.set_usize (-1, 125);
clear_button.set_name ("ConnectionEditorButton");
add_port_button.set_name ("ConnectionEditorButton");
Gtkmmext::set_usize_to_display_given_text (add_port_button, _("Add Port"), 35, 15);
selector_frame.set_name ("ConnectionEditorFrame");
port_frame.set_name ("ConnectionEditorFrame");
selector_frame.set_label (_("Available Ports"));
selector_button_box.set_spacing (5);
selector_button_box.set_border_width (5);
Gtkmmext::set_usize_to_display_given_text (rescan_button, _("Rescan"), 35, 15);
selector_button_box.pack_start (rescan_button, false, false);
selector_box.set_spacing (5);
selector_box.set_border_width (5);
selector_box.pack_start (notebook);
selector_box.pack_start (selector_button_box);
selector_frame.add (selector_box);
port_box.set_spacing (5);
port_box.set_border_width (3);
port_button_box.set_spacing (5);
port_button_box.set_border_width (2);
port_button_box.pack_start (add_port_button, false, false);
port_and_button_box.set_border_width (5);
port_and_button_box.pack_start (port_button_box, false, false);
port_and_button_box.pack_start (port_box);
port_frame.add (port_and_button_box);
port_and_selector_box.set_spacing (5);
port_and_selector_box.pack_start (port_frame);
port_and_selector_box.pack_start (selector_frame);
right_vbox.set_spacing (5);
right_vbox.set_border_width (5);
right_vbox.pack_start (port_and_selector_box);
input_connection_display.set_shadow_type (GTK_SHADOW_IN);
input_connection_display.set_selection_mode (GTK_SELECTION_SINGLE);
input_connection_display.set_usize (80, -1);
input_connection_display.set_name ("ConnectionEditorConnectionList");
input_connection_display.select_row.connect (bind (slot (*this, &ConnectionEditor::connection_selected), true));
output_connection_display.set_shadow_type (GTK_SHADOW_IN);
output_connection_display.set_selection_mode (GTK_SELECTION_SINGLE);
output_connection_display.set_usize (80, -1);
output_connection_display.set_name ("ConnectionEditorConnectionList");
output_connection_display.select_row.connect (bind (slot (*this, &ConnectionEditor::connection_selected), false));
input_scroller.set_policy (GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
output_scroller.set_policy (GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
input_scroller.add_with_viewport (input_connection_display);
output_scroller.add_with_viewport (output_connection_display);
input_box.set_border_width (5);
input_box.set_spacing (5);
input_box.pack_start (input_scroller);
input_box.pack_start (new_input_connection_button, false, false);
input_frame.add (input_box);
output_box.set_border_width (5);
output_box.set_spacing (5);
output_box.pack_start (output_scroller);
output_box.pack_start (new_output_connection_button, false, false);
output_frame.add (output_box);
connection_box.set_spacing (5);
connection_box.pack_start (input_frame);
connection_box.pack_start (output_frame);
left_vbox.set_spacing (5);
left_vbox.pack_start (connection_box);
main_hbox.set_border_width (10);
main_hbox.set_spacing (5);
main_hbox.pack_start (left_vbox);
main_hbox.pack_start (right_vbox);
main_vbox.set_border_width (10);
main_vbox.set_spacing (5);
main_vbox.pack_start (main_hbox);
main_vbox.pack_start (button_frame, false, false);
set_title (_("ardour: connections"));
add (main_vbox);
delete_event.connect (bind (slot (just_hide_it), reinterpret_cast<Window *> (this)));
clear_button.clicked.connect (slot (*this, &ConnectionEditor::clear));
add_port_button.clicked.connect (slot (*this, &ConnectionEditor::add_port));
new_input_connection_button.clicked.connect (bind (slot (*this, &ConnectionEditor::new_connection), true));
new_output_connection_button.clicked.connect (bind (slot (*this, &ConnectionEditor::new_connection), false));
delete_connection_button.clicked.connect (slot (*this, &ConnectionEditor::delete_connection));
}
ConnectionEditor::~ConnectionEditor()
{
}
void
ConnectionEditor::set_session (Session *s)
{
if (s != session) {
ArdourDialog::set_session (s);
if (session) {
session->ConnectionAdded.connect (slot (*this, &ConnectionEditor::proxy_add_connection_and_select));
session->ConnectionRemoved.connect (slot (*this, &ConnectionEditor::proxy_remove_connection));
} else {
hide ();
}
}
}
void
ConnectionEditor::rescan ()
{
refill_connection_display ();
display_ports ();
}
void
ConnectionEditor::cancel ()
{
hide ();
}
void
ConnectionEditor::accept ()
{
hide ();
}
void
ConnectionEditor::clear ()
{
if (current_connection) {
current_connection->clear ();
}
}
gint
ConnectionEditor::map_event_impl (GdkEventAny *ev)
{
refill_connection_display ();
return Window::map_event_impl (ev);
}
void
ConnectionEditor::add_connection (ARDOUR::Connection *connection)
{
using namespace CList_Helpers;
const char *rowtext[1];
rowtext[0] = connection->name().c_str();
if (dynamic_cast<InputConnection *> (connection)) {
if (push_at_front) {
input_connection_display.rows().push_front (rowtext);
input_connection_display.rows().front().set_data (connection);
} else {
input_connection_display.rows().push_back (rowtext);
input_connection_display.rows().back().set_data (connection);
}
} else {
if (push_at_front) {
output_connection_display.rows().push_front (rowtext);
output_connection_display.rows().front().set_data (connection);
} else {
output_connection_display.rows().push_back (rowtext);
output_connection_display.rows().back().set_data (connection);
}
}
}
void
ConnectionEditor::remove_connection (ARDOUR::Connection *connection)
{
using namespace Gtk::CList_Helpers;
RowList::iterator i;
RowList* rlist;
if (dynamic_cast<InputConnection *> (connection)) {
rlist = &input_connection_display.rows();
} else {
rlist = &output_connection_display.rows();
}
if ((i = rlist->find_data (connection)) != rlist->end()) {
rlist->erase (i);
}
}
void
ConnectionEditor::proxy_add_connection_and_select (ARDOUR::Connection *connection)
{
Gtkmmext::UI::instance()->call_slot (bind (slot (*this, &ConnectionEditor::add_connection_and_select), connection));
}
void
ConnectionEditor::proxy_remove_connection (ARDOUR::Connection *connection)
{
Gtkmmext::UI::instance()->call_slot (bind (slot (*this, &ConnectionEditor::remove_connection), connection));
}
void
ConnectionEditor::add_connection_and_select (ARDOUR::Connection *connection)
{
add_connection (connection);
if (dynamic_cast<InputConnection *> (connection)) {
input_connection_display.rows().front().select ();
} else {
output_connection_display.rows().front().select ();
}
}
void
ConnectionEditor::refill_connection_display ()
{
input_connection_display.clear();
output_connection_display.clear();
current_connection = 0;
if (session) {
session->foreach_connection (this, &ConnectionEditor::add_connection);
}
}
void
ConnectionEditor::connection_selected (gint row, gint col, GdkEvent *ev, bool input)
{
ARDOUR::Connection *old_current = current_connection;
if (input) {
output_connection_display.unselect_all ();
current_connection = reinterpret_cast<ARDOUR::Connection*> (input_connection_display.row(row).get_data());
} else {
input_connection_display.unselect_all ();
current_connection = reinterpret_cast<ARDOUR::Connection*> (output_connection_display.row(row).get_data());
}
if (old_current != current_connection) {
config_connection.disconnect ();
connect_connection.disconnect ();
}
if (current_connection) {
config_connection = current_connection->ConfigurationChanged.connect
(bind (slot (*this, &ConnectionEditor::configuration_changed), input));
connect_connection = current_connection->ConnectionsChanged.connect
(bind (slot (*this, &ConnectionEditor::connections_changed), input));
}
display_connection_state (input);
display_ports ();
}
void
ConnectionEditor::configuration_changed (bool for_input)
{
display_connection_state (for_input);
}
void
ConnectionEditor::connections_changed (int which_port, bool for_input)
{
display_connection_state (for_input);
}
void
ConnectionEditor::display_ports ()
{
if (session == 0 || current_connection == 0) {
return;
}
using namespace Notebook_Helpers;
using namespace CList_Helpers;
typedef map<string,vector<pair<string,string> > > PortMap;
PortMap portmap;
const char **ports;
PageList& pages = notebook.pages();
gint current_page;
vector<string> rowdata;
bool for_input;
current_page = notebook.get_current_page_num ();
pages.clear ();
/* get relevant current JACK ports */
for_input = (dynamic_cast<InputConnection *> (current_connection) != 0);
ports = session->engine().get_ports ("", JACK_DEFAULT_AUDIO_TYPE, for_input?JackPortIsOutput:JackPortIsInput);
if (ports == 0) {
return;
}
/* find all the client names and group their ports into a list-by-client */
for (int n = 0; ports[n]; ++n) {
pair<string,vector<pair<string,string> > > newpair;
pair<string,string> strpair;
pair<PortMap::iterator,bool> result;
string str = ports[n];
string::size_type pos;
string portname;
pos = str.find (':');
newpair.first = str.substr (0, pos);
portname = str.substr (pos+1);
result = portmap.insert (newpair);
strpair.first = portname;
strpair.second = str;
result.first->second.push_back (strpair);
}
PortMap::iterator i;
for (i = portmap.begin(); i != portmap.end(); ++i) {
Box *client_box = manage (new VBox);
Gtk::CList *client_port_display = manage (new Gtk::CList (1));
ScrolledWindow *scroller = manage (new ScrolledWindow);
scroller->add_with_viewport (*client_port_display);
scroller->set_policy (GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
client_box->pack_start (*scroller);
client_port_display->set_selection_mode (GTK_SELECTION_BROWSE);
client_port_display->set_name ("ConnectionEditorList");
for (vector<pair<string,string> >::iterator s = i->second.begin(); s != i->second.end(); ++s) {
rowdata.clear ();
rowdata.push_back (s->first);
client_port_display->rows().push_back (rowdata);
client_port_display->rows().back().set_data (g_strdup (s->second.c_str()), free);
}
client_port_display->columns_autosize ();
client_port_display->select_row.connect (bind (slot (*this, &ConnectionEditor::port_selection_handler), client_port_display));
Label *tab_label = manage (new Label);
tab_label->set_name ("ConnectionEditorNotebookTab");
tab_label->set_text ((*i).first);
pages.push_back (TabElem (*client_box, *tab_label));
}
notebook.set_page (current_page);
notebook.show.connect (bind (slot (notebook, &Notebook::set_page), current_page));
selector_box.show_all ();
}
void
ConnectionEditor::display_connection_state (bool for_input)
{
LockMonitor lm (port_display_lock, __LINE__, __FILE__);
uint32_t limit;
if (session == 0 || current_connection == 0) {
return;
}
string frame_label = _("Connection \"");
frame_label += current_connection->name();
frame_label += _("\"");
port_frame.set_label (frame_label);
for (slist<ScrolledWindow *>::iterator i = port_displays.begin(); i != port_displays.end(); ) {
slist<ScrolledWindow *>::iterator tmp;
tmp = i;
tmp++;
port_box.remove (**i);
delete *i;
port_displays.erase (i);
i = tmp;
}
limit = current_connection->nports();
for (uint32_t n = 0; n < limit; ++n) {
CList *clist;
ScrolledWindow *scroller;
const gchar *title[1];
char buf[32];
string really_short_name;
if (for_input) {
snprintf(buf, sizeof(buf)-1, _("in %d"), n+1);
} else {
snprintf(buf, sizeof(buf)-1, _("out %d"), n+1);
}
title[0] = buf;
clist = manage (new CList (1, title));
scroller = new ScrolledWindow;
scroller->add_with_viewport (*clist);
scroller->set_policy (GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
port_displays.insert (port_displays.end(), scroller);
port_box.pack_start (*scroller);
clist->set_data ("port", (gpointer) ((intptr_t) n));
clist->set_name ("ConnectionEditorPortList");
clist->click_column.connect (bind (slot (*this, &ConnectionEditor::port_column_click), clist));
clist->set_selection_mode (GTK_SELECTION_SINGLE);
clist->set_shadow_type (GTK_SHADOW_IN);
scroller->set_usize (-1, 75);
/* now fill the clist with the current connections */
const ARDOUR::Connection::PortList& connections = current_connection->port_connections (n);
for (ARDOUR::Connection::PortList::const_iterator i = connections.begin(); i != connections.end(); ++i) {
const gchar *data[1];
data[0] = (*i).c_str();
clist->rows().push_back (data);
}
clist->columns_autosize ();
clist->button_release_event.connect (bind (slot (*this, &ConnectionEditor::port_button_event), clist));
}
port_box.show_all ();
}
void
ConnectionEditor::port_selection_handler (gint row, gint col, GdkEvent *ev, Gtk::CList *clist)
{
using namespace CList_Helpers;
string other_port_name = (char *) clist->rows()[row].get_data();
if (current_connection && selected_port >= 0) {
current_connection->add_connection (selected_port, other_port_name);
}
}
void
ConnectionEditor::add_port ()
{
if (current_connection) {
current_connection->add_port ();
}
}
void
ConnectionEditor::port_column_click (gint col, CList *clist)
{
/* Gack. CList's don't respond visually to a change
in their state, so rename them to force a style
switch.
*/
LockMonitor lm (port_display_lock, __LINE__, __FILE__);
int which_port = reinterpret_cast<intptr_t> (clist->get_data ("port"));
if (which_port != selected_port) {
selected_port = which_port;
display_ports ();
clist->set_name ("ConnectionEditorPortListSelected");
for (slist<ScrolledWindow *>::iterator i = port_displays.begin(); i != port_displays.end(); ++i) {
Widget *child = (*i)->get_child();
if (static_cast<CList *> (child) != clist) {
child->set_name ("ConnectionEditorPortList");
child->queue_draw ();
}
}
} else {
selected_port = -1;
clist->set_name ("ConnectionEditorPortList");
clist->queue_draw();
}
}
gint
ConnectionEditor::connection_click (GdkEventButton *ev, CList *clist)
{
gint row, col;
if (clist->get_selection_info ((int)ev->x, (int)ev->y, &row, &col) == 0) {
return FALSE;
}
current_connection = reinterpret_cast<ARDOUR::Connection *> (clist->row(row).get_data ());
return TRUE;
}
void
ConnectionEditor::new_connection (bool for_input)
{
if (session == 0) {
return;
}
ArdourPrompter prompter (true);
prompter.set_prompt (_("Name for new connection:"));
prompter.done.connect (Gtk::Main::quit.slot());
prompter.show_all();
Gtk::Main::run();
if (prompter.status == Gtkmmext::Prompter::entered) {
string name;
prompter.get_result (name);
push_at_front = true;
if (name.length()) {
if (for_input) {
session->add_connection (new ARDOUR::InputConnection (name));
} else {
session->add_connection (new ARDOUR::OutputConnection (name));
}
}
push_at_front = false;
}
}
void
ConnectionEditor::delete_connection ()
{
if (session && current_connection) {
session->remove_connection (current_connection);
current_connection = 0;
}
}
gint
ConnectionEditor::port_button_event (GdkEventButton *ev, CList *clist)
{
int row, col;
if (current_connection == 0) {
return FALSE;
}
if (clist->get_selection_info ((int) ev->x, (int) ev->y, &row, &col) == 0) {
return FALSE;
}
if (!(Keyboard::is_delete_event (ev))) {
return FALSE;
}
string port_name = clist->cell (row, col).get_text ();
int which_port = (intptr_t) clist->get_data ("port");
current_connection->remove_connection (which_port, port_name);
return TRUE;
}

View File

@@ -0,0 +1,147 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_gtk_connection_editor_h__
#define __ardour_gtk_connection_editor_h__
#if __GNUC__ >= 3
#include <ext/slist>
using __gnu_cxx::slist;
#else
#include <slist.h>
#endif
#include <gtk--/box.h>
#include <gtk--/window.h>
#include <gtk--/scrolledwindow.h>
#include <gtk--/button.h>
#include <gtk--/frame.h>
#include <gtk--/notebook.h>
#include <gtk--/clist.h>
#include "ardour_dialog.h"
#include <pbd/lockmonitor.h>
namespace ARDOUR {
class Session;
class Connection;
}
class ConnectionEditor : public ArdourDialog {
public:
ConnectionEditor ();
~ConnectionEditor ();
void set_session (ARDOUR::Session *);
protected:
gint map_event_impl (GdkEventAny *);
private:
ARDOUR::Connection *current_connection;
int selected_port;
bool push_at_front;
Gtk::CList input_connection_display;
Gtk::CList output_connection_display;
Gtk::ScrolledWindow input_scroller;
Gtk::ScrolledWindow output_scroller;
Gtk::Frame input_frame;
Gtk::Frame output_frame;
Gtk::VBox input_box;
Gtk::VBox output_box;
Gtk::VBox connection_box;
Gtk::HBox main_hbox;
Gtk::VBox main_vbox;
Gtk::VBox left_vbox;
Gtk::VBox right_vbox;
Gtk::VBox port_and_selector_box;
Gtk::Button new_input_connection_button;
Gtk::Button new_output_connection_button;
Gtk::Button delete_connection_button;
/* client/port selection */
Gtk::Notebook notebook;
Gtk::Button clear_client_button;
Gtk::Frame selector_frame;
Gtk::VBox selector_box;
Gtk::HBox selector_button_box;
/* connection displays */
Gtk::HBox port_box;
Gtk::HBox port_button_box;
Gtk::VBox port_and_button_box;
Gtk::Frame port_frame;
Gtk::Button clear_button;
Gtk::Button add_port_button;
PBD::Lock port_display_lock;
slist<Gtk::ScrolledWindow *> port_displays;
Gtk::Button ok_button;
Gtk::Button cancel_button;
Gtk::Button rescan_button;
Gtk::Frame button_frame;
Gtk::HBox button_box;
void new_connection (bool for_input);
void delete_connection ();
void display_ports ();
void display_connection_state (bool for_input);
void add_connection (ARDOUR::Connection *);
void add_connection_and_select (ARDOUR::Connection *);
void proxy_add_connection_and_select (ARDOUR::Connection *);
void proxy_remove_connection (ARDOUR::Connection *);
void remove_connection (ARDOUR::Connection *);
void refill_connection_display ();
void rescan ();
void clear ();
void cancel ();
void accept ();
void port_selection_handler (gint row, gint col, GdkEvent *ev, Gtk::CList *);
void add_port ();
void remove_port (int which_port);
void port_column_click (gint col, Gtk::CList *clist);
gint port_button_event (GdkEventButton *, Gtk::CList *clist);
gint connection_click (GdkEventButton *ev, Gtk::CList *clist);
void connection_selected (gint, gint, GdkEvent *, bool);
SigC::Connection config_connection;
SigC::Connection connect_connection;
void configuration_changed (bool);
void connections_changed (int, bool);
};
#endif /* __ardour_gtk_connection_editor_h__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,195 @@
#ifndef __gtk_ardour_xfade_edit_h__
#define __gtk_ardour_xfade_edit_h__
#include <list>
#include <gtk--/box.h>
#include <gtk--/button.h>
#include <gtk--/radiobutton.h>
#include <gtk-canvas.h>
#include <ardour/curve.h>
#include "ardour_dialog.h"
namespace ARDOUR
{
class Session;
class Curve;
class Crossfade;
}
class CrossfadeEditor : public ArdourDialog
{
public:
CrossfadeEditor (ARDOUR::Session&, ARDOUR::Crossfade&, double miny, double maxy);
~CrossfadeEditor ();
void apply ();
static const double canvas_border;
/* these are public so that a caller/subclass can make them do the right thing.
*/
Gtk::Button cancel_button;
Gtk::Button ok_button;
struct PresetPoint {
double x;
double y;
PresetPoint (double a, double b)
: x (a), y (b) {}
};
struct Preset : public list<PresetPoint> {
const gchar** xpm;
Preset (const gchar** x)
: xpm (x) {}
};
typedef list<Preset*> Presets;
static Presets* fade_in_presets;
static Presets* fade_out_presets;
private:
ARDOUR::Crossfade& xfade;
ARDOUR::Session& session;
Gtk::VBox vpacker;
struct Point {
~Point();
GtkCanvasItem* box;
GtkCanvasItem* curve;
double x;
double y;
static const int32_t size;
void move_to (double x, double y, double xfract, double yfract);
};
struct PointSorter
{
bool operator() (const CrossfadeEditor::Point* a, const CrossfadeEditor::Point *b) {
return a->x < b->x;
}
};
GtkWidget* _canvas;
GtkCanvasItem* toplevel;
Gtk::Widget* canvas;
struct Half {
GtkCanvasItem* line;
GtkCanvasItem* shading;
list<Point*> points;
ARDOUR::Curve normative_curve; /* 0 - 1.0, linear */
ARDOUR::Curve gain_curve; /* 0 - 2.0, gain mapping */
vector<GtkCanvasItem*> waves;
Half();
};
enum WhichFade {
In = 0,
Out = 1
};
Half fade[2];
WhichFade current;
bool point_grabbed;
vector<Gtk::Button*> fade_out_buttons;
vector<Gtk::Button*> fade_in_buttons;
Gtk::HBox action_box;
Gtk::VBox vpacker2;
Gtk::Button clear_button;
Gtk::Button revert_button;
Gtk::ToggleButton audition_both_button;
Gtk::ToggleButton audition_left_dry_button;
Gtk::ToggleButton audition_left_button;
Gtk::ToggleButton audition_right_dry_button;
Gtk::ToggleButton audition_right_button;
Gtk::ToggleButton preroll_button;
Gtk::ToggleButton postroll_button;
Gtk::HBox roll_box;
gint event_handler (GdkEvent*);
static gint _canvas_event (GtkCanvasItem*, GdkEvent* event, gpointer data);
static gint _point_event (GtkCanvasItem*, GdkEvent* event, gpointer data);
static gint _curve_event (GtkCanvasItem*, GdkEvent* event, gpointer data);
gint canvas_event (GtkCanvasItem*, GdkEvent* event);
gint point_event (GtkCanvasItem*, GdkEvent* event);
gint curve_event (GtkCanvasItem*, GdkEvent* event);
void canvas_allocation (GtkAllocation*);
void add_control_point (double x, double y);
Point* make_point ();
void redraw ();
double effective_width () const { return _canvas->allocation.width - (2.0 * canvas_border); }
double effective_height () const { return _canvas->allocation.height - (2.0 * canvas_border); }
void clear ();
void reset ();
double miny;
double maxy;
Gtk::Table fade_in_table;
Gtk::Table fade_out_table;
void build_presets ();
void apply_preset (Preset*);
Gtk::RadioButton select_in_button;
Gtk::RadioButton select_out_button;
Gtk::HBox curve_button_box;
Gtk::HBox audition_box;
void curve_select_clicked (WhichFade);
double x_coordinate (double& xfract) const;
double y_coordinate (double& yfract) const;
void set (const ARDOUR::Curve& alist, WhichFade);
void make_waves (ARDOUR::AudioRegion&, WhichFade);
void peaks_ready (ARDOUR::AudioRegion* r, WhichFade);
void _apply_to (ARDOUR::Crossfade* xf);
void setup (ARDOUR::Crossfade*);
void cancel_audition ();
void audition_state_changed (bool);
void audition_toggled ();
void audition_right_toggled ();
void audition_right_dry_toggled ();
void audition_left_toggled ();
void audition_left_dry_toggled ();
void audition_both ();
void audition_left_dry ();
void audition_left ();
void audition_right_dry ();
void audition_right ();
void xfade_changed (ARDOUR::Change);
void dump ();
};
#endif /* __gtk_ardour_xfade_edit_h__ */

View File

@@ -0,0 +1,263 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <algorithm>
#include <ardour/region.h>
#include <gtkmmext/doi.h>
#include "canvas-simplerect.h"
#include "canvas-curve.h"
#include "crossfade_view.h"
#include "rgb_macros.h"
#include "audio_time_axis.h"
#include "public_editor.h"
#include "regionview.h"
#include "utils.h"
using namespace SigC;
using namespace ARDOUR;
using namespace Editing;
SigC::Signal1<void,CrossfadeView*> CrossfadeView::GoingAway;
CrossfadeView::CrossfadeView (GtkCanvasGroup *parent,
AudioTimeAxisView &tv,
Crossfade& xf,
double spu,
GdkColor& basic_color,
AudioRegionView& lview,
AudioRegionView& rview)
: TimeAxisViewItem ("xf.name()", parent, tv, spu, basic_color, xf.position(),
xf.overlap_length(), TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowFrame)),
crossfade (xf),
left_view (lview),
right_view (rview)
{
_valid = true;
_visible = true;
fade_in = gtk_canvas_item_new (GTK_CANVAS_GROUP(group),
gtk_canvas_line_get_type(),
"fill_color_rgba", color_map[cCrossfadeLine],
"width_pixels", (guint) 1,
NULL);
fade_out = gtk_canvas_item_new (GTK_CANVAS_GROUP(group),
gtk_canvas_line_get_type(),
"fill_color_rgba", color_map[cCrossfadeLine],
"width_pixels", (guint) 1,
NULL);
set_height (get_time_axis_view().height);
/* no frame around the xfade or overlap rects */
gtk_canvas_item_set (frame, "outline_what", 0, NULL);
/* never show the vestigial frame */
gtk_canvas_item_hide (vestigial_frame);
show_vestigial = false;
gtk_object_set_data (GTK_OBJECT(group), "crossfadeview", this);
gtk_signal_connect (GTK_OBJECT(group), "event",
(GtkSignalFunc) PublicEditor::canvas_crossfade_view_event,
this);
crossfade_changed (Change (~0));
crossfade.StateChanged.connect (slot (*this, &CrossfadeView::crossfade_changed));
}
CrossfadeView::~CrossfadeView ()
{
GoingAway (this) ; /* EMIT_SIGNAL */
}
std::string
CrossfadeView::get_item_name ()
{
return "xfade";
// return crossfade.name();
}
void
CrossfadeView::reset_width_dependent_items (double pixel_width)
{
TimeAxisViewItem::reset_width_dependent_items (pixel_width);
active_changed ();
if (pixel_width < 5) {
gtk_canvas_item_hide (fade_in);
gtk_canvas_item_hide (fade_out);
}
}
void
CrossfadeView::set_height (double height)
{
if (height == TimeAxisView::Smaller ||
height == TimeAxisView::Small)
TimeAxisViewItem::set_height (height - 3 );
else
TimeAxisViewItem::set_height (height - NAME_HIGHLIGHT_SIZE - 3 );
redraw_curves ();
}
void
CrossfadeView::crossfade_changed (Change what_changed)
{
bool need_redraw_curves = false;
if (what_changed & BoundsChanged) {
set_position (crossfade.position(), this);
set_duration (crossfade.overlap_length(), this);
need_redraw_curves = true;
}
if (what_changed & Crossfade::ActiveChanged) {
/* calls redraw_curves */
active_changed ();
} else if (need_redraw_curves) {
redraw_curves ();
}
}
void
CrossfadeView::redraw_curves ()
{
GtkCanvasPoints* points;
int32_t npoints;
float* vec;
double h;
/*
At "height - 3.0" the bottom of the crossfade touches the name highlight or the bottom of the track (if the
track is either Small or Smaller.
*/
switch(get_time_axis_view().height) {
case TimeAxisView::Smaller:
case TimeAxisView::Small:
h = get_time_axis_view().height - 3.0;
break;
default:
h = get_time_axis_view().height - NAME_HIGHLIGHT_SIZE - 3.0;
}
if (h < 0) {
/* no space allocated yet */
return;
}
npoints = get_time_axis_view().editor.frame_to_pixel (crossfade.length());
npoints = std::min (gdk_screen_width(), npoints);
if (!_visible || !crossfade.active() || npoints < 3) {
gtk_canvas_item_hide (fade_in);
gtk_canvas_item_hide (fade_out);
return;
} else {
gtk_canvas_item_show (fade_in);
gtk_canvas_item_show (fade_out);
}
points = get_canvas_points ("xfade edit redraw", npoints);
vec = new float[npoints];
crossfade.fade_in().get_vector (0, crossfade.length(), vec, npoints);
for (int i = 0, pci = 0; i < npoints; ++i) {
points->coords[pci++] = i;
points->coords[pci++] = 2.0 + h - (h * vec[i]);
}
gtk_canvas_item_set (fade_in, "points", points, NULL);
crossfade.fade_out().get_vector (0, crossfade.length(), vec, npoints);
for (int i = 0, pci = 0; i < npoints; ++i) {
points->coords[pci++] = i;
points->coords[pci++] = 2.0 + h - (h * vec[i]);
}
gtk_canvas_item_set (fade_out, "points", points, NULL);
delete [] vec;
gtk_canvas_points_unref (points);
/* XXX this is ugly, but it will have to wait till Crossfades are reimplented
as regions. This puts crossfade views on top of a track, above all regions.
*/
gtk_canvas_item_raise_to_top (group);
}
void
CrossfadeView::active_changed ()
{
if (crossfade.active()) {
gtk_canvas_item_set (frame, "fill_color_rgba", color_map[cActiveCrossfade], NULL);
} else {
gtk_canvas_item_set (frame, "fill_color_rgba", color_map[cInactiveCrossfade], NULL);
}
redraw_curves ();
}
void
CrossfadeView::set_valid (bool yn)
{
_valid = yn;
}
AudioRegionView&
CrossfadeView::upper_regionview () const
{
if (left_view.region.layer() > right_view.region.layer()) {
return left_view;
} else {
return right_view;
}
}
void
CrossfadeView::show ()
{
gtk_canvas_item_show (group);
_visible = true;
}
void
CrossfadeView::hide ()
{
gtk_canvas_item_hide (group);
_visible = false;
}
void
CrossfadeView::fake_hide ()
{
gtk_canvas_item_hide (group);
}

View File

@@ -0,0 +1,84 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __gtk_ardour_crossfade_view_h__
#define __gtk_ardour_crossfade_view_h__
#include <vector>
#include <gtk--.h>
#include <gtk-canvas.h>
#include <sigc++/signal_system.h>
#include <ardour/crossfade.h>
#include "time_axis_view_item.h"
class AudioTimeAxisView;
class AudioRegionView;
struct CrossfadeView : public TimeAxisViewItem
{
CrossfadeView (GtkCanvasGroup*,
AudioTimeAxisView&,
ARDOUR::Crossfade&,
double initial_samples_per_unit,
GdkColor& basic_color,
AudioRegionView& leftview,
AudioRegionView& rightview);
~CrossfadeView ();
ARDOUR::Crossfade& crossfade; // ok, let 'em have it
AudioRegionView& left_view; // and these too
AudioRegionView& right_view;
std::string get_item_name();
void set_height (double);
bool valid() const { return _valid; }
bool visible() const { return _visible; }
void set_valid (bool yn);
static SigC::Signal1<void,CrossfadeView*> GoingAway;
AudioRegionView& upper_regionview () const;
void fake_hide ();
void hide ();
void show ();
protected:
void reset_width_dependent_items (double pixel_width);
private:
bool _valid;
bool _visible;
double spu;
GtkCanvasItem *overlap_rect;
GtkCanvasItem *fade_in;
GtkCanvasItem *fade_out;
GtkCanvasItem *active_button;
void crossfade_changed (ARDOUR::Change);
void active_changed ();
void redraw_curves ();
};
#endif /* __gtk_ardour_crossfade_view_h__ */

View File

@@ -0,0 +1,316 @@
#ifndef __ardour_gtk_crossfade_xpms_h_
#define __ardour_gtk_crossfade_xpms_h_
/* XPM */
static const gchar * hiout_xpm[] = {
"25 25 3 1",
" c None",
". c #F6F92A",
"+ c #F6FA2A",
" ",
" ",
" ",
" ",
" .+++++++ ",
" .++++++++ ",
" ++++++ ",
" +++++ ",
" ++++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" ++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" .+. ",
" ",
" ",
" "};
/* XPM */
static const gchar * regout2_xpm[] = {
"25 25 3 1",
" c None",
". c #FDFD00",
"+ c #FEFE00",
" ",
" ",
" .+. ",
" +++ ",
" +++ ",
" +++ ",
" .++ ",
" ++ ",
" ++. ",
" +++ ",
" .++ ",
" +++ ",
" +++ ",
" .+++ ",
" ++++ ",
" ++++ ",
" +++++. ",
" .+++++. ",
" .++++++. ",
" .+++++ ",
" .+. ",
" ",
" ",
" ",
" "};
/* XPM */
static const gchar * regout_xpm[] = {
"25 25 3 1",
" c None",
". c #FDFD00",
"+ c #FEFE00",
" ",
" ",
" ",
" ",
" .++++. ",
" .++++++. ",
" .+++++. ",
" .+++++ ",
" ++++ ",
" ++++ ",
" ++++ ",
" +++. ",
" +++ ",
" ++. ",
" +++ ",
" .++. ",
" +++ ",
" .++ ",
" ++ ",
" ++ ",
" ++ ",
" .. ",
" ",
" ",
" "};
/* XPM */
static const gchar * regin2_xpm[] = {
"25 25 3 1",
" c None",
". c #FDFD00",
"+ c #FEFE00",
" ",
" ",
" .+. ",
" +++ ",
" +++ ",
" ++. ",
" .++ ",
" +++ ",
" ++. ",
" .++ ",
" +++ ",
" .++. ",
" +++ ",
" +++. ",
" ++++ ",
" .++++ ",
" .+++++ ",
" .++++++. ",
" .++++++. ",
" ++++. ",
" .. ",
" ",
" ",
" ",
" "};
/* XPM */
static const gchar * regin_xpm[] = {
"25 25 3 1",
" c None",
". c #FDFD00",
"+ c #FEFE00",
" ",
" ",
" ",
" ",
" .++++. ",
" .++++++. ",
" .+++++. ",
" +++++. ",
" ++++ ",
" ++++ ",
" ++++ ",
" .+++ ",
" +++ ",
" .++ ",
" +++ ",
" .++. ",
" +++ ",
" ++. ",
" ++ ",
" ++ ",
" ++ ",
" .. ",
" ",
" ",
" "};
/* XPM */
static const gchar * linout_xpm[] = {
"25 25 3 1",
" c None",
". c #FDFD00",
"+ c #FEFE00",
" ",
" ",
" ",
" .. ",
" +++ ",
" .+++ ",
" ++++ ",
" ++++ ",
" +++. ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" .+++ ",
" ++++ ",
" ++++ ",
" ++++ ",
" ++++ ",
" .. ",
" ",
" ",
" "};
/* XPM */
static const gchar * linin_xpm[] = {
"25 25 3 1",
" c None",
". c #FDFD00",
"+ c #FEFE00",
" ",
" ",
" ",
" ",
" .+. ",
" +++. ",
" ++++ ",
" ++++ ",
" ++++ ",
" ++++ ",
" +++. ",
" +++ ",
" +++ ",
" +++ ",
" .+++ ",
" ++++ ",
" ++++ ",
" ++++ ",
" ++++ ",
" .+++ ",
" .++ ",
" + ",
" ",
" ",
" "};
/* XPM */
static const gchar * loout_xpm[] = {
"25 25 3 1",
" c None",
". c #F6F92A",
"+ c #F6FA2A",
" ",
" ",
" .. ",
" ++ ",
" ++ ",
" ++ ",
" ++ ",
" ++ ",
" +++ ",
" +++ ",
" +++ ",
" ++++ ",
" +++ ",
" +++ ",
" +++ ",
" ++++ ",
" +++++ ",
" ++++++ ",
" +++++++++. ",
" ++++++++ ",
" ++++. ",
" ",
" ",
" ",
" "};
/* XPM */
static const gchar * loin_xpm[] = {
"25 25 3 1",
" c None",
". c #F6F92A",
"+ c #F6FA2A",
" ",
" ",
" .+. ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" ++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" +++ ",
" ++++ ",
" +++++ ",
" ++++++ ",
" .++++++++ ",
" .+++++++ ",
" ",
" ",
" ",
" ",
" "};
/* XPM */
static const gchar * hiin_xpm[] = {
"25 25 3 1",
" c None",
". c #F6FA2A",
"+ c #F6F92A",
" ",
" ",
" ",
" ",
" .......+ ",
" ........+ ",
" ...... ",
" ..... ",
" .... ",
" ... ",
" ... ",
" ... ",
" ... ",
" ... ",
" ... ",
" ... ",
" .. ",
" ... ",
" ... ",
" ... ",
" ... ",
" +.+ ",
" ",
" ",
" "};
#endif /* __ardour_gtk_crossfade_xpms_h_ */

51
gtk2_ardour/curvetest.cc Normal file
View File

@@ -0,0 +1,51 @@
#include <iostream>
#include <fstream>
#include <cfloat>
#include <unistd.h>
#include <ardour/curve.h>
using namespace std;
using namespace ARDOUR;
int
curvetest (string filename)
{
ifstream in (filename.c_str());
stringstream line;
Curve c (-1.0, +1.0, 0, true);
double minx = DBL_MAX;
double maxx = DBL_MIN;
while (in) {
double x, y;
in >> x;
in >> y;
if (!in) {
break;
}
if (x < minx) {
minx = x;
}
if (x > maxx) {
maxx = x;
}
c.add (x, y);
}
float foo[1024];
c.get_vector (minx, maxx, foo, 1024);
for (int i = 0; i < 1024; ++i) {
cout << minx + (((double) i / 1024.0) * (maxx - minx)) << ' ' << foo[i] << endl;
}
return 0;
}

113
gtk2_ardour/default_keys.cc Normal file
View File

@@ -0,0 +1,113 @@
/*
Copyright (C) 1999 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <gtk--.h>
#include <sigc++/bind.h>
#include <pbd/error.h>
#include "ardour_ui.h"
#include "keyboard_target.h"
using namespace ARDOUR;
using namespace Gtkmmext;
using namespace Gtk;
using namespace SigC;
void
ARDOUR_UI::install_keybindings ()
{
KeyboardTarget::add_action ("start-prefix", slot (*this, &ARDOUR_UI::start_keyboard_prefix));
KeyboardTarget::add_action ("toggle-editor-window", slot (*this, &ARDOUR_UI::goto_editor_window));
KeyboardTarget::add_action ("toggle-mixer-window", slot (*this, &ARDOUR_UI::goto_mixer_window));
KeyboardTarget::add_action ("toggle-locations-window", slot (*this, &ARDOUR_UI::toggle_location_window));
KeyboardTarget::add_action ("toggle-big-clock-window", slot (*this, &ARDOUR_UI::toggle_big_clock_window));
KeyboardTarget::add_action ("toggle-options-window", slot (*this, &ARDOUR_UI::toggle_options_window));
KeyboardTarget::add_action ("toggle-auto-loop", slot (*this, &ARDOUR_UI::toggle_session_auto_loop));
KeyboardTarget::add_action ("toggle-punch-in", slot (*this, &ARDOUR_UI::toggle_session_punch_in));
KeyboardTarget::add_action ("new-session", bind (slot (*this, &ARDOUR_UI::new_session), false, string()));
KeyboardTarget::add_action ("add-audio-track", bind (slot (*this, &ARDOUR_UI::session_add_audio_track), 1, 1));
KeyboardTarget::add_action ("add-audio-bus", bind (slot (*this, &ARDOUR_UI::session_add_audio_bus), 1, 1));
KeyboardTarget::add_action ("save-state", bind (slot (*this, &ARDOUR_UI::save_state), string ("")));
KeyboardTarget::add_action ("quit", (slot (*this, &ARDOUR_UI::finish)));
KeyboardTarget::add_action ("remove-last-capture", slot (*this, &ARDOUR_UI::remove_last_capture));
KeyboardTarget::add_action ("transport-stop", slot (*this, &ARDOUR_UI::transport_stop));
KeyboardTarget::add_action ("transport-stop-and-forget-capture", slot (*this, &ARDOUR_UI::transport_stop_and_forget_capture));
KeyboardTarget::add_action ("transport-roll", slot (*this, &ARDOUR_UI::transport_roll));
KeyboardTarget::add_action ("transport-loop", slot (*this, &ARDOUR_UI::transport_loop));
KeyboardTarget::add_action ("transport-record", slot (*this, &ARDOUR_UI::transport_record));
KeyboardTarget::add_action ("transport-rewind", bind (slot (*this, &ARDOUR_UI::transport_rewind), 0));
KeyboardTarget::add_action ("transport-rewind-slow", bind (slot (*this, &ARDOUR_UI::transport_rewind), -1));
KeyboardTarget::add_action ("transport-rewind-fast", bind (slot (*this, &ARDOUR_UI::transport_rewind), 1));
KeyboardTarget::add_action ("transport-forward", bind (slot (*this, &ARDOUR_UI::transport_forward), 0));
KeyboardTarget::add_action ("transport-forward-slow", bind (slot (*this, &ARDOUR_UI::transport_forward), -1));
KeyboardTarget::add_action ("transport-forward-fast", bind (slot (*this, &ARDOUR_UI::transport_forward), 1));
KeyboardTarget::add_action ("transport-goto-start", slot (*this, &ARDOUR_UI::transport_goto_start));
KeyboardTarget::add_action ("transport-goto-end", slot (*this, &ARDOUR_UI::transport_goto_end));
KeyboardTarget::add_action ("send-all-midi-feedback", slot (*this, &ARDOUR_UI::send_all_midi_feedback));
KeyboardTarget::add_action ("toggle-record-enable-track1", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 0U));
KeyboardTarget::add_action ("toggle-record-enable-track2", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 1U));
KeyboardTarget::add_action ("toggle-record-enable-track3", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 2U));
KeyboardTarget::add_action ("toggle-record-enable-track4", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 3U));
KeyboardTarget::add_action ("toggle-record-enable-track5", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 4U));
KeyboardTarget::add_action ("toggle-record-enable-track6", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 5U));
KeyboardTarget::add_action ("toggle-record-enable-track7", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 6U));
KeyboardTarget::add_action ("toggle-record-enable-track8", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 7U));
KeyboardTarget::add_action ("toggle-record-enable-track9", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 8U));
KeyboardTarget::add_action ("toggle-record-enable-track10", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 9U));
KeyboardTarget::add_action ("toggle-record-enable-track11", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 10U));
KeyboardTarget::add_action ("toggle-record-enable-track12", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 11U));
KeyboardTarget::add_action ("toggle-record-enable-track13", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 12U));
KeyboardTarget::add_action ("toggle-record-enable-track14", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 13U));
KeyboardTarget::add_action ("toggle-record-enable-track15", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 14U));
KeyboardTarget::add_action ("toggle-record-enable-track16", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 15U));
KeyboardTarget::add_action ("toggle-record-enable-track17", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 16U));
KeyboardTarget::add_action ("toggle-record-enable-track18", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 17U));
KeyboardTarget::add_action ("toggle-record-enable-track19", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 18U));
KeyboardTarget::add_action ("toggle-record-enable-track20", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 19U));
KeyboardTarget::add_action ("toggle-record-enable-track21", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 20U));
KeyboardTarget::add_action ("toggle-record-enable-track22", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 21U));
KeyboardTarget::add_action ("toggle-record-enable-track23", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 22U));
KeyboardTarget::add_action ("toggle-record-enable-track24", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 23U));
KeyboardTarget::add_action ("toggle-record-enable-track25", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 24U));
KeyboardTarget::add_action ("toggle-record-enable-track26", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 25U));
KeyboardTarget::add_action ("toggle-record-enable-track27", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 26U));
KeyboardTarget::add_action ("toggle-record-enable-track28", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 27U));
KeyboardTarget::add_action ("toggle-record-enable-track29", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 28U));
KeyboardTarget::add_action ("toggle-record-enable-track30", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 29U));
KeyboardTarget::add_action ("toggle-record-enable-track31", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 30U));
KeyboardTarget::add_action ("toggle-record-enable-track32", bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 31U));
#if 0
ADD ME TO ARDOUR RC SOMEDAY
add_binding ("Shift-F1",, bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 0+12U));
add_binding ("Control-F1",, bind (slot (*this, &ARDOUR_UI::toggle_record_enable), 0+24U));
add_binding ("Alt-F1",, bind (slot (*this, &ARDOUR_UI::toggle_monitor_enable), 0U));
add_binding ("Alt-Shift-F1",, bind (slot (*this, &ARDOUR_UI::toggle_monitor_enable), 0+12U));
add_binding ("Alt-Control-F1",, bind (slot (*this, &ARDOUR_UI::toggle_monitor_enable), 0+24U));
#endif
}

104
gtk2_ardour/editing.cc Normal file
View File

@@ -0,0 +1,104 @@
#include <string>
#include "editing.h"
using namespace std;
// This involves some cpp magic. --taybin
#define SNAPTYPE(a) /*empty*/
#define SNAPMODE(a) /*empty*/
#define REGIONLISTSORTTYPE(a) /*empty*/
#define MOUSEMODE(a) /*empty*/
#define ZOOMFOCUS(a) /*empty*/
#define DISPLAYCONTROL(a) /*empty*/
namespace Editing {
// SNAPTYPE
#undef SNAPTYPE
#define SNAPTYPE(s) if (!strcmp(type, #s)) {return s;}
SnapType
str2snaptype (string str) {
const char* type = str.c_str();
#include "editing_syms.h"
return SnapToBar;
}
#undef SNAPTYPE
#define SNAPTYPE(a) /*empty*/
// SNAPMODE
#undef SNAPMODE
#define SNAPMODE(s) if (!strcmp(type, #s)) {return s;}
SnapMode
str2snapmode (string str) {
const char* type = str.c_str();
#include "editing_syms.h"
return SnapNormal;
}
#undef SNAPMODE
#define SNAPMODE(a) /*empty*/
// REGIONLISTSORTTYPE
#undef REGIONLISTSORTTYPE
#define REGIONLISTSORTTYPE(s) if (!strcmp(type, #s)) {return s;}
RegionListSortType
str2regionlistsorttype (string str) {
const char* type = str.c_str();
#include "editing_syms.h"
return ByName;
}
#undef REGIONLISTSORTTYPE
#define REGIONLISTSORTTYPE(a) /*empty*/
// MOUSEMODE
#undef MOUSEMODE
#define MOUSEMODE(s) if (!strcmp(type, #s)) {return s;}
MouseMode
str2mousemode (string str) {
const char* type = str.c_str();
#include "editing_syms.h"
return MouseObject;
}
#undef MOUSEMODE
#define MOUSEMODE(a) /*empty*/
// ZOOMFOCUS
#undef ZOOMFOCUS
#define ZOOMFOCUS(s) if (!strcmp(type, #s)) {return s;}
ZoomFocus
str2zoomfocus (string str) {
const char* type = str.c_str();
#include "editing_syms.h"
return ZoomFocusPlayhead;
}
#undef ZOOMFOCUS
#define ZOOMFOCUS(a) /*empty*/
// DISPLAYCONTROL
#undef DISPLAYCONTROL
#define DISPLAYCONTROL(s) if (!strcmp(type, #s)) {return s;}
DisplayControl
str2displaycontrol (string str) {
const char* type = str.c_str();
#include "editing_syms.h"
return FollowPlayhead;
}
#undef DISPLAYCONTROL
#define DISPLAYCONTROL(a) /*empty*/
// COLORID
#undef COLORID
#define COLORID(s) if (!strcmp(type, #s)) {return s;}
ColorID
str2color_id (string str) {
const char* type = str.c_str();
#include "editing_syms.h"
return cFrameHandleEndOutline;
}
#undef COLORID
#define COLORID(a) /*empty*/
ColorMap color_map;
} // namespace Editing

170
gtk2_ardour/editing.h Normal file
View File

@@ -0,0 +1,170 @@
#ifndef __gtk_ardour_editing_h__
#define __gtk_ardour_editing_h__
#include <string>
#include <map>
// This involves some cpp magic. --taybin
#define SNAPTYPE(a) /*empty*/
#define SNAPMODE(a) /*empty*/
#define REGIONLISTSORTTYPE(a) /*empty*/
#define MOUSEMODE(a) /*empty*/
#define ZOOMFOCUS(a) /*empty*/
#define DISPLAYCONTROL(a) /*empty*/
#define COLORID(a) /*empty*/
namespace Editing {
// SNAPTYPE
#undef SNAPTYPE
#define SNAPTYPE(a) a,
enum SnapType {
#include "editing_syms.h"
};
#undef SNAPTYPE
#define SNAPTYPE(s) #s,
static const char *snaptypestrs[] = {
#include "editing_syms.h"
};
inline const char* enum2str(SnapType m) {return snaptypestrs[m];}
SnapType str2snaptype(std::string);
#undef SNAPTYPE
#define SNAPTYPE(a) /*empty*/
// SNAPMODE
#undef SNAPMODE
#define SNAPMODE(a) a,
enum SnapMode {
#include "editing_syms.h"
};
#undef SNAPMODE
#define SNAPMODE(s) #s,
static const char *snapmodestrs[] = {
#include "editing_syms.h"
};
inline const char* enum2str(SnapMode m) {return snapmodestrs[m];}
SnapMode str2snapmode(std::string);
#undef SNAPMODE
#define SNAPMODE(a) /*empty*/
// REGIONLISTSORTTYPE
#undef REGIONLISTSORTTYPE
#define REGIONLISTSORTTYPE(a) a,
enum RegionListSortType {
#include "editing_syms.h"
};
#undef REGIONLISTSORTTYPE
#define REGIONLISTSORTTYPE(s) #s,
static const char *regionlistsorttypestrs[] = {
#include "editing_syms.h"
};
inline const char* enum2str(RegionListSortType m) {return regionlistsorttypestrs[m];}
RegionListSortType str2regionlistsorttype(std::string);
#undef REGIONLISTSORTTYPE
#define REGIONLISTSORTTYPE(a) /*empty*/
// MOUSEMODE
#undef MOUSEMODE
#define MOUSEMODE(a) a,
enum MouseMode {
#include "editing_syms.h"
};
#undef MOUSEMODE
#define MOUSEMODE(s) #s,
static const char *mousemodestrs[] = {
#include "editing_syms.h"
};
inline const char* enum2str(MouseMode m) {return mousemodestrs[m];}
MouseMode str2mousemode(std::string);
#undef MOUSEMODE
#define MOUSEMODE(a) /*empty*/
// ZOOMFOCUS
#undef ZOOMFOCUS
#define ZOOMFOCUS(a) a,
enum ZoomFocus {
#include "editing_syms.h"
};
#undef ZOOMFOCUS
#define ZOOMFOCUS(s) #s,
static const char *zoomfocusstrs[] = {
#include "editing_syms.h"
};
inline const char* enum2str(ZoomFocus m) {return zoomfocusstrs[m];}
ZoomFocus str2zoomfocus(std::string);
#undef ZOOMFOCUS
#define ZOOMFOCUS(a) /*empty*/
// DISPLAYCONTROL
#undef DISPLAYCONTROL
#define DISPLAYCONTROL(a) a,
enum DisplayControl {
#include "editing_syms.h"
};
#undef DISPLAYCONTROL
#define DISPLAYCONTROL(s) #s,
static const char *displaycontrolstrs[] = {
#include "editing_syms.h"
};
inline const char* enum2str(DisplayControl m) {return displaycontrolstrs[m];}
DisplayControl str2displaycontrol (std::string);
#undef DISPLAYCONTROL
#define DISPLAYCONTROL(a) /*empty*/
#undef COLORID
#define COLORID(a) a,
enum ColorID {
#include "editing_syms.h"
};
#undef COLORID
#define COLORID(s) #s,
static const char *color_id_strs[] = {
#include "editing_syms.h"
};
inline const char* enum2str(ColorID m) {return color_id_strs[m];}
ColorID str2color_id (std::string);
#undef COLORID
#define COLORID(a) /*empty*/
/////////////////////
// These don't need their state saved. yet...
enum CutCopyOp {
Cut,
Copy,
Clear
};
enum XFadeType {
Pre,
Post,
At
};
struct Color {
char r;
char g;
char b;
char a;
};
typedef std::map<Editing::ColorID,int> ColorMap;
extern ColorMap color_map;
} // namespace Editing
#endif // __gtk_ardour_editing_h__

157
gtk2_ardour/editing_syms.h Normal file
View File

@@ -0,0 +1,157 @@
/* Changing this order will break the menu */
SNAPTYPE(SnapToFrame)
SNAPTYPE(SnapToCDFrame)
SNAPTYPE(SnapToSMPTEFrame)
SNAPTYPE(SnapToSMPTESeconds)
SNAPTYPE(SnapToSMPTEMinutes)
SNAPTYPE(SnapToSeconds)
SNAPTYPE(SnapToMinutes)
SNAPTYPE(SnapToAThirtysecondBeat)
SNAPTYPE(SnapToASixteenthBeat)
SNAPTYPE(SnapToAEighthBeat)
SNAPTYPE(SnapToAQuarterBeat)
SNAPTYPE(SnapToAThirdBeat)
SNAPTYPE(SnapToBeat)
SNAPTYPE(SnapToBar)
SNAPTYPE(SnapToMark)
SNAPTYPE(SnapToEditCursor)
SNAPTYPE(SnapToRegionStart)
SNAPTYPE(SnapToRegionEnd)
SNAPTYPE(SnapToRegionSync)
SNAPTYPE(SnapToRegionBoundary)
/* Changing this order will break the menu */
SNAPMODE(SnapNormal)
SNAPMODE(SnapMagnetic)
REGIONLISTSORTTYPE(ByEndInFile)
REGIONLISTSORTTYPE(ByLength)
REGIONLISTSORTTYPE(ByName)
REGIONLISTSORTTYPE(ByPosition)
REGIONLISTSORTTYPE(BySourceFileCreationDate)
REGIONLISTSORTTYPE(BySourceFileFS)
REGIONLISTSORTTYPE(BySourceFileLength)
REGIONLISTSORTTYPE(BySourceFileName)
REGIONLISTSORTTYPE(ByStartInFile)
REGIONLISTSORTTYPE(ByTimestamp)
MOUSEMODE(MouseGain)
MOUSEMODE(MouseObject)
MOUSEMODE(MouseRange)
MOUSEMODE(MouseTimeFX)
MOUSEMODE(MouseZoom)
MOUSEMODE(MouseAudition)
/* Changing this order will break the menu */
ZOOMFOCUS(ZoomFocusLeft)
ZOOMFOCUS(ZoomFocusRight)
ZOOMFOCUS(ZoomFocusCenter)
ZOOMFOCUS(ZoomFocusPlayhead)
ZOOMFOCUS(ZoomFocusEdit)
DISPLAYCONTROL(FollowPlayhead)
DISPLAYCONTROL(ShowMeasures)
DISPLAYCONTROL(ShowWaveforms)
DISPLAYCONTROL(ShowWaveformsRecording)
COLORID(cWaveForm)
COLORID(cMutedWaveForm)
COLORID(cSelectedFrameBase)
COLORID(cFrameBase)
COLORID(cAudioTrackBase)
COLORID(cAudioTrackOutline)
COLORID(cAudioBusBase)
COLORID(cTimeStretchFill)
COLORID(cTimeStretchOutline)
COLORID(cAutomationLine)
COLORID(cLeftPanAutomationLine)
COLORID(cRightPanAutomationLine)
COLORID(cRedirectAutomationLine)
COLORID(cControlPointFill)
COLORID(cControlPointOutline)
COLORID(cEnteredControlPointOutline)
COLORID(cEnteredControlPointSelected)
COLORID(cEnteredControlPoint)
COLORID(cControlPointSelected)
COLORID(cControlPoint)
COLORID(cAutomationTrackFill)
COLORID(cAutomationTrackOutline)
COLORID(cCrossfadeEditorBase)
COLORID(cCrossfadeEditorLine)
COLORID(cSelectedCrossfadeEditorLine)
COLORID(cCrossfadeEditorLineShading)
COLORID(cCrossfadeEditorPointFill)
COLORID(cCrossfadeEditorPointOutline)
COLORID(cCrossfadeEditorWave)
COLORID(cSelectedCrossfadeEditorWave)
COLORID(cCrossfadeLine)
COLORID(cActiveCrossfade)
COLORID(cInactiveCrossfade)
COLORID(cLocationMarker)
COLORID(cLocationRange)
COLORID(cLocationCDMarker)
COLORID(cLocationLoop)
COLORID(cLocationPunch)
COLORID(cVerboseCanvasCursor)
COLORID(cTempoBar)
COLORID(cMeterBar)
COLORID(cMarkerBar)
COLORID(cRangeMarkerBar)
COLORID(cTransportMarkerBar)
COLORID(cRangeDragBarRect)
COLORID(cRangeDragBarRectFill)
COLORID(cRangeDragRect)
COLORID(cRangeDragRectFill)
COLORID(cTransportDragRect)
COLORID(cTransportDragRectFill)
COLORID(cMarkerDragLine)
COLORID(cTransportLoopRect)
COLORID(cTransportLoopRectFill)
COLORID(cTransportPunchRect)
COLORID(cTransportPunchRectFill)
COLORID(cPunchInLine)
COLORID(cPunchOutLine)
COLORID(cZoomRect)
COLORID(cZoomRectFill)
COLORID(cRubberBandRect)
COLORID(cRubberBandRectFill)
COLORID(cFirstActionMessage)
COLORID(cEnteredGainLine)
COLORID(cEnteredAutomationLine)
COLORID(cEnteredMarker)
COLORID(cMeterMarker)
COLORID(cTempoMarker)
COLORID(cMeasureLineBeat)
COLORID(cMeasureLineBar)
COLORID(cGhostTrackBaseOutline)
COLORID(cGhostTrackBaseFill)
COLORID(cGhostTrackWave)
COLORID(cImageTrackBase)
COLORID(cImageTrackOutline)
COLORID(cMarkerTrackBase)
COLORID(cMarkerTrackOutline)
COLORID(cZeroLine)
COLORID(cGainLine)
COLORID(cGainLineInactive)
COLORID(cRecordingRectFill)
COLORID(cRecordingRectOutline)
COLORID(cSelectionRectFill)
COLORID(cSelectionRectOutline)
COLORID(cSelectionEndFill)
COLORID(cSelectionEndOutline)
COLORID(cSelectionStartFill)
COLORID(cSelectionStartOutline)
COLORID(cVestigialFrameFill)
COLORID(cVestigialFrameOutline)
COLORID(cTimeAxisFrameFill)
COLORID(cTimeAxisFrameOutline)
COLORID(cNameHighlightFill)
COLORID(cNameHighlightOutline)
COLORID(cFrameHandleStartFill)
COLORID(cFrameHandleStartOutline)
COLORID(cFrameHandleEndFill)
COLORID(cFrameHandleEndOutline)
COLORID(cTrimHandleLockedStart)
COLORID(cTrimHandleLockedEnd)
COLORID(cTrimHandleStart)
COLORID(cTrimHandleEnd)

4655
gtk2_ardour/editor.cc Normal file

File diff suppressed because it is too large Load Diff

1823
gtk2_ardour/editor.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
#include <ardour/location.h>
#include <ardour/diskstream.h>
#include "editor.h"
#include "editing.h"
#include "audio_time_axis.h"
#include "regionview.h"
#include "selection.h"
using namespace ARDOUR;
void
Editor::set_route_loop_selection ()
{
if (session == 0 || selection->time.empty()) {
return;
}
jack_nframes_t start = selection->time[clicked_selection].start;
jack_nframes_t end = selection->time[clicked_selection].end;
Location* loc = transport_loop_location();
if (loc) {
loc->set (start, end);
// enable looping, reposition and start rolling
session->request_auto_loop (true);
session->request_locate (loc->start(), true);
}
}
void
Editor::set_show_waveforms (bool yn)
{
AudioTimeAxisView* atv;
if (_show_waveforms != yn) {
_show_waveforms = yn;
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
if ((atv = dynamic_cast<AudioTimeAxisView*>(*i)) != 0) {
atv->set_show_waveforms (yn);
}
}
DisplayControlChanged (Editing::ShowWaveforms);
}
}
void
Editor::set_show_waveforms_recording (bool yn)
{
AudioTimeAxisView* atv;
if (_show_waveforms_recording != yn) {
_show_waveforms_recording = yn;
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
if ((atv = dynamic_cast<AudioTimeAxisView*>(*i)) != 0) {
atv->set_show_waveforms_recording (yn);
}
}
DisplayControlChanged (Editing::ShowWaveformsRecording);
}
}

View File

@@ -0,0 +1,999 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include <gtk-canvas.h>
#include <ardour/diskstream.h>
#include <ardour/audioplaylist.h>
#include "editor.h"
#include "public_editor.h"
#include "regionview.h"
#include "streamview.h"
#include "crossfade_view.h"
#include "audio_time_axis.h"
#include "region_gain_line.h"
#include "automation_gain_line.h"
#include "automation_pan_line.h"
#include "automation_time_axis.h"
#include "redirect_automation_line.h"
#include "i18n.h"
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;
gint
Editor::_canvas_copy_region_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
Editor* editor = (Editor*)data;
return editor->canvas_copy_region_event (item, event);
}
gint
Editor::_canvas_crossfade_view_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
CrossfadeView* xfv = static_cast<CrossfadeView*> (data);
Editor* editor = dynamic_cast<Editor*>(&xfv->get_time_axis_view().editor);
return editor->canvas_crossfade_view_event (item, event, xfv);
}
gint
Editor::_canvas_fade_in_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AudioRegionView* rv = static_cast<AudioRegionView*> (data);
Editor* editor = dynamic_cast<Editor*>(&rv->get_time_axis_view().editor);
return editor->canvas_fade_in_event (item, event, rv);
}
gint
Editor::_canvas_fade_in_handle_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AudioRegionView* rv = static_cast<AudioRegionView*> (data);
Editor* editor = dynamic_cast<Editor*>(&rv->get_time_axis_view().editor);
return editor->canvas_fade_in_handle_event (item, event, rv);
}
gint
Editor::_canvas_fade_out_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AudioRegionView* rv = static_cast<AudioRegionView*> (data);
Editor* editor = dynamic_cast<Editor*>(&rv->get_time_axis_view().editor);
return editor->canvas_fade_out_event (item, event, rv);
}
gint
Editor::_canvas_fade_out_handle_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AudioRegionView* rv = static_cast<AudioRegionView*> (data);
Editor* editor = dynamic_cast<Editor*>(&rv->get_time_axis_view().editor);
return editor->canvas_fade_out_handle_event (item, event, rv);
}
gint
Editor::_canvas_region_view_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AudioRegionView *rv = reinterpret_cast<AudioRegionView *>(data);
Editor* editor = dynamic_cast<Editor*>(&rv->get_time_axis_view().editor);
return editor->canvas_region_view_event (item, event, rv);
}
gint
Editor::_canvas_region_view_name_highlight_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AudioRegionView *rv = reinterpret_cast<AudioRegionView *> (data);
Editor* editor = dynamic_cast<Editor*>(&rv->get_time_axis_view().editor);
return editor->canvas_region_view_name_highlight_event (item, event);
}
gint
Editor::_canvas_region_view_name_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AudioRegionView *rv = reinterpret_cast<AudioRegionView *> (data);
Editor* editor = dynamic_cast<Editor*>(&rv->get_time_axis_view().editor);
return editor->canvas_region_view_name_event (item, event);
}
gint
Editor::_canvas_stream_view_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* note that stream views are by definition audio track views */
AudioTimeAxisView *tv = (AudioTimeAxisView *) data;
Editor* editor = dynamic_cast<Editor*>(&tv->editor);
return editor->canvas_stream_view_event (item, event, tv);
}
gint
Editor::_canvas_automation_track_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AutomationTimeAxisView* atv = (AutomationTimeAxisView*) data;
Editor* editor = dynamic_cast<Editor*>(&atv->editor);
return editor->canvas_automation_track_event (item, event, atv);
}
gint
Editor::_canvas_control_point_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
ControlPoint *cp = reinterpret_cast<ControlPoint *>(data);
Editor* editor = dynamic_cast<Editor*>(&cp->line.trackview.editor);
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_control_point = cp;
clicked_trackview = &cp->line.trackview;
clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
clicked_regionview = 0;
break;
default:
break;
}
return editor->canvas_control_point_event (item, event);
}
gint
Editor::_canvas_line_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
AutomationLine *line = reinterpret_cast<AutomationLine*> (data);
Editor* editor = dynamic_cast<Editor*>(&line->trackview.editor);
return editor->canvas_line_event (item, event);
}
gint
Editor::_canvas_tempo_marker_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
Editor* editor = dynamic_cast<Editor*>((PublicEditor*) data);
return editor->canvas_tempo_marker_event (item, event);
}
gint
Editor::_canvas_meter_marker_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
Editor* editor = dynamic_cast<Editor*>((PublicEditor *) data);
return editor->canvas_meter_marker_event (item, event);
}
gint
Editor::_canvas_tempo_bar_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* XXX NO CAST */
Editor* editor = (Editor*) data;
return editor->canvas_tempo_bar_event (item, event);
}
gint
Editor::_canvas_meter_bar_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* XXX NO CAST */
Editor* editor = (Editor*) data;
return editor->canvas_meter_bar_event (item, event);
}
gint
Editor::_canvas_marker_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
Editor* editor = dynamic_cast<Editor*>((PublicEditor*) data);
return editor->canvas_marker_event (item, event);
}
gint
Editor::_canvas_marker_bar_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* NO CAST */
Editor* editor = (Editor*) data;
return editor->canvas_marker_bar_event (item, event);
}
gint
Editor::_canvas_range_marker_bar_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* NO CAST */
Editor* editor = (Editor*) data;
return editor->canvas_range_marker_bar_event (item, event);
}
gint
Editor::_canvas_transport_marker_bar_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* NO CAST */
Editor* editor = (Editor*) data;
return editor->canvas_transport_marker_bar_event (item, event);
}
gint
Editor::_canvas_playhead_cursor_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* NO CAST */
Editor* editor = (Editor*) data;
return editor->canvas_playhead_cursor_event (item, event);
}
gint
Editor::_canvas_edit_cursor_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* NO CAST */
Editor* editor = (Editor*) data;
return editor->canvas_edit_cursor_event (item, event);
}
gint
Editor::_canvas_zoom_rect_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
Editor* editor = dynamic_cast<Editor*>((PublicEditor*) data);
return editor->canvas_zoom_rect_event (item, event);
}
gint
Editor::_canvas_selection_rect_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
Editor* editor = dynamic_cast<Editor*>((PublicEditor*) data);
return editor->canvas_selection_rect_event (item, event);
}
gint
Editor::_canvas_selection_start_trim_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
Editor* editor = dynamic_cast<Editor*>((PublicEditor*) data);
return editor->canvas_selection_start_trim_event (item, event);
}
gint
Editor::_canvas_selection_end_trim_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
Editor* editor = dynamic_cast<Editor*>((PublicEditor*) data);
return editor->canvas_selection_end_trim_event (item, event);
}
gint
Editor::_track_canvas_event (GtkCanvasItem *item, GdkEvent *event, gpointer data)
{
/* NO CAST */
Editor* editor = (Editor*) data;
return editor->track_canvas_event (item, event);
}
/********** END OF.TATIC EVENT HANDLERS */
gint
Editor::track_canvas_event (GtkCanvasItem *item, GdkEvent *event)
{
gint x, y;
switch (event->type) {
case GDK_MOTION_NOTIFY:
/* keep those motion events coming */
track_canvas->get_pointer (x, y);
return track_canvas_motion (item, event);
case GDK_BUTTON_RELEASE:
switch (event->button.button) {
case 4:
case 5:
button_release_handler (item, event, NoItem);
break;
}
break;
default:
break;
}
return FALSE;
}
gint
Editor::track_canvas_motion (GtkCanvasItem *item, GdkEvent *ev)
{
if (verbose_cursor_visible) {
gtk_canvas_item_set (verbose_canvas_cursor,
"x", ev->motion.x + 20,
"y", ev->motion.y + 20,
NULL);
}
return FALSE;
}
gint
Editor::typed_event (GtkCanvasItem *item, GdkEvent *event, ItemType type)
{
gint ret = FALSE;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
ret = button_press_handler (item, event, type);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, type);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, type);
break;
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, type);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, type);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_region_view_event (GtkCanvasItem *item, GdkEvent *event, AudioRegionView *rv)
{
gint ret = FALSE;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_regionview = rv;
clicked_control_point = 0;
clicked_trackview = &rv->get_time_axis_view();
clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
ret = button_press_handler (item, event, RegionItem);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, RegionItem);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, RegionItem);
break;
case GDK_ENTER_NOTIFY:
set_entered_regionview (rv);
break;
case GDK_LEAVE_NOTIFY:
set_entered_regionview (0);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_stream_view_event (GtkCanvasItem *item, GdkEvent *event, AudioTimeAxisView *tv)
{
gint ret = FALSE;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_regionview = 0;
clicked_control_point = 0;
clicked_trackview = tv;
clicked_audio_trackview = tv;
ret = button_press_handler (item, event, StreamItem);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, StreamItem);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, StreamItem);
break;
case GDK_ENTER_NOTIFY:
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_automation_track_event (GtkCanvasItem *item, GdkEvent *event, AutomationTimeAxisView *atv)
{
gint ret = FALSE;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_regionview = 0;
clicked_control_point = 0;
clicked_trackview = atv;
clicked_audio_trackview = 0;
ret = button_press_handler (item, event, AutomationTrackItem);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, AutomationTrackItem);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, AutomationTrackItem);
break;
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, AutomationTrackItem);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, AutomationTrackItem);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_fade_in_event (GtkCanvasItem *item, GdkEvent *event, AudioRegionView *rv)
{
/* we handle only button 3 press/release events */
switch (event->type) {
case GDK_BUTTON_PRESS:
clicked_regionview = rv;
clicked_control_point = 0;
clicked_trackview = &rv->get_time_axis_view();
clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
if (event->button.button == 3) {
return button_press_handler (item, event, FadeInItem);
}
break;
case GDK_BUTTON_RELEASE:
if (event->button.button == 3) {
return button_release_handler (item, event, FadeInItem);
}
break;
default:
break;
}
/* proxy for the regionview */
return canvas_region_view_event (rv->get_canvas_group(), event, rv);
}
gint
Editor::canvas_fade_in_handle_event (GtkCanvasItem *item, GdkEvent *event, AudioRegionView *rv)
{
gint ret = FALSE;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_regionview = rv;
clicked_control_point = 0;
clicked_trackview = &rv->get_time_axis_view();
clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
ret = button_press_handler (item, event, FadeInHandleItem);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, FadeInHandleItem);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, FadeInHandleItem);
break;
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, FadeInHandleItem);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, FadeInHandleItem);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_fade_out_event (GtkCanvasItem *item, GdkEvent *event, AudioRegionView *rv)
{
/* we handle only button 3 press/release events */
switch (event->type) {
case GDK_BUTTON_PRESS:
clicked_regionview = rv;
clicked_control_point = 0;
clicked_trackview = &rv->get_time_axis_view();
clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
if (event->button.button == 3) {
return button_press_handler (item, event, FadeOutItem);
}
break;
case GDK_BUTTON_RELEASE:
if (event->button.button == 3) {
return button_release_handler (item, event, FadeOutItem);
}
break;
default:
break;
}
/* proxy for the regionview */
return canvas_region_view_event (rv->get_canvas_group(), event, rv);
}
gint
Editor::canvas_fade_out_handle_event (GtkCanvasItem *item, GdkEvent *event, AudioRegionView *rv)
{
gint ret = FALSE;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_regionview = rv;
clicked_control_point = 0;
clicked_trackview = &rv->get_time_axis_view();
clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
ret = button_press_handler (item, event, FadeOutHandleItem);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, FadeOutHandleItem);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, FadeOutHandleItem);
break;
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, FadeOutHandleItem);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, FadeOutHandleItem);
break;
default:
break;
}
return ret;
}
struct DescendingRegionLayerSorter {
bool operator()(Region* a, Region* b) {
return a->layer() > b->layer();
}
};
gint
Editor::canvas_crossfade_view_event (GtkCanvasItem* item, GdkEvent* event, CrossfadeView* xfv)
{
/* we handle only button 3 press/release events */
switch (event->type) {
case GDK_BUTTON_PRESS:
clicked_crossfadeview = xfv;
clicked_trackview = &clicked_crossfadeview->get_time_axis_view();
if (event->button.button == 3) {
return button_press_handler (item, event, CrossfadeViewItem);
}
break;
case GDK_BUTTON_RELEASE:
if (event->button.button == 3) {
gint ret = button_release_handler (item, event, CrossfadeViewItem);
return ret;
}
break;
default:
break;
}
/* proxy for the upper most regionview */
/* XXX really need to check if we are in the name highlight,
and proxy to that when required.
*/
TimeAxisView& tv (xfv->get_time_axis_view());
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*>(&tv)) != 0) {
if (atv->is_audio_track()) {
AudioPlaylist* pl = atv->get_diskstream()->playlist();
Playlist::RegionList* rl = pl->regions_at (event_frame (event));
if (!rl->empty()) {
DescendingRegionLayerSorter cmp;
rl->sort (cmp);
AudioRegionView* arv = atv->view->find_view (*(dynamic_cast<AudioRegion*> (rl->front())));
/* proxy */
delete rl;
return canvas_region_view_event (arv->get_canvas_group(), event, arv);
}
}
}
return TRUE;
}
gint
Editor::canvas_control_point_event (GtkCanvasItem *item, GdkEvent *event)
{
ItemType type;
ControlPoint *cp;
if ((cp = static_cast<ControlPoint *> (gtk_object_get_data (GTK_OBJECT(item), "control_point"))) == 0) {
fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
/*NOTREACHED*/
}
if (dynamic_cast<AudioRegionGainLine*> (&cp->line) != 0) {
type = GainControlPointItem;
} else if (dynamic_cast<AutomationGainLine*> (&cp->line) != 0) {
type = GainAutomationControlPointItem;
} else if (dynamic_cast<AutomationPanLine*> (&cp->line) != 0) {
type = PanAutomationControlPointItem;
} else if (dynamic_cast<RedirectAutomationLine*> (&cp->line) != 0) {
type = RedirectAutomationControlPointItem;
} else {
return FALSE;
}
return typed_event (item, event, type);
}
gint
Editor::canvas_line_event (GtkCanvasItem *item, GdkEvent *event)
{
ItemType type;
AutomationLine *al;
if ((al = static_cast<AutomationLine *> (gtk_object_get_data (GTK_OBJECT(item), "line"))) == 0) {
fatal << _("programming error: line canvas item has no line object pointer!") << endmsg;
/*NOTREACHED*/
}
if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
type = GainLineItem;
} else if (dynamic_cast<AutomationGainLine*> (al) != 0) {
type = GainAutomationLineItem;
} else if (dynamic_cast<AutomationPanLine*> (al) != 0) {
type = PanAutomationLineItem;
} else if (dynamic_cast<RedirectAutomationLine*> (al) != 0) {
type = RedirectAutomationLineItem;
} else {
return FALSE;
}
return typed_event (item, event, type);
}
gint
Editor::canvas_selection_rect_event (GtkCanvasItem *item, GdkEvent *event)
{
gint ret = FALSE;
SelectionRect *rect = 0;
if ((rect = reinterpret_cast<SelectionRect*> (gtk_object_get_data (GTK_OBJECT(item), "rect"))) == 0) {
fatal << _("programming error: no \"rect\" pointer associated with selection item") << endmsg;
/*NOTREACHED*/
}
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_selection = rect->id;
ret = button_press_handler (item, event, SelectionItem);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, SelectionItem);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, SelectionItem);
break;
/* Don't need these at the moment. */
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, SelectionItem);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, SelectionItem);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_selection_start_trim_event (GtkCanvasItem *item, GdkEvent *event)
{
gint ret = FALSE;
SelectionRect *rect = 0;
if ((rect = reinterpret_cast<SelectionRect*> (gtk_object_get_data (GTK_OBJECT(item), "rect"))) == 0) {
fatal << _("programming error: no \"rect\" pointer associated with selection item") << endmsg;
/*NOTREACHED*/
}
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_selection = rect->id;
ret = button_press_handler (item, event, StartSelectionTrimItem);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, StartSelectionTrimItem);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, StartSelectionTrimItem);
break;
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, StartSelectionTrimItem);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, StartSelectionTrimItem);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_selection_end_trim_event (GtkCanvasItem *item, GdkEvent *event)
{
gint ret = FALSE;
SelectionRect *rect = 0;
if ((rect = reinterpret_cast<SelectionRect*> (gtk_object_get_data (GTK_OBJECT(item), "rect"))) == 0) {
fatal << _("programming error: no \"rect\" pointer associated with selection item") << endmsg;
/*NOTREACHED*/
}
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_selection = rect->id;
ret = button_press_handler (item, event, EndSelectionTrimItem);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, EndSelectionTrimItem);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, EndSelectionTrimItem);
break;
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, EndSelectionTrimItem);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, EndSelectionTrimItem);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_region_view_name_highlight_event (GtkCanvasItem *item, GdkEvent *event)
{
gint ret = FALSE;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_regionview = reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"));
clicked_control_point = 0;
clicked_trackview = &clicked_regionview->get_time_axis_view();
clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
ret = button_press_handler (item, event, AudioRegionViewNameHighlight);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, AudioRegionViewNameHighlight);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, AudioRegionViewNameHighlight);
break;
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, AudioRegionViewNameHighlight);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, AudioRegionViewNameHighlight);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_region_view_name_event (GtkCanvasItem *item, GdkEvent *event)
{
gint ret = FALSE;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
clicked_regionview = reinterpret_cast<AudioRegionView *> (gtk_object_get_data(GTK_OBJECT(item), "regionview"));
clicked_control_point = 0;
clicked_trackview = &clicked_regionview->get_time_axis_view();
clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
ret = button_press_handler (item, event, AudioRegionViewName);
break;
case GDK_BUTTON_RELEASE:
ret = button_release_handler (item, event, AudioRegionViewName);
break;
case GDK_MOTION_NOTIFY:
ret = motion_handler (item, event, AudioRegionViewName);
break;
case GDK_ENTER_NOTIFY:
ret = enter_handler (item, event, AudioRegionViewName);
break;
case GDK_LEAVE_NOTIFY:
ret = leave_handler (item, event, AudioRegionViewName);
break;
default:
break;
}
return ret;
}
gint
Editor::canvas_marker_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, MarkerItem);
}
gint
Editor::canvas_marker_bar_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, MarkerBarItem);
}
gint
Editor::canvas_range_marker_bar_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, RangeMarkerBarItem);
}
gint
Editor::canvas_transport_marker_bar_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, TransportMarkerBarItem);
}
gint
Editor::canvas_tempo_marker_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, TempoMarkerItem);
}
gint
Editor::canvas_meter_marker_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, MeterMarkerItem);
}
gint
Editor::canvas_tempo_bar_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, TempoBarItem);
}
gint
Editor::canvas_meter_bar_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, MeterBarItem);
}
gint
Editor::canvas_playhead_cursor_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, PlayheadCursorItem);
}
gint
Editor::canvas_edit_cursor_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, EditCursorItem);
}
gint
Editor::canvas_zoom_rect_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, NoItem);
}
gint
Editor::canvas_copy_region_event (GtkCanvasItem *item, GdkEvent *event)
{
return typed_event (item, event, RegionItem);
}

View File

@@ -0,0 +1,121 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include <gtk-canvas.h>
#include "utils.h"
#include "editor.h"
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;
Editor::Cursor::Cursor (Editor& ed, const string& color, GtkSignalFunc callbck)
: editor (ed), callback (callbck), length(1.0)
{
GtkCanvasGroup *group;
points = gtk_canvas_points_new (2);
/* "randomly" initialize coords */
points->coords[0] = -9383839.0;
points->coords[1] = 0.0;
points->coords[2] = 1.0;
points->coords[3] = 0.0;
group = GTK_CANVAS_GROUP (editor.cursor_group);
// cerr << "set cursor points, nc = " << points->num_points << endl;
canvas_item = gtk_canvas_item_new (group,
gtk_canvas_line_get_type(),
"points", points,
"fill_color", color.c_str(),
"width_pixels", 1,
"first_arrowhead", (gboolean) TRUE,
"last_arrowhead", (gboolean) TRUE,
"arrow_shape_a", 11.0,
"arrow_shape_b", 0.0,
"arrow_shape_c", 9.0,
NULL);
// cerr << "cursor line @ " << canvas_item << endl;
gtk_object_set_data (GTK_OBJECT(canvas_item), "cursor", this);
gtk_signal_connect (GTK_OBJECT(canvas_item), "event", callback, &editor);
current_frame = 1; /* force redraw at 0 */
}
Editor::Cursor::~Cursor ()
{
gtk_object_destroy (GTK_OBJECT(canvas_item));
gtk_canvas_points_unref (points);
}
void
Editor::Cursor::set_position (jack_nframes_t frame)
{
double new_pos = editor.frame_to_unit (frame);
if (editor.session == 0) {
gtk_canvas_item_hide (canvas_item);
} else {
gtk_canvas_item_show (canvas_item);
}
current_frame = frame;
if (new_pos == points->coords[0]) {
/* change in position is not visible, so just raise it */
gtk_canvas_item_raise_to_top (canvas_item);
return;
}
points->coords[0] = new_pos;
points->coords[2] = new_pos;
// cerr << "set cursor2 al points, nc = " << points->num_points << endl;
gtk_canvas_item_set (canvas_item, "points", points, NULL);
gtk_canvas_item_raise_to_top (canvas_item);
}
void
Editor::Cursor::set_length (double units)
{
length = units;
points->coords[3] = points->coords[1] + length;
// cerr << "set cursor3 al points, nc = " << points->num_points << endl;
gtk_canvas_item_set (canvas_item, "points", points, NULL);
}
void
Editor::Cursor::set_y_axis (double position)
{
points->coords[1] = position;
points->coords[3] = position + length;
// cerr << "set cursor4 al points, nc = " << points->num_points << endl;
gtk_canvas_item_set (canvas_item, "points", points, NULL);
}

View File

@@ -0,0 +1,210 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include <gtkmmext/stop_signal.h>
#include <ardour/route_group.h>
#include "editor.h"
#include "keyboard.h"
#include "marker.h"
#include "time_axis_view.h"
#include "prompter.h"
#include <ardour/route.h>
#include "i18n.h"
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;
void
Editor::edit_group_list_column_click (gint col)
{
if (edit_group_list_menu == 0) {
build_edit_group_list_menu ();
}
edit_group_list_menu->popup (0, 0);
}
void
Editor::build_edit_group_list_menu ()
{
using namespace Gtk::Menu_Helpers;
edit_group_list_menu = new Menu;
edit_group_list_menu->set_name ("ArdourContextMenu");
MenuList& items = edit_group_list_menu->items();
items.push_back (MenuElem (_("Show All"), slot (*this, &Editor::select_all_edit_groups)));
items.push_back (MenuElem (_("Hide All"), slot (*this, &Editor::unselect_all_edit_groups)));
}
void
Editor::unselect_all_edit_groups ()
{
}
void
Editor::select_all_edit_groups ()
{
CList_Helpers::RowList::iterator i;
/* XXX potential race with remove_track(), but the select operation
cannot be done with the track_lock held.
*/
for (i = route_list.rows().begin(); i != route_list.rows().end(); ++i) {
i->select ();
}
}
void
Editor::new_edit_group ()
{
if (session == 0) {
return;
}
ArdourPrompter prompter;
string result;
prompter.set_prompt (_("Name for new edit group"));
prompter.done.connect (Gtk::Main::quit.slot());
prompter.show_all ();
Gtk::Main::run ();
if (prompter.status != Gtkmmext::Prompter::entered) {
return;
}
prompter.get_result (result);
if (result.length()) {
session->add_edit_group (result);
}
}
void
Editor::edit_group_list_button_clicked ()
{
new_edit_group ();
}
gint
Editor::edit_group_list_button_press_event (GdkEventButton* ev)
{
gint row, col;
if (edit_group_list.get_selection_info ((int)ev->x, (int)ev->y, &row, &col) == 0) {
return FALSE;
}
if (col == 1) {
if (Keyboard::is_edit_event (ev)) {
// RouteGroup* group = (RouteGroup *) edit_group_list.row(row).get_data ();
// edit_route_group (group);
return stop_signal (edit_group_list, "button_press_event");
} else {
/* allow regular select to occur */
return FALSE;
}
} else if (col == 0) {
RouteGroup* group = reinterpret_cast<RouteGroup *>(edit_group_list.row(row).get_data ());
if (group) {
group->set_active (!group->is_active(), this);
}
}
return stop_signal (edit_group_list, "button_press_event");
}
void
Editor::edit_group_selected (gint row, gint col, GdkEvent* ev)
{
RouteGroup* group = (RouteGroup *) edit_group_list.row(row).get_data ();
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
if ((*i)->edit_group() == group) {
select_strip_in_display (*(*i));
}
}
}
void
Editor::edit_group_unselected (gint row, gint col, GdkEvent* ev)
{
RouteGroup* group = (RouteGroup *) edit_group_list.row(row).get_data ();
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
if ((*i)->edit_group() == group) {
unselect_strip_in_display (*(*i));
}
}
}
void
Editor::add_edit_group (RouteGroup* group)
{
list<string> names;
names.push_back ("*");
names.push_back (group->name());
edit_group_list.rows().push_back (names);
edit_group_list.rows().back().set_data (group);
edit_group_list.rows().back().select();
group->FlagsChanged.connect (bind (slot (*this, &Editor::group_flags_changed), group));
}
void
Editor::group_flags_changed (void* src, RouteGroup* group)
{
if (src != this) {
// select row
}
CList_Helpers::RowIterator ri = edit_group_list.rows().find_data (group);
if (group->is_active()) {
edit_group_list.cell (ri->get_row_num(),0).set_pixmap (check_pixmap, check_mask);
} else {
edit_group_list.cell (ri->get_row_num(),0).set_pixmap (empty_pixmap, empty_mask);
}
}

View File

@@ -0,0 +1,10 @@
#ifndef __ardour_gtk_editor_enums_h__
#define __ardour_gtk_editor_enums_h__
enum EditorDisplayControl {
ShowMeasures,
ShowWaveforms,
FollowPlayhead
};
#endif /* __ardour_gtk_editor_enums_h__ */

View File

@@ -0,0 +1,437 @@
/*
Copyright (C) 2001 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <unistd.h>
#include <climits>
#include "export_dialog.h"
#include "editor.h"
#include "public_editor.h"
#include "selection.h"
#include "time_axis_view.h"
#include "audio_time_axis.h"
#include "regionview.h"
#include "ardour_message.h"
#include <pbd/pthread_utils.h>
#include <ardour/types.h>
#include <ardour/export.h>
#include <ardour/audio_track.h>
#include <ardour/filesource.h>
#include <ardour/diskstream.h>
#include <ardour/audioregion.h>
#include <ardour/audioplaylist.h>
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace Gtk;
void
Editor::export_session()
{
if (session) {
export_range (0, session->current_end_frame());
}
}
void
Editor::export_selection ()
{
if (session) {
if (selection->time.empty()) {
ArdourMessage message (this, X_("norange"), _("There is no range to export.\n\nSelect a range using the range mouse mode"));
return;
}
export_range (selection->time.front().start,
selection->time.front().end);
}
}
void
Editor::export_range (jack_nframes_t start, jack_nframes_t end)
{
if (session) {
if (export_dialog == 0) {
export_dialog = new ExportDialog (*this);
}
export_dialog->connect_to_session (session);
export_dialog->set_range (start, end);
export_dialog->start_export();
}
}
void
Editor::export_region ()
{
if (clicked_regionview == 0) {
return;
}
ExportDialog* dialog = new ExportDialog (*this, &clicked_regionview->region);
dialog->connect_to_session (session);
dialog->set_range (0, clicked_regionview->region.length());
dialog->start_export();
}
void
Editor::write_a_region ()
{
if (clicked_regionview == 0) {
return;
}
FileSelection file_selector;
file_selector.get_selection_entry()->activate.connect (bind (slot (*this, &Editor::finish_sub_event_loop), 1));
file_selector.get_cancel_button()->clicked.connect (bind (slot (*this, &Editor::finish_sub_event_loop), -1));
file_selector.get_ok_button()->clicked.connect (bind (slot (*this, &Editor::finish_sub_event_loop), 1));
file_selector.delete_event.connect (bind (slot (*this, &Editor::finish_sub_event_loop_on_delete), -1));
file_selector.show_all();
run_sub_event_loop ();
if (sub_event_loop_status == 1) {
string path = file_selector.get_filename();
printf ("got region: %s\n", path.c_str());
if (path.length()) {
write_region (path, clicked_regionview->region);
}
}
}
int
Editor::write_region_selection (AudioRegionSelection& regions)
{
for (AudioRegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
if (write_region ("", (*i)->region) == false) {
return -1;
}
}
return 0;
}
void
Editor::bounce_region_selection ()
{
for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
AudioRegion& region ((*i)->region);
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&(*i)->get_time_axis_view());
AudioTrack* track = dynamic_cast<AudioTrack*>(&(atv->route()));
InterThreadInfo itt;
itt.done = false;
itt.cancel = false;
itt.progress = 0.0f;
track->bounce_range (region.position(), region.position() + region.length(), itt);
}
}
bool
Editor::write_region (string path, AudioRegion& region)
{
FileSource* fs;
const jack_nframes_t chunk_size = 4096;
jack_nframes_t to_read;
Sample buf[chunk_size];
gain_t gain_buffer[chunk_size];
jack_nframes_t pos;
char s[PATH_MAX+1];
uint32_t cnt;
vector<FileSource *> sources;
uint32_t nchans;
nchans = region.n_channels();
/* don't do duplicate of the entire source if that's what is going on here */
if (region.start() == 0 && region.length() == region.source().length()) {
/* XXX should link(2) to create a new inode with "path" */
return true;
}
if (path.length() == 0) {
for (uint32_t n=0; n < nchans; ++n) {
for (cnt = 0; cnt < 999999; ++cnt) {
if (nchans == 1) {
snprintf (s, sizeof(s), "%s/%s_%" PRIu32 ".wav", session->sound_dir().c_str(),
legalize_for_path(region.name()).c_str(), cnt);
}
else {
snprintf (s, sizeof(s), "%s/%s_%" PRIu32 "-%" PRId32 ".wav", session->sound_dir().c_str(),
legalize_for_path(region.name()).c_str(), cnt, n);
}
path = s;
if (::access (path.c_str(), F_OK) != 0) {
break;
}
}
if (cnt == 999999) {
error << "" << endmsg;
goto error_out;
}
try {
fs = new FileSource (path, session->frame_rate());
}
catch (failed_constructor& err) {
goto error_out;
}
sources.push_back (fs);
}
}
else {
/* TODO: make filesources based on passed path */
}
to_read = region.length();
pos = region.position();
while (to_read) {
jack_nframes_t this_time;
this_time = min (to_read, chunk_size);
for (vector<FileSource *>::iterator src=sources.begin(); src != sources.end(); ++src) {
fs = (*src);
if (region.read_at (buf, buf, gain_buffer, pos, this_time) != this_time) {
break;
}
if (fs->write (buf, this_time) != this_time) {
error << "" << endmsg;
goto error_out;
}
}
to_read -= this_time;
pos += this_time;
}
time_t tnow;
struct tm* now;
time (&tnow);
now = localtime (&tnow);
for (vector<FileSource *>::iterator src = sources.begin(); src != sources.end(); ++src) {
(*src)->update_header (0, *now, tnow);
}
return true;
error_out:
for (vector<FileSource*>::iterator i = sources.begin(); i != sources.end(); ++i) {
(*i)->mark_for_remove ();
delete (*i);
}
return 0;
}
int
Editor::write_audio_selection (TimeSelection& ts)
{
int ret = 0;
if (selection->tracks.empty()) {
return 0;
}
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*>(*i)) == 0) {
continue;
}
if (atv->is_audio_track()) {
Playlist* playlist = atv->get_diskstream()->playlist();
if (playlist && write_audio_range (*playlist, atv->get_diskstream()->n_channels(), ts) == 0) {
ret = -1;
break;
}
}
}
return ret;
}
bool
Editor::write_audio_range (Playlist& playlist, uint32_t channels, list<AudioRange>& range)
{
FileSource* fs;
const jack_nframes_t chunk_size = 4096;
jack_nframes_t nframes;
Sample buf[chunk_size];
gain_t gain_buffer[chunk_size];
jack_nframes_t pos;
char s[PATH_MAX+1];
uint32_t cnt;
string path;
vector<FileSource *> sources;
for (uint32_t n=0; n < channels; ++n) {
for (cnt = 0; cnt < 999999; ++cnt) {
if (channels == 1) {
snprintf (s, sizeof(s), "%s/%s_%" PRIu32 ".wav", session->sound_dir().c_str(),
legalize_for_path(playlist.name()).c_str(), cnt);
}
else {
snprintf (s, sizeof(s), "%s/%s_%" PRIu32 "-%" PRId32 ".wav", session->sound_dir().c_str(),
legalize_for_path(playlist.name()).c_str(), cnt, n);
}
if (::access (s, F_OK) != 0) {
break;
}
}
if (cnt == 999999) {
error << "" << endmsg;
goto error_out;
}
path = s;
try {
fs = new FileSource (path, session->frame_rate());
}
catch (failed_constructor& err) {
goto error_out;
}
sources.push_back (fs);
}
for (list<AudioRange>::iterator i = range.begin(); i != range.end();) {
nframes = (*i).length();
pos = (*i).start;
while (nframes) {
jack_nframes_t this_time;
this_time = min (nframes, chunk_size);
for (uint32_t n=0; n < channels; ++n) {
fs = sources[n];
if (playlist.read (buf, buf, gain_buffer, pos, this_time, n) != this_time) {
break;
}
if (fs->write (buf, this_time) != this_time) {
goto error_out;
}
}
nframes -= this_time;
pos += this_time;
}
list<AudioRange>::iterator tmp = i;
++tmp;
if (tmp != range.end()) {
/* fill gaps with silence */
nframes = (*tmp).start - (*i).end;
while (nframes) {
jack_nframes_t this_time = min (nframes, chunk_size);
memset (buf, 0, sizeof (Sample) * this_time);
for (uint32_t n=0; n < channels; ++n) {
fs = sources[n];
if (fs->write (buf, this_time) != this_time) {
goto error_out;
}
}
nframes -= this_time;
}
}
i = tmp;
}
time_t tnow;
struct tm* now;
time (&tnow);
now = localtime (&tnow);
for (uint32_t n=0; n < channels; ++n) {
sources[n]->update_header (0, *now, tnow);
// do we need to ref it again?
}
return true;
error_out:
/* unref created files */
for (vector<FileSource*>::iterator i = sources.begin(); i != sources.end(); ++i) {
(*i)->mark_for_remove ();
delete *i;
}
return false;
}
void
Editor::write_selection ()
{
if (!selection->time.empty()) {
write_audio_selection (selection->time);
} else if (!selection->audio_regions.empty()) {
write_region_selection (selection->audio_regions);
}
}

View File

@@ -0,0 +1,270 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include "editor.h"
#include <ardour/session.h>
using namespace std;
using namespace ARDOUR;
void
Editor::hscroll_slider_allocate (GtkAllocation *alloc)
{
//edit_hscroll_slider_width = alloc->width;
//edit_hscroll_slider_height = alloc->height ;
if (session) {
track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
}
}
gint
Editor::hscroll_slider_expose (GdkEventExpose *ev)
{
GdkRectangle draw_rect;
GdkRectangle bar_rect;
gint bar_max = edit_hscroll_slider_width - 2;
bar_rect.y = 1;
bar_rect.height = edit_hscroll_slider_height - 2;
if (session) {
bar_rect.width = (gint) floor (bar_max * ((canvas_width * frames_per_unit) / session->current_end_frame()));
if (bar_rect.width > bar_max) {
bar_rect.x = 1;
bar_rect.width = bar_max;
} else {
bar_rect.x = 1 + (gint) floor (bar_max * ((double) leftmost_frame / session->current_end_frame()));
}
} else {
bar_rect.x = 1;
bar_rect.width = bar_max;
}
/* make sure we can see the bar at all times, and have enough to do zoom-trim on */
bar_rect.width = max ((guint16) (edit_hscroll_edge_width+5), bar_rect.width);
gdk_rectangle_intersect (&ev->area, &bar_rect, &draw_rect);
gtk_paint_box (edit_hscroll_slider.get_style()->gtkobj(),
edit_hscroll_slider.get_window(),
GTK_STATE_ACTIVE,
GTK_SHADOW_IN,
&ev->area,
GTK_WIDGET(edit_hscroll_slider.gtkobj()),
"trough",
0, 0, -1, -1);
gtk_paint_box (edit_hscroll_slider.get_style()->gtkobj(),
edit_hscroll_slider.get_window(),
GTK_STATE_NORMAL,
GTK_SHADOW_OUT,
&draw_rect,
GTK_WIDGET(edit_hscroll_slider.gtkobj()),
"hscale",
bar_rect.x, bar_rect.y, bar_rect.width, bar_rect.height);
return TRUE;
}
gint
Editor::hscroll_slider_button_press (GdkEventButton *ev)
{
if (!session) {
return TRUE;
}
edit_hscroll_dragging = true;
//cerr << "PRESS" << endl;
return TRUE;
gint start;
gint width;
gint end;
gint x;
start = (gint) floor (edit_hscroll_slider_width * ((double) leftmost_frame / session->current_end_frame()));
width = (gint) floor (edit_hscroll_slider_width * ((canvas_width * frames_per_unit) / session->current_end_frame()));
end = start + width - 1;
x = (gint) max (0.0, ev->x);
if (x >= start && x <= end) {
edit_hscroll_drag_last = x;
edit_hscroll_dragging = true;
Gtk::Main::grab_add (edit_hscroll_slider);
}
return TRUE;
}
gint
Editor::hscroll_slider_button_release (GdkEventButton *ev)
{
if (!session) {
return TRUE;
}
gint start;
gint width;
gint end;
gint x;
gint bar_max = edit_hscroll_slider_width - 2;
jack_nframes_t new_leftmost = 0;
//cerr << "RELESAE" << endl;
if (edit_hscroll_dragging) {
// lets do a tempo redisplay now only, because it is dog slow
tempo_map_changed (Change (0));
edit_hscroll_dragging = false;
}
return TRUE;
start = (gint) floor (bar_max * ((double) leftmost_frame / session->current_end_frame()));
width = (gint) floor (bar_max * ((canvas_width * frames_per_unit) / session->current_end_frame()));
end = start + width - 1;
x = (gint) max (0.0, ev->x);
if (!edit_hscroll_dragging) {
new_leftmost = (jack_nframes_t) floor (((double) x/bar_max) * session->current_end_frame());
reposition_x_origin (new_leftmost);
}
if (edit_hscroll_dragging) {
// lets do a tempo redisplay now only, because it is dog slow
tempo_map_changed (Change (0));
edit_hscroll_dragging = false;
Gtk::Main::grab_remove (edit_hscroll_slider);
}
return TRUE;
}
gint
Editor::hscroll_slider_motion (GdkEventMotion *ev)
{
gint x, y;
GdkModifierType state;
gint bar_max = edit_hscroll_slider_width - 2;
if (!session || !edit_hscroll_dragging) {
return TRUE;
}
edit_hscroll_slider.get_window().get_pointer (x, y, state);
jack_nframes_t new_frame;
jack_nframes_t frames;
double distance;
double fract;
distance = x - edit_hscroll_drag_last;
fract = fabs (distance) / bar_max;
frames = (jack_nframes_t) floor (session->current_end_frame() * fract);
if (distance < 0) {
if (leftmost_frame < frames) {
new_frame = 0;
} else {
new_frame = leftmost_frame - frames;
}
} else {
if (leftmost_frame > max_frames - frames) {
new_frame = max_frames;
} else {
new_frame = leftmost_frame + frames;
}
}
if (new_frame != leftmost_frame) {
reposition_x_origin (new_frame);
}
edit_hscroll_drag_last = x;
return TRUE;
}
void
Editor::update_hscroller ()
{
//edit_hscroll_slider.queue_draw ();
// if (session) {
// track_canvas_scroller.get_hadjustment()->set_upper (session->current_end_frame() / frames_per_unit);
// track_canvas_scroller.get_hadjustment()->set_value (leftmost_frame/frames_per_unit);
// }
}
gint
Editor::hscroll_left_arrow_button_press (GdkEventButton *ev)
{
if (!session) {
return FALSE;
}
start_canvas_autoscroll (-1);
return TRUE;
}
gint
Editor::hscroll_right_arrow_button_press (GdkEventButton *ev)
{
if (!session) {
return FALSE;
}
start_canvas_autoscroll (1);
return TRUE;
}
gint
Editor::hscroll_left_arrow_button_release (GdkEventButton *ev)
{
if (!session) {
return FALSE;
}
stop_canvas_autoscroll ();
return TRUE;
}
gint
Editor::hscroll_right_arrow_button_release (GdkEventButton *ev)
{
if (!session) {
return FALSE;
}
stop_canvas_autoscroll ();
return TRUE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,144 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <ardour/audioregion.h>
#include "editor.h"
#include "regionview.h"
#include "selection.h"
void
Editor::kbd_driver (SigC::Slot1<void,GdkEvent*> theslot, bool use_track_canvas, bool use_time_canvas, bool can_select)
{
gint x, y;
double dx, dy;
GdkEvent ev;
GdkModifierType mask;
Gdk_Window evw (track_canvas->get_window().get_pointer (x, y, mask));
bool doit = false;
if (use_track_canvas && gdk_window_get_pointer (track_canvas_event_box.get_window(),
&x, &y, &mask)) {
doit = true;
} else if (use_time_canvas && gdk_window_get_pointer (time_canvas_event_box.get_window(),
&x, &y, &mask)) {
doit = true;
}
if (doit) {
if (entered_regionview && can_select) {
selection->set (entered_regionview);
}
gtk_canvas_window_to_world (GTK_CANVAS(track_gtk_canvas), x, y, &dx, &dy);
ev.type = GDK_BUTTON_PRESS;
ev.button.x = dx;
ev.button.y = dy;
ev.button.state = 0; /* XXX correct? */
theslot (&ev);
}
}
void
Editor::kbd_set_playhead_cursor ()
{
kbd_driver (slot (*this, &Editor::set_playhead_cursor), true, true, false);
}
void
Editor::kbd_set_edit_cursor ()
{
kbd_driver (slot (*this, &Editor::set_edit_cursor), true, true, false);
}
void
Editor::kbd_do_split (GdkEvent* ev)
{
jack_nframes_t where = event_frame (ev);
if (entered_regionview) {
if (selection->audio_regions.find (entered_regionview) != selection->audio_regions.end()) {
split_regions_at (where, selection->audio_regions);
} else {
AudioRegionSelection s;
s.add (entered_regionview);
split_regions_at (where, s);
}
}
}
void
Editor::kbd_split ()
{
kbd_driver (slot (*this, &Editor::kbd_do_split), true, true, false);
}
void
Editor::kbd_do_align (GdkEvent* ev, ARDOUR::RegionPoint what)
{
align (what);
}
void
Editor::kbd_align (ARDOUR::RegionPoint what)
{
kbd_driver (bind (slot (*this, &Editor::kbd_do_align), what));
}
void
Editor::kbd_do_align_relative (GdkEvent* ev, ARDOUR::RegionPoint what)
{
align (what);
}
void
Editor::kbd_align_relative (ARDOUR::RegionPoint what)
{
kbd_driver (bind (slot (*this, &Editor::kbd_do_align), what), true, true, false);
}
void
Editor::kbd_do_brush (GdkEvent *ev)
{
brush (event_frame (ev, 0, 0));
}
void
Editor::kbd_brush ()
{
kbd_driver (slot (*this, &Editor::kbd_do_brush), true, true, false);
}
void
Editor::kbd_do_audition (GdkEvent *ignored)
{
audition_selected_region ();
}
void
Editor::kbd_audition ()
{
kbd_driver (slot (*this, &Editor::kbd_do_audition), true, false, true);
}

268
gtk2_ardour/editor_keys.cc Normal file
View File

@@ -0,0 +1,268 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include <string>
#include <pbd/error.h>
#include <gtkmmext/popup_selector.h>
#include <ardour/session.h>
#include <ardour/region.h>
#include "ardour_ui.h"
#include "editor.h"
#include "time_axis_view.h"
#include "regionview.h"
#include "selection.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace SigC;
void
Editor::install_keybindings ()
{
/* add named actions for the editor */
add_action ("toggle-xfades-active", slot (*this, &Editor::toggle_xfades_active));
add_action ("playhead-to-next-region-start", bind (slot (*this, &Editor::cursor_to_next_region_point), playhead_cursor, RegionPoint (Start)));
add_action ("playhead-to-next-region-end", bind (slot (*this, &Editor::cursor_to_next_region_point), playhead_cursor, RegionPoint (End)));
add_action ("playhead-to-next-region-sync", bind (slot (*this, &Editor::cursor_to_next_region_point), playhead_cursor, RegionPoint (SyncPoint)));
add_action ("playhead-to-previous-region-start", bind (slot (*this, &Editor::cursor_to_previous_region_point), playhead_cursor, RegionPoint (Start)));
add_action ("playhead-to-previous-region-end", bind (slot (*this, &Editor::cursor_to_previous_region_point), playhead_cursor, RegionPoint (End)));
add_action ("playhead-to-previous-region-sync", bind (slot (*this, &Editor::cursor_to_previous_region_point), playhead_cursor, RegionPoint (SyncPoint)));
add_action ("edit-cursor-to-next-region-start", bind (slot (*this, &Editor::cursor_to_next_region_point), edit_cursor, RegionPoint (Start)));
add_action ("edit-cursor-to-next-region-end", bind (slot (*this, &Editor::cursor_to_next_region_point), edit_cursor, RegionPoint (End)));
add_action ("edit-cursor-to-next-region-sync", bind (slot (*this, &Editor::cursor_to_next_region_point), edit_cursor, RegionPoint (SyncPoint)));
add_action ("edit-cursor-to-previous-region-start", bind (slot (*this, &Editor::cursor_to_previous_region_point), edit_cursor, RegionPoint (Start)));
add_action ("edit-cursor-to-previous-region-end", bind (slot (*this, &Editor::cursor_to_previous_region_point), edit_cursor, RegionPoint (End)));
add_action ("edit-cursor-to-previous-region-sync", bind (slot (*this, &Editor::cursor_to_previous_region_point), edit_cursor, RegionPoint (SyncPoint)));
add_action ("playhead-to-range-start", bind (slot (*this, &Editor::cursor_to_selection_start), playhead_cursor));
add_action ("playhead-to-range-end", bind (slot (*this, &Editor::cursor_to_selection_end), playhead_cursor));
add_action ("edit-cursor-to-range-start", bind (slot (*this, &Editor::cursor_to_selection_start), edit_cursor));
add_action ("edit-cursor-to-range-end", bind (slot (*this, &Editor::cursor_to_selection_end), edit_cursor));
add_action ("jump-forward-to-mark", slot (*this, &Editor::jump_forward_to_mark));
add_action ("jump-backward-to-mark", slot (*this, &Editor::jump_backward_to_mark));
add_action ("add-location-from-playhead", slot (*this, &Editor::add_location_from_playhead_cursor));
add_action ("nudge-forward", bind (slot (*this, &Editor::nudge_forward), false));
add_action ("nudge-next-forward", bind (slot (*this, &Editor::nudge_forward), true));
add_action ("nudge-backward", bind (slot (*this, &Editor::nudge_backward), false));
add_action ("nudge-next-backward", bind (slot (*this, &Editor::nudge_backward), true));
add_action ("toggle-playback", bind (slot (*this, &Editor::toggle_playback), false));
add_action ("toggle-playback-forget-capture", bind (slot (*this, &Editor::toggle_playback), true));
add_action ("toggle-loop-playback", slot (*this, &Editor::toggle_loop_playback));
add_action ("temporal-zoom-out", bind (slot (*this, &Editor::temporal_zoom_step), true));
add_action ("temporal-zoom-in", bind (slot (*this, &Editor::temporal_zoom_step), false));
add_action ("zoom-to-session", slot (*this, &Editor::temporal_zoom_session));
add_action ("scroll-tracks-up", slot (*this, &Editor::scroll_tracks_up));
add_action ("scroll-tracks-down", slot (*this, &Editor::scroll_tracks_down));
add_action ("step-tracks-up", slot (*this, &Editor::scroll_tracks_up_line));
add_action ("step-tracks-down", slot (*this, &Editor::scroll_tracks_down_line));
add_action ("scroll-backward", bind (slot (*this, &Editor::scroll_backward), 0.8f));
add_action ("scroll-forward", bind (slot (*this, &Editor::scroll_forward), 0.8f));
add_action ("goto", slot (*this, &Editor::goto_frame));
add_action ("center-playhead", slot (*this, &Editor::center_playhead));
add_action ("center-edit_cursor", slot (*this, &Editor::center_edit_cursor));
add_action ("playhead-forward", slot (*this, &Editor::playhead_forward));
add_action ("playhead-backward", slot (*this, &Editor::playhead_backward));
add_action ("playhead-to-edit", bind (slot (*this, &Editor::cursor_align), true));
add_action ("edit-to-playhead", bind (slot (*this, &Editor::cursor_align), false));
add_action ("align-regions-start", bind (slot (*this, &Editor::align), ARDOUR::Start));
add_action ("align-regions-start-relative", bind (slot (*this, &Editor::align_relative), ARDOUR::Start));
add_action ("align-regions-end", bind (slot (*this, &Editor::align), ARDOUR::End));
add_action ("align-regions-end-relative", bind (slot (*this, &Editor::align_relative), ARDOUR::End));
add_action ("align-regions-sync", bind (slot (*this, &Editor::align), ARDOUR::SyncPoint));
add_action ("align-regions-sync-relative", bind (slot (*this, &Editor::align_relative), ARDOUR::SyncPoint));
add_action ("set-playhead", slot (*this, &Editor::kbd_set_playhead_cursor));
add_action ("set-edit-cursor", slot (*this, &Editor::kbd_set_edit_cursor));
add_action ("set-mouse-mode-object", bind (slot (*this, &Editor::set_mouse_mode), Editing::MouseObject, false));
add_action ("set-mouse-mode-range", bind (slot (*this, &Editor::set_mouse_mode), Editing::MouseRange, false));
add_action ("set-mouse-mode-gain", bind (slot (*this, &Editor::set_mouse_mode), Editing::MouseGain, false));
add_action ("set-mouse-mode-zoom", bind (slot (*this, &Editor::set_mouse_mode), Editing::MouseZoom, false));
add_action ("set-mouse-mode-timefx", bind (slot (*this, &Editor::set_mouse_mode), Editing::MouseTimeFX, false));
add_action ("set-undo", bind (slot (*this, &Editor::undo), 1U));
add_action ("set-redo", bind (slot (*this, &Editor::redo), 1U));
add_action ("export-session", slot (*this, &Editor::export_session));
add_action ("export-range", slot (*this, &Editor::export_selection));
add_action ("editor-cut", slot (*this, &Editor::cut));
add_action ("editor-copy", slot (*this, &Editor::copy));
add_action ("editor-paste", slot (*this, &Editor::keyboard_paste));
add_action ("duplicate-region", slot (*this, &Editor::keyboard_duplicate_region));
add_action ("duplicate-range", slot (*this, &Editor::keyboard_duplicate_selection));
add_action ("insert-region", slot (*this, &Editor::keyboard_insert_region_list_selection));
add_action ("reverse-region", slot (*this, &Editor::reverse_region));
add_action ("normalize-region", slot (*this, &Editor::normalize_region));
add_action ("editor-crop", slot (*this, &Editor::crop_region_to_selection));
add_action ("insert-chunk", bind (slot (*this, &Editor::paste_named_selection), 1.0f));
add_action ("split-at-edit-cursor", slot (*this, &Editor::split_region));
add_action ("split-at-mouse", slot (*this, &Editor::kbd_split));
add_action ("brush-at-mouse", slot (*this, &Editor::kbd_brush));
add_action ("audition-at-mouse", slot (*this, &Editor::kbd_audition));
add_action ("start-range", slot (*this, &Editor::keyboard_selection_begin));
add_action ("finish-range", bind (slot (*this, &Editor::keyboard_selection_finish), false));
add_action ("finish-add-range", bind (slot (*this, &Editor::keyboard_selection_finish), true));
add_action ("extend-range-to-end-of-region", bind (slot (*this, &Editor::extend_selection_to_end_of_region), false));
add_action ("extend-range-to-start-of-region", bind (slot (*this, &Editor::extend_selection_to_start_of_region), false));
add_action ("zoom-focus-left", bind (slot (*this, &Editor::set_zoom_focus), Editing::ZoomFocusLeft));
add_action ("zoom-focus-right", bind (slot (*this, &Editor::set_zoom_focus), Editing::ZoomFocusRight));
add_action ("zoom-focus-center", bind (slot (*this, &Editor::set_zoom_focus), Editing::ZoomFocusCenter));
add_action ("zoom-focus-playhead", bind (slot (*this, &Editor::set_zoom_focus), Editing::ZoomFocusPlayhead));
add_action ("zoom-focus-edit", bind (slot (*this, &Editor::set_zoom_focus), Editing::ZoomFocusEdit));
add_action ("toggle-follow-playhead", (slot (*this, &Editor::toggle_follow_playhead)));
add_action ("remove-last-capture", (slot (*this, &Editor::remove_last_capture)));
add_action ("snap-to-frame", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToFrame)));
add_action ("snap-to-cd-frame", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToCDFrame)));
add_action ("snap-to-smpte-frame", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToSMPTEFrame)));
add_action ("snap-to-smpte-seconds", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToSMPTESeconds)));
add_action ("snap-to-smpte-minutes", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToSMPTEMinutes)));
add_action ("snap-to-seconds", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToSeconds)));
add_action ("snap-to-minutes", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToMinutes)));
add_action ("snap-to-thirtyseconds", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToAThirtysecondBeat)));
add_action ("snap-to-asixteenthbeat", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToASixteenthBeat)));
add_action ("snap-to-eighths", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToAEighthBeat)));
add_action ("snap-to-quarters", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToAQuarterBeat)));
add_action ("snap-to-thirds", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToAThirdBeat)));
add_action ("snap-to-beat", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToBeat)));
add_action ("snap-to-bar", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToBar)));
add_action ("snap-to-mark", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToMark)));
add_action ("snap-to-edit-cursor", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToEditCursor)));
add_action ("snap-to-region-start", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToRegionStart)));
add_action ("snap-to-region-end", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToRegionEnd)));
add_action ("snap-to-region-sync", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToRegionSync)));
add_action ("snap-to-region-boundary", (bind (slot (*this, &Editor::set_snap_to), Editing::SnapToRegionBoundary)));
}
void
Editor::keyboard_selection_finish (bool add)
{
if (session && have_pending_keyboard_selection) {
begin_reversible_command (_("keyboard selection"));
if (!add) {
selection->set (0, pending_keyboard_selection_start, session->audible_frame());
} else {
selection->add (pending_keyboard_selection_start, session->audible_frame());
}
commit_reversible_command ();
have_pending_keyboard_selection = false;
}
}
void
Editor::keyboard_selection_begin ()
{
if (session) {
pending_keyboard_selection_start = session->audible_frame();
have_pending_keyboard_selection = true;
}
}
void
Editor::keyboard_duplicate_region ()
{
if (selection->audio_regions.empty()) {
return;
}
float prefix;
bool was_floating;
if (get_prefix (prefix, was_floating) == 0) {
duplicate_some_regions (selection->audio_regions, prefix);
} else {
duplicate_some_regions (selection->audio_regions, 1);
}
}
void
Editor::keyboard_duplicate_selection ()
{
float prefix;
bool was_floating;
if (get_prefix (prefix, was_floating) == 0) {
duplicate_selection (prefix);
} else {
duplicate_selection (1);
}
}
void
Editor::keyboard_paste ()
{
float prefix;
bool was_floating;
if (get_prefix (prefix, was_floating) == 0) {
paste (prefix);
} else {
paste (1);
}
}
void
Editor::keyboard_insert_region_list_selection ()
{
float prefix;
bool was_floating;
if (get_prefix (prefix, was_floating) == 0) {
insert_region_list_selection (prefix);
} else {
insert_region_list_selection (1);
}
}
int
Editor::get_prefix (float& val, bool& was_floating)
{
return Keyboard::the_keyboard().get_prefix (val, was_floating);
}

View File

@@ -0,0 +1,911 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <sigc++/rettype.h>
#include <cstdlib>
#include <cmath>
#include <gtk-canvas.h>
#include <gtkmmext/gtk_ui.h>
#include <ardour/location.h>
#include "editor.h"
#include "marker.h"
#include "selection.h"
#include "editing.h"
#include "gui_thread.h"
#include "i18n.h"
using namespace std;
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;
void
Editor::clear_marker_display ()
{
for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
delete i->second;
}
location_markers.clear ();
}
void
Editor::add_new_location (Location *location)
{
LocationMarkers *lam = new LocationMarkers;
uint32_t color;
if (location->is_cd_marker()) {
color = location_cd_marker_color;
} else if (location->is_mark()) {
color = location_marker_color;
} else if (location->is_auto_loop()) {
color = location_loop_color;
} else if (location->is_auto_punch()) {
color = location_punch_color;
} else {
color = location_range_color;
}
if (location->is_mark()) {
lam->start = new Marker (*this, GTK_CANVAS_GROUP(marker_group), color,
location->name(), Marker::Mark, PublicEditor::canvas_marker_event, location->start());
lam->end = 0;
} else if (location->is_auto_loop()) {
// transport marker
lam->start = new Marker (*this, GTK_CANVAS_GROUP(transport_marker_group), color,
location->name(), Marker::LoopStart, PublicEditor::canvas_marker_event, location->start());
lam->end = new Marker (*this, GTK_CANVAS_GROUP(transport_marker_group), color,
location->name(), Marker::LoopEnd, PublicEditor::canvas_marker_event, location->end());
} else if (location->is_auto_punch()) {
// transport marker
lam->start = new Marker (*this, GTK_CANVAS_GROUP(transport_marker_group), color,
location->name(), Marker::PunchIn, PublicEditor::canvas_marker_event, location->start());
lam->end = new Marker (*this, GTK_CANVAS_GROUP(transport_marker_group), color,
location->name(), Marker::PunchOut, PublicEditor::canvas_marker_event, location->end());
} else {
// range marker
lam->start = new Marker (*this, GTK_CANVAS_GROUP(range_marker_group), color,
location->name(), Marker::Start, PublicEditor::canvas_marker_event, location->start());
lam->end = new Marker (*this, GTK_CANVAS_GROUP(range_marker_group), color,
location->name(), Marker::End, PublicEditor::canvas_marker_event, location->end());
}
if (location->is_hidden ()) {
lam->hide();
} else {
lam->show ();
}
location->start_changed.connect (slot (*this, &Editor::location_changed));
location->end_changed.connect (slot (*this, &Editor::location_changed));
location->changed.connect (slot (*this, &Editor::location_changed));
location->name_changed.connect (slot (*this, &Editor::location_changed));
location->FlagsChanged.connect (slot (*this, &Editor::location_flags_changed));
pair<Location*,LocationMarkers*> newpair;
newpair.first = location;
newpair.second = lam;
location_markers.insert (newpair);
}
void
Editor::location_changed (Location *location)
{
ENSURE_GUI_THREAD (bind (slot (*this, &Editor::location_changed), location));
LocationMarkers *lam = find_location_markers (location);
if (lam == 0) {
/* a location that isn't "marked" with markers */
return;
}
lam->set_name (location->name());
lam->set_position (location->start(), location->end());
if (location->is_auto_loop()) {
update_loop_range_view ();
} else if (location->is_auto_punch()) {
update_punch_range_view ();
}
}
void
Editor::location_flags_changed (Location *location, void *src)
{
ENSURE_GUI_THREAD(bind (slot (*this, &Editor::location_flags_changed), location, src));
LocationMarkers *lam = find_location_markers (location);
if (lam == 0) {
/* a location that isn't "marked" with markers */
return;
}
if (location->is_cd_marker()) {
lam->set_color_rgba (location_cd_marker_color);
} else if (location->is_mark()) {
lam->set_color_rgba (location_marker_color);
} else if (location->is_auto_punch()) {
lam->set_color_rgba (location_punch_color);
} else if (location->is_auto_loop()) {
lam->set_color_rgba (location_loop_color);
} else {
lam->set_color_rgba (location_range_color);
}
if (location->is_hidden()) {
lam->hide();
} else {
lam->show ();
}
}
Editor::LocationMarkers::~LocationMarkers ()
{
if (start) {
delete start;
}
if (end) {
delete end;
}
}
Editor::LocationMarkers *
Editor::find_location_markers (Location *location)
{
LocationMarkerMap::iterator i;
for (i = location_markers.begin(); i != location_markers.end(); ++i) {
if ((*i).first == location) {
return (*i).second;
}
}
return 0;
}
Location *
Editor::find_location_from_marker (Marker *marker, bool& is_start)
{
LocationMarkerMap::iterator i;
for (i = location_markers.begin(); i != location_markers.end(); ++i) {
LocationMarkers *lm = (*i).second;
if (lm->start == marker) {
is_start = true;
return (*i).first;
} else if (lm->end == marker) {
is_start = false;
return (*i).first;
}
}
return 0;
}
void
Editor::refresh_location_display_internal (Locations::LocationList& locations)
{
clear_marker_display ();
for (Locations::LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
add_new_location (*i);
}
}
void
Editor::refresh_location_display ()
{
ENSURE_GUI_THREAD(slot (*this, &Editor::refresh_location_display));
if (session) {
session->locations()->apply (*this, &Editor::refresh_location_display_internal);
}
}
void
Editor::refresh_location_display_s (Change ignored)
{
ENSURE_GUI_THREAD(bind (slot (*this, &Editor::refresh_location_display_s), ignored));
if (session) {
session->locations()->apply (*this, &Editor::refresh_location_display_internal);
}
}
void
Editor::LocationMarkers::hide()
{
start->hide ();
if (end) { end->hide(); }
}
void
Editor::LocationMarkers::show()
{
start->show ();
if (end) { end->show(); }
}
void
Editor::LocationMarkers::set_name (const string& str)
{
start->set_name (str);
if (end) { end->set_name (str); }
}
void
Editor::LocationMarkers::set_position (jack_nframes_t startf,
jack_nframes_t endf)
{
start->set_position (startf);
if (end) { end->set_position (endf); }
}
void
Editor::LocationMarkers::set_color_rgba (uint32_t rgba)
{
start->set_color_rgba (rgba);
if (end) { end->set_color_rgba (rgba); }
}
void
Editor::mouse_add_new_marker (jack_nframes_t where)
{
if (session) {
Location *location = new Location (where, where, "mark", Location::IsMark);
session->begin_reversible_command (_("add marker"));
session->add_undo (session->locations()->get_memento());
session->locations()->add (location, true);
session->add_redo_no_execute (session->locations()->get_memento());
session->commit_reversible_command ();
}
}
void
Editor::remove_marker (GtkCanvasItem* item, GdkEvent* event)
{
Marker* marker;
bool is_start;
if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
Location* loc = find_location_from_marker (marker, is_start);
if (session && loc) {
if (loc->is_end()) {
/* you can't hide or delete this marker */
return;
}
if (loc->is_auto_loop() || loc->is_auto_punch()) {
// just hide them
loc->set_hidden (true, this);
}
else {
Gtk::Main::idle.connect (bind (slot (*this, &Editor::really_remove_marker), loc));
}
}
}
gint
Editor::really_remove_marker (Location* loc)
{
session->begin_reversible_command (_("remove marker"));
session->add_undo (session->locations()->get_memento());
session->locations()->remove (loc);
session->add_redo_no_execute (session->locations()->get_memento());
session->commit_reversible_command ();
return FALSE;
}
void
Editor::location_gone (Location *location)
{
ENSURE_GUI_THREAD(bind (slot (*this, &Editor::location_gone), location));
LocationMarkerMap::iterator i;
if (location == transport_loop_location()) {
update_loop_range_view (true);
}
if (location == transport_punch_location()) {
update_punch_range_view (true);
}
for (i = location_markers.begin(); i != location_markers.end(); ++i) {
if ((*i).first == location) {
delete (*i).second;
location_markers.erase (i);
break;
}
}
}
void
Editor::tm_marker_context_menu (GdkEventButton* ev, GtkCanvasItem* item)
{
if (tm_marker_menu == 0) {
build_tm_marker_menu ();
}
marker_menu_item = item;
tm_marker_menu->popup (1, ev->time);
}
void
Editor::marker_context_menu (GdkEventButton* ev, GtkCanvasItem* item)
{
Marker * marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
bool is_start;
Location * loc = find_location_from_marker (marker, is_start);
if (loc == transport_loop_location() || loc == transport_punch_location()) {
if (transport_marker_menu == 0) {
build_transport_marker_menu ();
}
marker_menu_item = item;
transport_marker_menu->popup (1, ev->time);
}
else {
if (marker_menu == 0) {
build_marker_menu ();
}
Menu_Helpers::MenuList & children = marker_menu->items();
// XXX: should really find this some other way
if (children.size() >= 3) {
MenuItem * loopitem = children[2];
if (loopitem) {
if (loc->is_mark()) {
loopitem->set_sensitive(false);
}
else {
loopitem->set_sensitive(true);
}
}
}
marker_menu_item = item;
marker_menu->popup (1, ev->time);
}
}
void
Editor::new_transport_marker_context_menu (GdkEventButton* ev, GtkCanvasItem* item)
{
if (new_transport_marker_menu == 0) {
build_new_transport_marker_menu ();
}
new_transport_marker_menu->popup (1, ev->time);
}
void
Editor::transport_marker_context_menu (GdkEventButton* ev, GtkCanvasItem* item)
{
if (transport_marker_menu == 0) {
build_transport_marker_menu ();
}
transport_marker_menu->popup (1, ev->time);
}
void
Editor::build_marker_menu ()
{
using namespace Menu_Helpers;
marker_menu = new Menu;
MenuList& items = marker_menu->items();
marker_menu->set_name ("ArdourContextMenu");
items.push_back (MenuElem (_("Locate to"), slot (*this, &Editor::marker_menu_set_playhead)));
items.push_back (MenuElem (_("Play from"), slot (*this, &Editor::marker_menu_play_from)));
items.push_back (MenuElem (_("Loop range"), slot (*this, &Editor::marker_menu_loop_range)));
items.push_back (MenuElem (_("Set from playhead"), slot (*this, &Editor::marker_menu_set_from_playhead)));
items.push_back (MenuElem (_("Set from range"), slot (*this, &Editor::marker_menu_set_from_selection)));
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Rename"), slot (*this, &Editor::marker_menu_rename)));
items.push_back (MenuElem (_("Hide"), slot (*this, &Editor::marker_menu_hide)));
items.push_back (MenuElem (_("Remove"), slot (*this, &Editor::marker_menu_remove)));
}
void
Editor::build_tm_marker_menu ()
{
using namespace Menu_Helpers;
tm_marker_menu = new Menu;
MenuList& items = tm_marker_menu->items();
tm_marker_menu->set_name ("ArdourContextMenu");
items.push_back (MenuElem (_("Edit"), slot (*this, &Editor::marker_menu_edit)));
items.push_back (MenuElem (_("Remove"), slot (*this, &Editor::marker_menu_remove)));
}
void
Editor::build_new_transport_marker_menu ()
{
using namespace Menu_Helpers;
new_transport_marker_menu = new Menu;
MenuList& items = new_transport_marker_menu->items();
new_transport_marker_menu->set_name ("ArdourContextMenu");
items.push_back (MenuElem (_("Set Loop Range"), slot (*this, &Editor::new_transport_marker_menu_set_loop)));
items.push_back (MenuElem (_("Set Punch Range"), slot (*this, &Editor::new_transport_marker_menu_set_punch)));
new_transport_marker_menu->unmap_event.connect ( slot (*this, &Editor::new_transport_marker_menu_popdown));
}
void
Editor::build_transport_marker_menu ()
{
using namespace Menu_Helpers;
transport_marker_menu = new Menu;
MenuList& items = transport_marker_menu->items();
transport_marker_menu->set_name ("ArdourContextMenu");
items.push_back (MenuElem (_("Locate to"), slot (*this, &Editor::marker_menu_set_playhead)));
items.push_back (MenuElem (_("Play from"), slot (*this, &Editor::marker_menu_play_from)));
items.push_back (MenuElem (_("Set from playhead"), slot (*this, &Editor::marker_menu_set_from_playhead)));
items.push_back (MenuElem (_("Set from range"), slot (*this, &Editor::marker_menu_set_from_selection)));
items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Hide"), slot (*this, &Editor::marker_menu_hide)));
}
void
Editor::marker_menu_hide ()
{
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
Location* l;
bool is_start;
if ((l = find_location_from_marker (marker, is_start)) != 0) {
l->set_hidden (true, this);
}
}
void
Editor::marker_menu_play_from ()
{
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
Location* l;
bool is_start;
if ((l = find_location_from_marker (marker, is_start)) != 0) {
if (l->is_mark()) {
session->request_locate (l->start(), true);
}
else {
//session->request_bounded_roll (l->start(), l->end());
if (is_start) {
session->request_locate (l->start(), true);
} else {
session->request_locate (l->end(), true);
}
}
}
}
void
Editor::marker_menu_set_playhead ()
{
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
Location* l;
bool is_start;
if ((l = find_location_from_marker (marker, is_start)) != 0) {
if (l->is_mark()) {
session->request_locate (l->start(), false);
}
else {
if (is_start) {
session->request_locate (l->start(), false);
} else {
session->request_locate (l->end(), false);
}
}
}
}
void
Editor::marker_menu_set_from_playhead ()
{
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
Location* l;
bool is_start;
if ((l = find_location_from_marker (marker, is_start)) != 0) {
if (l->is_mark()) {
l->set_start (session->transport_frame ());
}
else {
if (is_start) {
l->set_start (session->transport_frame ());
} else {
l->set_end (session->transport_frame ());
}
}
}
}
void
Editor::marker_menu_set_from_selection ()
{
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
Location* l;
bool is_start;
if ((l = find_location_from_marker (marker, is_start)) != 0) {
if (l->is_mark()) {
// nothing for now
}
else {
/* if range selection use first to last */
if (mouse_mode == Editing::MouseRange) {
if (!selection->time.empty()) {
l->set_start (selection->time.start());
l->set_end (selection->time.end_frame());
}
}
else {
if (!selection->audio_regions.empty()) {
l->set_start (selection->audio_regions.start());
l->set_end (selection->audio_regions.end_frame());
}
}
}
}
}
void
Editor::marker_menu_loop_range ()
{
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
Location* l;
bool is_start;
if ((l = find_location_from_marker (marker, is_start)) != 0) {
Location* l2;
if ((l2 = transport_loop_location()) != 0) {
l2->set (l->start(), l->end());
// enable looping, reposition and start rolling
session->request_auto_loop(true);
session->request_locate (l2->start(), true);
}
}
}
void
Editor::marker_menu_edit ()
{
MeterMarker* mm;
TempoMarker* tm;
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
edit_meter_section (&mm->meter());
} else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
edit_tempo_section (&tm->tempo());
} else {
fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
<< endmsg;
/*NOTREACHED*/
}
}
void
Editor::marker_menu_remove ()
{
MeterMarker* mm;
TempoMarker* tm;
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
remove_meter_marker (marker_menu_item);
} else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
remove_tempo_marker (marker_menu_item);
} else {
remove_marker (marker_menu_item, (GdkEvent*) 0);
}
}
void
Editor::marker_menu_rename ()
{
Marker* marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
Location* loc;
bool is_start;
loc = find_location_from_marker (marker, is_start);
if (!loc) return;
Dialog dialog;
Entry entry;
Button ok_button (_("OK"));
Button cancel_button (_("Cancel"));
if (loc->is_mark()) {
dialog.set_title (_("ardour: rename mark"));
} else {
dialog.set_title (_("ardour: rename range"));
}
dialog.set_name ("MarkRenameWindow");
dialog.set_usize (300, -1);
dialog.set_position (GTK_WIN_POS_MOUSE);
dialog.set_modal (true);
dialog.get_vbox()->set_border_width (10);
dialog.get_vbox()->pack_start (entry);
dialog.get_action_area()->pack_start (ok_button);
dialog.get_action_area()->pack_start (cancel_button);
entry.set_text (loc->name());
entry.set_name ("MarkerNameDisplay");
ok_button.set_name ("EditorGTKButton");
cancel_button.set_name ("EditorGTKButton");
entry.activate.connect (bind (slot (*this, &Editor::finish_sub_event_loop), 1));
cancel_button.clicked.connect (bind (slot (*this, &Editor::finish_sub_event_loop), -1));
ok_button.clicked.connect (bind (slot (*this, &Editor::finish_sub_event_loop), 1));
dialog.delete_event.connect (bind (slot (*this, &Editor::finish_sub_event_loop_on_delete), -1));
dialog.show_all ();
entry.grab_focus ();
run_sub_event_loop ();
if (sub_event_loop_status == 1) {
Location* l;
bool is_start;
if ((l = find_location_from_marker (marker, is_start)) != 0) {
l->set_name (entry.get_text());
}
}
}
gint
Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
{
// hide rects
gtk_canvas_item_hide (transport_bar_drag_rect);
gtk_canvas_item_hide (range_marker_drag_rect);
return FALSE;
}
void
Editor::new_transport_marker_menu_set_loop ()
{
if (!session) return;
begin_reversible_command (_("set loop range"));
Location* tll;
if ((tll = transport_loop_location()) == 0) {
Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"), Location::IsAutoLoop);
session->add_undo (session->locations()->get_memento());
session->locations()->add (loc, true);
session->set_auto_loop_location (loc);
session->add_redo_no_execute (session->locations()->get_memento());
}
else {
session->add_undo (rettype<void>(bind (slot (*tll, &Location::set), tll->start(), tll->end())));
session->add_redo (rettype<void>(bind (slot (*tll, &Location::set), temp_location->start(), temp_location->end())));
tll->set_hidden (false, this);
tll->set (temp_location->start(), temp_location->end());
}
commit_reversible_command ();
}
void
Editor::new_transport_marker_menu_set_punch ()
{
if (!session) return;
begin_reversible_command (_("set punch range"));
Location* tpl;
if ((tpl = transport_punch_location()) == 0) {
tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
session->add_undo (session->locations()->get_memento());
session->locations()->add (tpl, true);
session->set_auto_punch_location (tpl);
session->add_redo_no_execute (session->locations()->get_memento());
} else {
session->add_undo (rettype<void>(bind (slot (*tpl, &Location::set), tpl->start(), tpl->end())));
session->add_redo (rettype<void>(bind (slot (*tpl, &Location::set), temp_location->start(), temp_location->end())));
tpl->set_hidden(false, this);
tpl->set(temp_location->start(), temp_location->end());
}
commit_reversible_command ();
}
void
Editor::update_loop_range_view (bool visibility)
{
if (session == 0) {
return;
}
Location* tll;
if (session->get_auto_loop() && ((tll = transport_loop_location()) != 0)) {
double x1 = frame_to_pixel (tll->start());
double x2 = frame_to_pixel (tll->end());
gtk_canvas_item_set (transport_loop_range_rect, "x1", x1, "x2", x2, NULL);
if (visibility) {
gtk_canvas_item_show (transport_loop_range_rect);
}
}
else if (visibility) {
gtk_canvas_item_hide (transport_loop_range_rect);
}
}
void
Editor::update_punch_range_view (bool visibility)
{
if (session == 0) {
return;
}
Location* tpl;
if ((session->get_punch_in() || session->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
double x1 = frame_to_pixel (tpl->start());
double x2 = frame_to_pixel (tpl->end());
gtk_canvas_item_set (transport_punch_range_rect, "x1", x1, "x2", x2, NULL);
if (visibility) {
gtk_canvas_item_show (transport_punch_range_rect);
}
}
else if (visibility) {
gtk_canvas_item_hide (transport_punch_range_rect);
}
// if (session->get_punch_in()) {
// double x = frame_to_pixel (transport_punch_location->start());
// gtk_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
// if (visibility) {
// gtk_canvas_item_show (transport_punchin_line);
// }
// }
// else if (visibility) {
// gtk_canvas_item_hide (transport_punchin_line);
// }
// if (session->get_punch_out()) {
// double x = frame_to_pixel (transport_punch_location->end());
// gtk_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
// if (visibility) {
// gtk_canvas_item_show (transport_punchout_line);
// }
// }
// else if (visibility) {
// gtk_canvas_item_hide (transport_punchout_line);
// }
}

311
gtk2_ardour/editor_mixer.cc Normal file
View File

@@ -0,0 +1,311 @@
/*
Copyright (C) 2003-2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <gtkmmext/utils.h>
#include <ardour/audioengine.h>
#include "editor.h"
#include "mixer_strip.h"
#include "ardour_ui.h"
#include "selection.h"
#include "audio_time_axis.h"
#include "i18n.h"
void
Editor::editor_mixer_button_toggled ()
{
show_editor_mixer (editor_mixer_button.get_active());
}
void
Editor::cms_deleted ()
{
current_mixer_strip = 0;
}
void
Editor::show_editor_mixer (bool yn)
{
if (yn) {
if (current_mixer_strip == 0) {
if (selection->tracks.empty()) {
if (track_views.empty()) {
return;
}
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
*session,
atv->route(), false);
current_mixer_strip->GoingAway.connect (slot (*this, &Editor::cms_deleted));
break;
}
}
} else {
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
*session,
atv->route(), false);
current_mixer_strip->GoingAway.connect (slot (*this, &Editor::cms_deleted));
break;
}
}
}
if (current_mixer_strip == 0) {
return;
}
}
if (current_mixer_strip->get_parent() == 0) {
current_mixer_strip->set_embedded (true);
current_mixer_strip->Hiding.connect (slot (*this, &Editor::current_mixer_strip_hidden));
current_mixer_strip->GoingAway.connect (slot (*this, &Editor::current_mixer_strip_removed));
current_mixer_strip->set_width (editor_mixer_strip_width);
current_mixer_strip->show_all ();
global_hpacker.pack_start (*current_mixer_strip, false, false);
global_hpacker.reorder_child (*current_mixer_strip, 0);
}
} else {
if (current_mixer_strip) {
editor_mixer_strip_width = current_mixer_strip->get_width ();
if (current_mixer_strip->get_parent() != 0) {
global_hpacker.remove (*current_mixer_strip);
}
}
}
}
void
Editor::set_selected_mixer_strip (TimeAxisView& view)
{
AudioTimeAxisView* at;
bool show = false;
if (!session || (at = dynamic_cast<AudioTimeAxisView*>(&view)) == 0) {
return;
}
if (current_mixer_strip) {
/* might be nothing to do */
if (&current_mixer_strip->route() == &at->route()) {
return;
}
if (current_mixer_strip->get_parent()) {
show = true;
}
delete current_mixer_strip;
current_mixer_strip = 0;
}
current_mixer_strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(),
*session,
at->route());
current_mixer_strip->GoingAway.connect (slot (*this, &Editor::cms_deleted));
if (show) {
show_editor_mixer (true);
}
}
void
Editor::update_current_screen ()
{
if (session && engine.running()) {
jack_nframes_t frame;
frame = session->audible_frame();
/* only update if the playhead is on screen or we are following it */
if (_follow_playhead) {
gtk_canvas_item_show (playhead_cursor->canvas_item);
if (frame != last_update_frame) {
if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
if (session->transport_speed() < 0) {
if (frame > (current_page_frames()/2)) {
center_screen (frame-(current_page_frames()/2));
} else {
center_screen (current_page_frames()/2);
}
} else {
center_screen (frame+(current_page_frames()/2));
}
}
playhead_cursor->set_position (frame);
}
} else {
if (frame != last_update_frame) {
if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
gtk_canvas_item_hide (playhead_cursor->canvas_item);
} else {
playhead_cursor->set_position (frame);
}
}
}
last_update_frame = frame;
if (current_mixer_strip) {
current_mixer_strip->fast_update ();
}
}
}
void
Editor::update_slower ()
{
if (current_mixer_strip) {
current_mixer_strip->update ();
}
}
void
Editor::current_mixer_strip_removed ()
{
if (current_mixer_strip) {
/* it is being deleted */
current_mixer_strip = 0;
}
}
void
Editor::current_mixer_strip_hidden ()
{
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
AudioTimeAxisView* tmp;
if ((tmp = dynamic_cast<AudioTimeAxisView*>(*i)) != 0) {
if (&(tmp->route()) == &(current_mixer_strip->route())) {
(*i)->set_selected (false);
break;
}
}
}
global_hpacker.remove (*current_mixer_strip);
}
void
Editor::session_going_away ()
{
for (vector<SigC::Connection>::iterator i = session_connections.begin(); i != session_connections.end(); ++i) {
(*i).disconnect ();
}
stop_scrolling ();
selection->clear ();
cut_buffer->clear ();
clicked_regionview = 0;
clicked_trackview = 0;
clicked_audio_trackview = 0;
clicked_crossfadeview = 0;
entered_regionview = 0;
entered_track = 0;
latest_regionview = 0;
region_list_display_drag_region = 0;
last_update_frame = 0;
drag_info.item = 0;
last_audition_region = 0;
region_list_button_region = 0;
/* hide all tracks */
hide_all_tracks (false);
/* rip everything out of the list displays */
region_list_clear (); // no clear() method in gtkmm 1.2
route_list.clear ();
named_selection_display.clear ();
edit_group_list.clear ();
edit_cursor_clock.set_session (0);
selection_start_clock.set_session (0);
selection_end_clock.set_session (0);
zoom_range_clock.set_session (0);
nudge_clock.set_session (0);
/* put editor/mixer toggle button in off position and disable until a new session is loaded */
editor_mixer_button.set_active(false);
editor_mixer_button.set_sensitive(false);
/* clear tempo/meter rulers */
remove_metric_marks ();
hide_measures ();
clear_marker_display ();
if (current_bbt_points) {
delete current_bbt_points;
current_bbt_points = 0;
}
if (embed_audio_item) {
embed_audio_item->set_sensitive (false);
}
if (import_audio_item) {
import_audio_item->set_sensitive (false);
}
/* mixer strip will be deleted all by itself
when its route is deleted.
*/
current_mixer_strip = 0;
set_title (_("ardour: editor"));
session = 0;
}

4584
gtk2_ardour/editor_mouse.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include "editor.h"
#include "i18n.h"
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;

3627
gtk2_ardour/editor_ops.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,925 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <pbd/basename.h>
#include <ardour/audioregion.h>
#include <ardour/session_region.h>
#include <gtkmmext/stop_signal.h>
#include "editor.h"
#include "editing.h"
#include "ardour_ui.h"
#include "gui_thread.h"
#include "i18n.h"
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;
using namespace Editing;
#define wave_cursor_width 43
#define wave_cursor_height 61
#define wave_cursor_x_hot 0
#define wave_cursor_y_hot 25
static const gchar wave_cursor_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff,
0x03,
0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x02,
0x02, 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x00, 0x04, 0x00,
0x02,
0x02, 0x04, 0x00, 0x04, 0x00, 0x02, 0x02, 0x0c, 0x08, 0x0c, 0x00,
0x02,
0x02, 0x1c, 0x08, 0x0c, 0x00, 0x02, 0x02, 0x1c, 0x08, 0x0c, 0x04,
0x02,
0x02, 0x3c, 0x18, 0x0c, 0x04, 0x02, 0x02, 0x7c, 0x18, 0x1c, 0x0c,
0x02,
0x82, 0xfc, 0x38, 0x1c, 0x0c, 0x02, 0xc2, 0xfc, 0x78, 0x3c, 0x1c,
0x02,
0xe2, 0xfd, 0xf9, 0x7d, 0x1c, 0x02, 0xf2, 0xff, 0xfb, 0xff, 0x1c,
0x02,
0xfa, 0xff, 0xfb, 0xff, 0x3f, 0x02, 0xfe, 0xff, 0xff, 0xff, 0xff,
0x03,
0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, 0xfa, 0xff, 0xff, 0xff, 0x3f,
0x02,
0xf2, 0xff, 0xfb, 0xfd, 0x3c, 0x02, 0xe2, 0xfd, 0x7b, 0x7c, 0x1c,
0x02,
0xc2, 0xfc, 0x39, 0x3c, 0x1c, 0x02, 0x82, 0xfc, 0x18, 0x1c, 0x1c,
0x02,
0x02, 0xfc, 0x18, 0x1c, 0x0c, 0x02, 0x02, 0x7c, 0x18, 0x0c, 0x0c,
0x02,
0x02, 0x3c, 0x08, 0x0c, 0x04, 0x02, 0x02, 0x1c, 0x08, 0x0c, 0x04,
0x02,
0x02, 0x1c, 0x08, 0x0c, 0x00, 0x02, 0x02, 0x0c, 0x00, 0x04, 0x00,
0x02,
0x02, 0x04, 0x00, 0x04, 0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00,
0x02,
0x02, 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0xff, 0xff, 0xff,
0x03,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00,
0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00,
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#define wave_cursor_mask_width 43
#define wave_cursor_mask_height 61
#define wave_cursor_mask_x_hot 0
#define wave_cursor_mask_y_hot 25
static const gchar wave_cursor_mask_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
0x00,
0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x08, 0x0c, 0x00,
0x00,
0x00, 0x1c, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x0c, 0x04,
0x00,
0x00, 0x3c, 0x18, 0x0c, 0x04, 0x00, 0x00, 0x7c, 0x18, 0x1c, 0x0c,
0x00,
0x80, 0xfc, 0x38, 0x1c, 0x0c, 0x00, 0xc0, 0xfc, 0x78, 0x3c, 0x1c,
0x00,
0xe0, 0xfd, 0xf9, 0x7d, 0x1c, 0x00, 0xf0, 0xff, 0xfb, 0xff, 0x1c,
0x00,
0xf8, 0xff, 0xfb, 0xff, 0x3f, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
0x07,
0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, 0xff, 0xff, 0xff, 0x3f,
0x00,
0xf0, 0xff, 0xfb, 0xfd, 0x3c, 0x00, 0xe0, 0xfd, 0x7b, 0x7c, 0x1c,
0x00,
0xc0, 0xfc, 0x39, 0x3c, 0x1c, 0x00, 0x80, 0xfc, 0x18, 0x1c, 0x1c,
0x00,
0x00, 0xfc, 0x18, 0x1c, 0x0c, 0x00, 0x00, 0x7c, 0x18, 0x0c, 0x0c,
0x00,
0x00, 0x3c, 0x08, 0x0c, 0x04, 0x00, 0x00, 0x1c, 0x08, 0x0c, 0x04,
0x00,
0x00, 0x1c, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00,
0x00,
0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
GdkCursor *wave_cursor = 0;
void
Editor::handle_audio_region_removed (AudioRegion* ignored)
{
redisplay_regions ();
}
void
Editor::handle_new_audio_region (AudioRegion *region)
{
/* don't copy region - the one we are being notified
about belongs to the session, and so it will
never be edited.
*/
add_audio_region_to_region_display (region);
}
void
Editor::region_hidden (Region* r)
{
ENSURE_GUI_THREAD(bind (slot (*this, &Editor::region_hidden), r));
redisplay_regions ();
}
void
Editor::add_audio_region_to_region_display (AudioRegion *region)
{
using namespace Gtk::CTree_Helpers;
vector<const char*> item;
RowList::iterator i;
RowList::iterator tmpi;
string str;
if (!show_automatic_regions_in_region_list && region->automatic()) {
return;
}
if (region->hidden()) {
if (region_list_hidden_node == region_list_display.rows().end()) {
item.clear ();
item.push_back (_("hidden"));
region_list_hidden_node = region_list_display.rows().insert (region_list_display.rows().end(),
Element (item));
(*region_list_hidden_node).set_data (0);
(*region_list_hidden_node).set_leaf (false);
}
item.clear ();
if (region->n_channels() > 1) {
str = compose("%1 [%2]", region->name(), region->n_channels());
item.push_back (str.c_str());
} else {
item.push_back (region->name().c_str());
}
tmpi = region_list_hidden_node->subtree().insert (region_list_hidden_node->subtree().end(),
Element (item));
(*tmpi).set_data (region);
return;
} else if (region->whole_file()) {
item.clear ();
if (region->source().name()[0] == '/') { // external file
if (region->whole_file()) {
str = ".../";
str += PBD::basename_nosuffix (region->source().name());
} else {
str = region->name();
}
} else {
str = region->name();
}
item.push_back (str.c_str());
tmpi = region_list_display.rows().insert (region_list_display.rows().end(),
Element (item));
(*tmpi).set_data (region);
(*tmpi).set_leaf (false);
return;
} else {
/* find parent node, add as new child */
for (i = region_list_display.rows().begin(); i != region_list_display.rows().end(); ++i) {
AudioRegion* r = static_cast<AudioRegion*> ((*i).get_data());
if (r && r->whole_file()) {
if (region->source_equivalent (*r)) {
item.clear ();
if (region->n_channels() > 1) {
str = compose("%1 [%2]", region->name(), region->n_channels());
item.push_back (str.c_str());
} else {
item.push_back (region->name().c_str());
}
tmpi = i->subtree().insert (i->subtree().end(), Element (item));
(*tmpi).set_data (region);
return;
}
}
}
}
item.clear ();
if (region->n_channels() > 1) {
str = compose("%1 [%2]", region->name(), region->n_channels());
item.push_back (str.c_str());
} else {
item.push_back (region->name().c_str());
}
tmpi = region_list_display.rows().insert (region_list_display.rows().end(), Element (item));
(*tmpi).set_data (region);
(*tmpi).set_leaf (true);
}
void
Editor::insert_into_tmp_audio_regionlist(AudioRegion* region)
{
/* keep all whole files at the beginning */
if (region->whole_file()) {
tmp_audio_region_list.push_front (region);
} else {
tmp_audio_region_list.push_back (region);
}
}
void
Editor::redisplay_regions ()
{
if (session) {
region_list_display.freeze ();
region_list_clear ();
region_list_hidden_node = region_list_display.rows().end();
/* now add everything we have, via a temporary list used to help with
sorting.
*/
tmp_audio_region_list.clear();
session->foreach_audio_region (this, &Editor::insert_into_tmp_audio_regionlist);
for (list<AudioRegion*>::iterator r = tmp_audio_region_list.begin(); r != tmp_audio_region_list.end(); ++r) {
add_audio_region_to_region_display (*r);
}
region_list_display.sort ();
region_list_display.thaw ();
}
}
void
Editor::region_list_clear ()
{
/* ---------------------------------------- */
/* XXX MAKE ME A FUNCTION (no CTree::clear() in gtkmm 1.2) */
gtk_ctree_remove_node (region_list_display.gtkobj(), NULL);
/* ---------------------------------------- */
}
void
Editor::region_list_column_click (gint col)
{
bool sensitive;
if (region_list_menu == 0) {
build_region_list_menu ();
}
if (region_list_display.selection().size() != 0) {
sensitive = true;
} else {
sensitive = false;
}
for (vector<MenuItem*>::iterator i = rl_context_menu_region_items.begin(); i != rl_context_menu_region_items.end(); ++i) {
(*i)->set_sensitive (sensitive);
}
region_list_menu->popup (0, 0);
}
void
Editor::build_region_list_menu ()
{
using namespace Gtk::Menu_Helpers;
region_list_menu = new Menu;
MenuList& items = region_list_menu->items();
region_list_menu->set_name ("ArdourContextMenu");
items.push_back (MenuElem (_("Audition"), slot (*this, &Editor::audition_region_from_region_list)));
rl_context_menu_region_items.push_back (items.back());
items.push_back (MenuElem (_("Hide"), slot (*this, &Editor::hide_region_from_region_list)));
rl_context_menu_region_items.push_back (items.back());
items.push_back (MenuElem (_("Remove"), slot (*this, &Editor::remove_region_from_region_list)));
rl_context_menu_region_items.push_back (items.back());
items.push_back (SeparatorElem());
// items.push_back (MenuElem (_("Find")));
items.push_back (CheckMenuElem (_("Show all"), slot (*this, &Editor::toggle_full_region_list)));
toggle_full_region_list_item = static_cast<CheckMenuItem*> (items.back());
Gtk::Menu *sort_menu = manage (new Menu);
MenuList& sort_items = sort_menu->items();
sort_menu->set_name ("ArdourContextMenu");
RadioMenuItem::Group sort_order_group;
RadioMenuItem::Group sort_type_group;
sort_items.push_back (RadioMenuElem (sort_order_group, _("Ascending"),
bind (slot (*this, &Editor::reset_region_list_sort_direction), true)));
sort_items.push_back (RadioMenuElem (sort_order_group, _("Descending"),
bind (slot (*this, &Editor::reset_region_list_sort_direction), false)));
sort_items.push_back (SeparatorElem());
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Region Name"),
bind (slot (*this, &Editor::reset_region_list_sort_type), ByName)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Region Length"),
bind (slot (*this, &Editor::reset_region_list_sort_type), ByLength)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Region Position"),
bind (slot (*this, &Editor::reset_region_list_sort_type), ByPosition)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Region Timestamp"),
bind (slot (*this, &Editor::reset_region_list_sort_type), ByTimestamp)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Region Start in File"),
bind (slot (*this, &Editor::reset_region_list_sort_type), ByStartInFile)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Region End in File"),
bind (slot (*this, &Editor::reset_region_list_sort_type), ByEndInFile)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Source File Name"),
bind (slot (*this, &Editor::reset_region_list_sort_type), BySourceFileName)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Source File Length"),
bind (slot (*this, &Editor::reset_region_list_sort_type), BySourceFileLength)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Source File Creation Date"),
bind (slot (*this, &Editor::reset_region_list_sort_type), BySourceFileCreationDate)));
sort_items.push_back (RadioMenuElem (sort_type_group, _("By Source Filesystem"),
bind (slot (*this, &Editor::reset_region_list_sort_type), BySourceFileFS)));
items.push_back (MenuElem (_("Sorting"), *sort_menu));
items.push_back (SeparatorElem());
// items.push_back (CheckMenuElem (_("Display Automatic Regions"), slot (*this, &Editor::toggle_show_auto_regions)));
// toggle_auto_regions_item = static_cast<CheckMenuItem*> (items.back());
// toggle_auto_regions_item->set_active (show_automatic_regions_in_region_list);
// items.push_back (SeparatorElem());
items.push_back (MenuElem (_("Import audio (copy)"), bind (slot (*this, &Editor::import_audio), false)));
import_audio_item = items.back();
if (!session) {
import_audio_item->set_sensitive (false);
}
items.push_back (MenuElem (_("Embed audio (link)"), slot (*this, &Editor::embed_audio)));
embed_audio_item = items.back();
if (!session) {
embed_audio_item->set_sensitive (false);
}
}
void
Editor::toggle_show_auto_regions ()
{
//show_automatic_regions_in_region_list = toggle_auto_regions_item->get_active();
show_automatic_regions_in_region_list = true;
redisplay_regions ();
}
void
Editor::toggle_full_region_list ()
{
region_list_display.freeze ();
if (toggle_full_region_list_item->get_active()) {
for (CTree_Helpers::RowIterator r = region_list_display.rows().begin(); r != region_list_display.rows().end(); ++r) {
r->expand_recursive ();
}
} else {
for (CTree_Helpers::RowIterator r = region_list_display.rows().begin(); r != region_list_display.rows().end(); ++r) {
r->collapse ();
}
}
region_list_display.thaw ();
}
gint
Editor::region_list_display_key_press (GdkEventKey* ev)
{
return FALSE;
}
gint
Editor::region_list_display_key_release (GdkEventKey* ev)
{
switch (ev->keyval) {
case GDK_Delete:
remove_selected_regions_from_region_list ();
return TRUE;
break;
default:
break;
}
return FALSE;
}
gint
Editor::region_list_display_button_press (GdkEventButton *ev)
{
int row, col;
AudioRegion *region;
if (Keyboard::is_delete_event (ev)) {
if (region_list_display.get_selection_info ((int)ev->x, (int)ev->y, &row, &col) != 0) {
if ((region = (AudioRegion *) region_list_display.row(row).get_data()) != 0) {
delete region;
}
}
return TRUE;
}
if (Keyboard::is_context_menu_event (ev)) {
region_list_column_click (-1);
return TRUE;
}
switch (ev->button) {
case 1:
if (region_list_display.get_selection_info ((int)ev->x, (int)ev->y, &row, &col) != 0) {
if ((region = (AudioRegion *) region_list_display.row(row).get_data()) != 0) {
if (wave_cursor == 0) {
GdkPixmap *source, *mask;
GdkColor fg = { 0, 65535, 0, 0 }; /* Red. */
GdkColor bg = { 0, 0, 0, 65535 }; /* Blue. */
source = gdk_bitmap_create_from_data (NULL, wave_cursor_bits,
wave_cursor_width, wave_cursor_height);
mask = gdk_bitmap_create_from_data (NULL, wave_cursor_mask_bits,
wave_cursor_mask_width, wave_cursor_mask_height);
wave_cursor = gdk_cursor_new_from_pixmap (source,
mask,
&fg,
&bg,
wave_cursor_x_hot,
wave_cursor_y_hot);
gdk_pixmap_unref (source);
gdk_pixmap_unref (mask);
}
region_list_display_drag_region = region;
need_wave_cursor = 1;
/* audition on double click */
if (ev->type == GDK_2BUTTON_PRESS) {
consider_auditioning (region);
}
return TRUE;
}
}
break;
case 2:
if (!Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
if (region_list_display.get_selection_info ((int)ev->x, (int)ev->y, &row, &col) != 0) {
if ((region = (AudioRegion *) region_list_display.get_row_data (row)) != 0) {
if (consider_auditioning (region)) {
region_list_display.row(row).select();
}
else {
region_list_display.row(row).unselect();
}
return TRUE;
}
}
}
/* to prevent regular selection -- i dont think this is needed JLC */
return stop_signal (region_list_display, "button_press_event");
break;
case 3:
break;
default:
break;
}
return FALSE;
}
gint
Editor::region_list_display_button_release (GdkEventButton *ev)
{
int row, col;
if (region_list_display.get_selection_info ((int)ev->x, (int)ev->y, &row, &col) != 0) {
region_list_button_region = (AudioRegion *) region_list_display.get_row_data (row);
} else {
region_list_button_region = 0;
}
if (Keyboard::is_delete_event (ev)) {
remove_region_from_region_list ();
return TRUE;
}
switch (ev->button) {
case 1:
if (region_list_display_drag_region) {
insert_region_list_drag (*region_list_display_drag_region);
}
track_canvas_scroller.get_window().set_cursor (current_canvas_cursor);
region_list_display.get_window().set_cursor (0);
region_list_display_drag_region = 0;
need_wave_cursor = 0;
return TRUE;
break;
case 3:
if (!Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
if (region_list_menu == 0) {
build_region_list_menu ();
}
bool sensitive;
if (region_list_display.selection().size() != 0) {
sensitive = true;
} else {
sensitive = false;
}
for (vector<MenuItem*>::iterator i = rl_context_menu_region_items.begin(); i != rl_context_menu_region_items.end(); ++i) {
(*i)->set_sensitive (sensitive);
}
region_list_menu->popup (0, 0);
}
return TRUE;
break;
default:
break;
}
return FALSE;
}
gint
Editor::region_list_display_motion (GdkEventMotion *ev)
{
if (need_wave_cursor == 1) {
track_canvas_scroller.get_window().set_cursor (wave_cursor);
region_list_display.get_window().set_cursor (wave_cursor);
gdk_flush ();
need_wave_cursor = 2;
}
return FALSE;
}
void
Editor::region_list_display_selected (gint row, gint col, GdkEvent *ev)
{
AudioRegion* region = static_cast<AudioRegion *>(region_list_display.get_row_data (row));
if (session == 0 || region == 0) {
return;
}
set_selected_regionview_from_region_list (*region, false);
}
void
Editor::region_list_display_unselected (gint row, gint col, GdkEvent *ev)
{
}
bool
Editor::consider_auditioning (AudioRegion *r)
{
if (r == 0) {
session->cancel_audition ();
return false;
}
if (session->is_auditioning()) {
session->cancel_audition ();
if (r == last_audition_region) {
return false;
}
}
session->audition_region (*r);
last_audition_region = r;
return true;
}
gint
Editor::region_list_display_enter_notify (GdkEventCrossing *ev)
{
ARDOUR_UI::instance()->allow_focus (true);
region_list_display.grab_focus ();
return FALSE;
}
gint
Editor::region_list_display_leave_notify (GdkEventCrossing *ev)
{
ARDOUR_UI::instance()->allow_focus (false);
return FALSE;
}
gint
Editor::_region_list_sorter (GtkCList* clist, gconstpointer a, gconstpointer b)
{
Editor* editor = static_cast<Editor*> (gtk_object_get_data (GTK_OBJECT(clist), "editor"));
return editor->region_list_sorter (a, b);
}
gint
Editor::region_list_sorter (gconstpointer a, gconstpointer b)
{
GtkCListRow* row1 = (GtkCListRow *) a;
GtkCListRow* row2 = (GtkCListRow *) b;
AudioRegion* region1 = static_cast<AudioRegion*> (row1->data);
AudioRegion* region2 = static_cast<AudioRegion*> (row2->data);
if (region1 == 0 || region2 == 0) {
switch (region_list_sort_type) {
case ByName:
return true; /* XXX compare text in rows */
default:
return true;
}
}
switch (region_list_sort_type) {
case ByName:
return strcasecmp (region1->name().c_str(), region2->name().c_str());
break;
case ByLength:
return region1->length() - region2->length();
break;
case ByPosition:
return region1->position() - region2->position();
break;
case ByTimestamp:
return region1->source().timestamp() - region2->source().timestamp();
break;
case ByStartInFile:
return region1->start() - region2->start();
break;
case ByEndInFile:
return (region1->start() + region1->length()) - (region2->start() + region2->length());
break;
case BySourceFileName:
return strcasecmp (region1->source().name().c_str(), region2->source().name().c_str());
break;
case BySourceFileLength:
return region1->source().length() - region2->source().length();
break;
case BySourceFileCreationDate:
return region1->source().timestamp() - region2->source().timestamp();
break;
case BySourceFileFS:
if (region1->source().name() == region2->source().name()) {
return strcasecmp (region1->name().c_str(), region2->name().c_str());
} else {
return strcasecmp (region1->source().name().c_str(), region2->source().name().c_str());
}
break;
}
return FALSE;
}
void
Editor::reset_region_list_sort_type (RegionListSortType type)
{
if (type != region_list_sort_type) {
region_list_sort_type = type;
switch (type) {
case ByName:
region_list_display.set_column_title(0, _("Regions/name"));
break;
case ByLength:
region_list_display.set_column_title (0, _("Regions/length"));
break;
case ByPosition:
region_list_display.set_column_title (0, _("Regions/position"));
break;
case ByTimestamp:
region_list_display.set_column_title (0, _("Regions/creation"));
break;
case ByStartInFile:
region_list_display.set_column_title (0, _("Regions/start"));
break;
case ByEndInFile:
region_list_display.set_column_title (0, _("Regions/end"));
break;
case BySourceFileName:
region_list_display.set_column_title (0, _("Regions/file name"));
break;
case BySourceFileLength:
region_list_display.set_column_title (0, _("Regions/file size"));
break;
case BySourceFileCreationDate:
region_list_display.set_column_title (0, _("Regions/file date"));
break;
case BySourceFileFS:
region_list_display.set_column_title (0, _("Regions/file system"));
break;
}
region_list_display.sort ();
}
}
void
Editor::reset_region_list_sort_direction (bool up)
{
region_list_display.set_sort_type (up ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING);
region_list_display.sort ();
}
void
Editor::audition_region_from_region_list ()
{
if (region_list_button_region) {
consider_auditioning (dynamic_cast<AudioRegion*> (region_list_button_region));
}
}
void
Editor::hide_region_from_region_list ()
{
if (session == 0 || region_list_button_region == 0) {
return;
}
region_list_button_region->set_hidden (true);
}
void
Editor::remove_region_from_region_list ()
{
if (session == 0 || region_list_button_region == 0) {
return;
}
session->remove_region_from_region_list (*region_list_button_region);
}
void
Editor::remove_selected_regions_from_region_list ()
{
using namespace Gtk::CTree_Helpers;
SelectionList& selected = region_list_display.selection();
/* called from idle context to avoid snafus with the list
state.
*/
if (selected.empty() || session == 0) {
return;
}
vector<Region*> to_be_deleted;
for (SelectionList::iterator i = selected.begin(); i != selected.end(); ++i) {
to_be_deleted.push_back (static_cast<Region*> ((*i).get_data()));
}
for (vector<Region*>::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
session->remove_region_from_region_list (**i);
}
return;
}
void
Editor::region_list_display_drag_data_received (GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *data,
guint info,
guint time)
{
vector<string> paths;
if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) {
do_embed_sndfiles (paths, false);
}
gtk_drag_finish (context, TRUE, FALSE, time);
}

View File

@@ -0,0 +1,444 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include "editor.h"
#include "ardour_ui.h"
#include "audio_time_axis.h"
#include "mixer_strip.h"
#include "gui_thread.h"
#include <ardour/route.h>
#include "i18n.h"
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;
void
Editor::handle_new_route_p (Route* route)
{
ENSURE_GUI_THREAD(bind (slot (*this, &Editor::handle_new_route_p), route));
handle_new_route (*route);
}
void
Editor::handle_new_route (Route& route)
{
TimeAxisView *tv;
AudioTimeAxisView *atv;
const gchar *rowdata[1];
if (route.hidden()) {
return;
}
tv = new AudioTimeAxisView (*this, *session, route, track_canvas);
track_views.push_back (tv);
rowdata[0] = route.name ().c_str();
ignore_route_list_reorder = true;
route_list.rows().push_back (rowdata);
route_list.rows().back().set_data (tv);
if (tv->marked_for_display()) {
route_list.rows().back().select();
}
if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
/* added a new fresh one at the end */
if (atv->route().order_key(N_("editor")) == -1) {
atv->route().set_order_key (N_("editor"), route_list.rows().size()-1);
}
}
ignore_route_list_reorder = false;
route.gui_changed.connect (slot (*this, &Editor::handle_gui_changes));
tv->GoingAway.connect (bind (slot (*this, &Editor::remove_route), tv));
editor_mixer_button.set_sensitive(true);
}
void
Editor::handle_gui_changes (string what, void *src)
{
ENSURE_GUI_THREAD(bind (slot (*this, &Editor::handle_gui_changes), what, src));
if (what == "track_height") {
route_list_reordered ();
}
}
void
Editor::remove_route (TimeAxisView *tv)
{
ENSURE_GUI_THREAD(bind (slot (*this, &Editor::remove_route), tv));
TrackViewList::iterator i;
CList_Helpers::RowList::iterator ri;
if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
track_views.erase (i);
}
for (ri = route_list.rows().begin(); ri != route_list.rows().end(); ++ri) {
if (tv == ri->get_data()) {
route_list.rows().erase (ri);
break;
}
}
/* since the editor mixer goes away when you remove a route, set the
* button to inacttive
*/
editor_mixer_button.set_active(false);
/* and disable if all tracks and/or routes are gone */
if (track_views.size() == 0) {
editor_mixer_button.set_sensitive(false);
}
}
void
Editor::route_name_changed (TimeAxisView *tv)
{
CList_Helpers::RowList::iterator i;
gint row;
for (row = 0, i = route_list.rows().begin(); i != route_list.rows().end(); ++i, ++row) {
if (tv == i->get_data()) {
route_list.cell (row, 0).set_text (tv->name());
break;
}
}
}
void
Editor::route_list_selected (gint row, gint col, GdkEvent *ev)
{
TimeAxisView *tv;
if ((tv = (TimeAxisView *) route_list.get_row_data (row)) != 0) {
tv->set_marked_for_display (true);
route_list_reordered ();
}
}
void
Editor::route_list_unselected (gint row, gint col, GdkEvent *ev)
{
TimeAxisView *tv;
AudioTimeAxisView *atv;
if ((tv = (TimeAxisView *) route_list.get_row_data (row)) != 0) {
tv->set_marked_for_display (false);
if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
if (current_mixer_strip && &(atv->route()) == &(current_mixer_strip->route())) {
/* this will hide the mixer strip */
set_selected_mixer_strip(*atv);
}
}
route_list_reordered ();
}
}
void
Editor::unselect_strip_in_display (TimeAxisView& tv)
{
CList_Helpers::RowIterator i;
if ((i = route_list.rows().find_data (&tv)) != route_list.rows().end()) {
(*i).unselect ();
}
}
void
Editor::select_strip_in_display (TimeAxisView& tv)
{
CList_Helpers::RowIterator i;
if ((i = route_list.rows().find_data (&tv)) != route_list.rows().end()) {
(*i).select ();
}
}
void
Editor::queue_route_list_reordered (gint arg1, gint arg2)
{
/* the problem here is that we are called *before* the
list has been reordered. so just queue up
the actual re-drawer to happen once the re-ordering
is complete.
*/
Main::idle.connect (slot (*this, &Editor::route_list_reordered));
}
void
Editor::redisplay_route_list ()
{
route_list_reordered ();
}
gint
Editor::route_list_reordered ()
{
CList_Helpers::RowList::iterator i;
gdouble y;
int n;
for (n = 0, y = 0, i = route_list.rows().begin(); i != route_list.rows().end(); ++i) {
TimeAxisView *tv = (TimeAxisView *) (*i)->get_data ();
AudioTimeAxisView* at;
if (!ignore_route_list_reorder) {
/* this reorder is caused by user action, so reassign sort order keys
to tracks.
*/
if ((at = dynamic_cast<AudioTimeAxisView*> (tv)) != 0) {
at->route().set_order_key (N_("editor"), n);
}
}
if (tv->marked_for_display()) {
y += tv->show_at (y, n, &edit_controls_vbox);
y += track_spacing;
} else {
tv->hide ();
}
n++;
}
edit_controls_scroller.queue_resize ();
reset_scrolling_region ();
//gtk_canvas_item_raise_to_top (time_line_group);
gtk_canvas_item_raise_to_top (cursor_group);
return FALSE;
}
void
Editor::hide_all_tracks (bool with_select)
{
Gtk::CList_Helpers::RowList::iterator i;
Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
route_list.freeze ();
for (i = rowlist.begin(); i != rowlist.end(); ++i) {
TimeAxisView *tv = (TimeAxisView *) i->get_data ();
if (with_select) {
i->unselect ();
} else {
tv->set_marked_for_display (false);
tv->hide();
}
}
route_list.thaw ();
reset_scrolling_region ();
}
void
Editor::route_list_column_click (gint col)
{
if (route_list_menu == 0) {
build_route_list_menu ();
}
route_list_menu->popup (0, 0);
}
void
Editor::build_route_list_menu ()
{
using namespace Gtk::Menu_Helpers;
route_list_menu = new Menu;
MenuList& items = route_list_menu->items();
route_list_menu->set_name ("ArdourContextMenu");
items.push_back (MenuElem (_("Show All"), slot (*this, &Editor::select_all_routes)));
items.push_back (MenuElem (_("Hide All"), slot (*this, &Editor::unselect_all_routes)));
items.push_back (MenuElem (_("Show All AbstractTracks"), slot (*this, &Editor::select_all_audiotracks)));
items.push_back (MenuElem (_("Hide All AbstractTracks"), slot (*this, &Editor::unselect_all_audiotracks)));
items.push_back (MenuElem (_("Show All AudioBus"), slot (*this, &Editor::select_all_audiobus)));
items.push_back (MenuElem (_("Hide All AudioBus"), slot (*this, &Editor::unselect_all_audiobus)));
}
void
Editor::unselect_all_routes ()
{
hide_all_tracks (true);
}
void
Editor::select_all_routes ()
{
CList_Helpers::RowList::iterator i;
for (i = route_list.rows().begin(); i != route_list.rows().end(); ++i) {
i->select ();
}
}
void
Editor::select_all_audiotracks ()
{
Gtk::CList_Helpers::RowList::iterator i;
Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
route_list.freeze ();
for (i = rowlist.begin(); i != rowlist.end(); ++i) {
TimeAxisView *tv = (TimeAxisView *) i->get_data ();
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
if (atv->is_audio_track()) {
i->select ();
}
}
}
route_list.thaw ();
}
void
Editor::unselect_all_audiotracks ()
{
Gtk::CList_Helpers::RowList::iterator i;
Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
route_list.freeze ();
for (i = rowlist.begin(); i != rowlist.end(); ++i) {
TimeAxisView *tv = (TimeAxisView *) i->get_data ();
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
if (atv->is_audio_track()) {
i->unselect ();
}
}
}
route_list.thaw ();
}
void
Editor::select_all_audiobus ()
{
Gtk::CList_Helpers::RowList::iterator i;
Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
route_list.freeze ();
for (i = rowlist.begin(); i != rowlist.end(); ++i) {
TimeAxisView *tv = (TimeAxisView *) i->get_data ();
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
if (!atv->is_audio_track()) {
i->select ();
}
}
}
route_list.thaw ();
}
void
Editor::unselect_all_audiobus ()
{
Gtk::CList_Helpers::RowList::iterator i;
Gtk::CList_Helpers::RowList& rowlist = route_list.rows();
route_list.freeze ();
for (i = rowlist.begin(); i != rowlist.end(); ++i) {
TimeAxisView *tv = (TimeAxisView *) i->get_data ();
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
if (!atv->is_audio_track()) {
i->unselect ();
}
}
}
route_list.thaw ();
}
gint
route_list_compare_func (GtkCList* clist, gconstpointer a, gconstpointer b)
{
TimeAxisView *tv1;
TimeAxisView *tv2;
AudioTimeAxisView *atv1;
AudioTimeAxisView *atv2;
Route* ra;
Route* rb;
GtkCListRow *row1 = (GtkCListRow *) a;
GtkCListRow *row2 = (GtkCListRow *) b;
tv1 = static_cast<TimeAxisView*> (row1->data);
tv2 = static_cast<TimeAxisView*> (row2->data);
if ((atv1 = dynamic_cast<AudioTimeAxisView*>(tv1)) == 0 ||
(atv2 = dynamic_cast<AudioTimeAxisView*>(tv2)) == 0) {
return FALSE;
}
ra = &atv1->route();
rb = &atv2->route();
/* use of ">" forces the correct sort order */
return ra->order_key ("editor") > rb->order_key ("editor");
}

1602
gtk2_ardour/editor_rulers.cc Normal file

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1,185 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include <vector>
#include <gtk--.h>
#include <ardour/named_selection.h>
#include <ardour/session_selection.h>
#include <ardour/playlist.h>
#include <gtkmmext/stop_signal.h>
#include "editor.h"
#include "selection.h"
#include "time_axis_view.h"
#include "ardour_ui.h"
#include "prompter.h"
#include "i18n.h"
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;
using namespace Gtkmmext;
void
Editor::handle_new_named_selection ()
{
ARDOUR_UI::instance()->call_slot (slot (*this, &Editor::redisplay_named_selections));
}
void
Editor::add_named_selection_to_named_selection_display (NamedSelection& selection)
{
const gchar *row[1];
row[0] = selection.name.c_str();
named_selection_display.rows().push_back (row);
named_selection_display.rows().back().set_data (&selection);
}
void
Editor::redisplay_named_selections ()
{
named_selection_display.freeze ();
named_selection_display.clear ();
session->foreach_named_selection (*this, &Editor::add_named_selection_to_named_selection_display);
named_selection_display.thaw ();
}
gint
Editor::named_selection_display_button_press (GdkEventButton *ev)
{
NamedSelection* named_selection;
gint row;
gint col;
switch (ev->button) {
case 1:
if (Keyboard::is_delete_event (ev)) {
if (named_selection_display.get_selection_info ((int)ev->x, (int)ev->y, &row, &col) != 0) {
if ((named_selection = reinterpret_cast<NamedSelection *> (named_selection_display.get_row_data (row))) != 0) {
session->remove_named_selection (named_selection);
return stop_signal (named_selection_display, "button_press_event");
}
}
}
break;
case 2:
break;
case 3:
break;
default:
break;
}
return FALSE;
}
void
Editor::named_selection_display_selected (gint row, gint col, GdkEvent *ev)
{
}
void
Editor::named_selection_display_unselected (gint row, gint col, GdkEvent *ev)
{
}
void
Editor::name_selection ()
{
ArdourPrompter p;
p.set_prompt (_("name for chunk:"));
p.done.connect (slot (*this, &Editor::named_selection_name_chosen));
p.change_labels (_("Create chunk"), _("Forget it"));
p.show_all ();
Gtk::Main::run ();
if (p.status == Prompter::entered) {
string name;
p.get_result (name);
if (name.length()){
create_named_selection (name);
}
}
}
void
Editor::named_selection_name_chosen ()
{
Gtk::Main::quit ();
}
void
Editor::create_named_selection (string name)
{
if (session == 0) {
return;
}
/* check for a range-based selection */
if (selection->time.empty()) {
return;
}
TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
if (views->empty()) {
delete views;
return;
}
Playlist* what_we_found;
list<Playlist*> thelist;
for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
Playlist *pl = (*i)->playlist();
if (pl) {
if ((what_we_found = pl->copy (selection->time, false)) != 0) {
thelist.push_back (what_we_found);
}
}
}
NamedSelection* ns;
ns = new NamedSelection (name, thelist);
/* make the one we just added be selected */
named_selection_display.rows().back().select ();
}

View File

@@ -0,0 +1,493 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdio> // for sprintf, grrr
#include <cstdlib>
#include <cmath>
#include <string>
#include <climits>
#include <gtk-canvas.h>
#include <pbd/error.h>
#include <gtkmmext/utils.h>
#include <gtkmmext/gtk_ui.h>
#include <ardour/session.h>
#include <ardour/tempo.h>
#include <gtkmmext/doi.h>
#include "editor.h"
#include "marker.h"
#include "canvas-simpleline.h"
#include "tempo_dialog.h"
#include "rgb_macros.h"
#include "gui_thread.h"
#include "i18n.h"
using namespace std;
using namespace SigC;
using namespace ARDOUR;
using namespace Gtk;
using namespace Editing;
void
Editor::remove_metric_marks ()
{
/* don't delete these while handling events, just punt till the GUI is idle */
for (Marks::iterator x = metric_marks.begin(); x != metric_marks.end(); ++x) {
delete_when_idle (*x);
}
metric_marks.clear ();
}
void
Editor::draw_metric_marks (const Metrics& metrics)
{
for (Metrics::const_iterator i = metrics.begin(); i != metrics.end(); ++i) {
const MeterSection *ms;
const TempoSection *ts;
char buf[64];
if ((ms = dynamic_cast<const MeterSection*>(*i)) != 0) {
snprintf (buf, sizeof(buf), "%g/%g", ms->beats_per_bar(), ms->note_divisor ());
metric_marks.push_back (new MeterMarker (*this, GTK_CANVAS_GROUP(meter_group), color_map[cMeterMarker], buf,
*(const_cast<MeterSection*>(ms)), PublicEditor::canvas_meter_marker_event));
} else if ((ts = dynamic_cast<const TempoSection*>(*i)) != 0) {
snprintf (buf, sizeof (buf), "%.2f", ts->beats_per_minute());
metric_marks.push_back (new TempoMarker (*this, GTK_CANVAS_GROUP(tempo_group), color_map[cTempoMarker], buf,
*(const_cast<TempoSection*>(ts)), PublicEditor::canvas_tempo_marker_event));
}
}
}
void
Editor::tempo_map_changed (Change ignored)
{
ENSURE_GUI_THREAD(bind (slot (*this, &Editor::tempo_map_changed), ignored));
if (current_bbt_points) {
delete current_bbt_points;
current_bbt_points = 0;
}
if (session) {
current_bbt_points = session->tempo_map().get_points (leftmost_frame, leftmost_frame + current_page_frames());
} else {
current_bbt_points = 0;
}
redisplay_tempo ();
}
void
Editor::redisplay_tempo ()
{
update_tempo_based_rulers ();
remove_metric_marks ();
hide_measures ();
if (session && current_bbt_points) {
session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
draw_measures ();
}
}
void
Editor::hide_measures ()
{
for (TimeLineList::iterator i = used_measure_lines.begin(); i != used_measure_lines.end(); ++i) {
gtk_canvas_item_hide (*i);
free_measure_lines.push_back (*i);
}
used_measure_lines.clear ();
}
GtkCanvasItem *
Editor::get_time_line ()
{
GtkCanvasItem *line;
if (free_measure_lines.empty()) {
line = gtk_canvas_item_new (GTK_CANVAS_GROUP(time_line_group),
gtk_canvas_simpleline_get_type(),
NULL);
// cerr << "measure line @ " << line << endl;
used_measure_lines.push_back (line);
} else {
line = free_measure_lines.front();
free_measure_lines.erase (free_measure_lines.begin());
used_measure_lines.push_back (line);
}
return line;
}
void
Editor::draw_measures ()
{
if (session == 0 || _show_measures == false) {
return;
}
TempoMap::BBTPointList::iterator i;
TempoMap::BBTPointList *all_bbt_points;
GtkCanvasItem *line;
gdouble xpos, last_xpos;
uint32_t cnt;
uint32_t color;
if (current_bbt_points == 0 || current_bbt_points->empty()) {
return;
}
all_bbt_points = session->tempo_map().get_points (leftmost_frame, leftmost_frame + current_page_frames());
cnt = 0;
last_xpos = 0;
/* get the first bar spacing */
gdouble last_beat = DBL_MAX;
gdouble beat_spacing = 0;
for (i = all_bbt_points->begin(); i != all_bbt_points->end() && beat_spacing == 0; ++i) {
TempoMap::BBTPoint& p = (*i);
switch (p.type) {
case TempoMap::Bar:
break;
case TempoMap::Beat:
xpos = p.frame / (gdouble) frames_per_unit;
if (last_beat < xpos) {
beat_spacing = xpos - last_beat;
}
last_beat = xpos;
}
}
for (i = all_bbt_points->begin(); i != all_bbt_points->end(); ++i) {
TempoMap::BBTPoint& p = (*i);
switch (p.type) {
case TempoMap::Bar:
break;
case TempoMap::Beat:
xpos = p.frame / (gdouble) frames_per_unit;
if (p.beat == 1) {
color = color_map[cMeasureLineBeat];
} else {
color = color_map[cMeasureLineBar];
/* only draw beat lines if the gaps between beats
are large.
*/
if (beat_spacing < 25.0) {
break;
}
}
if (cnt == 0 || xpos - last_xpos > 4.0) {
line = get_time_line ();
gtk_object_set (GTK_OBJECT(line),
"x1", xpos,
"x2", xpos,
"y2", (gdouble) canvas_height,
"color_rgba", color,
NULL);
gtk_canvas_item_raise_to_top (line);
gtk_canvas_item_show (line);
last_xpos = xpos;
++cnt;
}
break;
}
}
delete all_bbt_points;
/* the cursors are always on top of everything */
gtk_canvas_item_raise_to_top (cursor_group);
gtk_canvas_item_lower_to_bottom (time_line_group);
}
void
Editor::mouse_add_new_tempo_event (jack_nframes_t frame)
{
if (session == 0) {
return;
}
TempoMap& map(session->tempo_map());
TempoDialog tempo_dialog (map, frame, _("add"));
tempo_dialog.bpm_entry.activate.connect (bind (slot (tempo_dialog, &ArdourDialog::stop), 0));
tempo_dialog.ok_button.clicked.connect (bind (slot (tempo_dialog, &ArdourDialog::stop), 0));
tempo_dialog.cancel_button.clicked.connect (bind (slot (tempo_dialog, &ArdourDialog::stop), -1));
tempo_dialog.set_position (GTK_WIN_POS_MOUSE);
tempo_dialog.realize ();
tempo_dialog.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
ensure_float (tempo_dialog);
tempo_dialog.run();
if (tempo_dialog.run_status() == 0) {
double bpm = 0;
BBT_Time requested;
bpm = tempo_dialog.get_bpm ();
bpm = max (0.01, bpm);
tempo_dialog.get_bbt_time (requested);
begin_reversible_command (_("add tempo mark"));
session->add_undo (map.get_memento());
map.add_tempo (Tempo (bpm), requested);
session->add_redo_no_execute (map.get_memento());
commit_reversible_command ();
map.dump (cerr);
}
}
void
Editor::mouse_add_new_meter_event (jack_nframes_t frame)
{
if (session == 0) {
return;
}
TempoMap& map(session->tempo_map());
MeterDialog meter_dialog (map, frame, _("add"));
meter_dialog.ok_button.clicked.connect (bind (slot (meter_dialog, &ArdourDialog::stop), 0));
meter_dialog.cancel_button.clicked.connect (bind (slot (meter_dialog, &ArdourDialog::stop), -1));
meter_dialog.set_position (GTK_WIN_POS_MOUSE);
meter_dialog.realize ();
meter_dialog.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
ensure_float (meter_dialog);
meter_dialog.run ();
if (meter_dialog.run_status() == 0) {
double bpb = meter_dialog.get_bpb ();
bpb = max (1.0, bpb); // XXX is this a reasonable limit?
double note_type = meter_dialog.get_note_type ();
BBT_Time requested;
meter_dialog.get_bbt_time (requested);
begin_reversible_command (_("add meter mark"));
session->add_undo (map.get_memento());
map.add_meter (Meter (bpb, note_type), requested);
session->add_redo_no_execute (map.get_memento());
commit_reversible_command ();
map.dump (cerr);
}
}
void
Editor::remove_tempo_marker (GtkCanvasItem* item)
{
Marker* marker;
TempoMarker* tempo_marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
if ((tempo_marker = dynamic_cast<TempoMarker*> (marker)) == 0) {
fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
/*NOTREACHED*/
}
if (tempo_marker->tempo().movable()) {
Gtk::Main::idle.connect (bind (slot (*this, &Editor::real_remove_tempo_marker), &tempo_marker->tempo()));
}
}
void
Editor::edit_meter_section (MeterSection* section)
{
MeterDialog meter_dialog (*section, _("done"));
meter_dialog.ok_button.clicked.connect (bind (slot (meter_dialog, &ArdourDialog::stop), 0));
meter_dialog.cancel_button.clicked.connect (bind (slot (meter_dialog, &ArdourDialog::stop), -1));
meter_dialog.set_position (GTK_WIN_POS_MOUSE);
meter_dialog.realize ();
meter_dialog.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
ensure_float (meter_dialog);
meter_dialog.run ();
if (meter_dialog.run_status() == 0) {
double bpb = meter_dialog.get_bpb ();
bpb = max (1.0, bpb); // XXX is this a reasonable limit?
double note_type = meter_dialog.get_note_type ();
begin_reversible_command (_("replace tempo mark"));
session->add_undo (session->tempo_map().get_memento());
session->tempo_map().replace_meter (*section, Meter (bpb, note_type));
session->add_redo_no_execute (session->tempo_map().get_memento());
commit_reversible_command ();
}
}
void
Editor::edit_tempo_section (TempoSection* section)
{
TempoDialog tempo_dialog (*section, _("done"));
tempo_dialog.bpm_entry.activate.connect (bind (slot (tempo_dialog, &ArdourDialog::stop), 0));
tempo_dialog.ok_button.clicked.connect (bind (slot (tempo_dialog, &ArdourDialog::stop), 0));
tempo_dialog.cancel_button.clicked.connect (bind (slot (tempo_dialog, &ArdourDialog::stop), -1));
tempo_dialog.set_position (GTK_WIN_POS_MOUSE);
tempo_dialog.realize ();
tempo_dialog.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH));
ensure_float (tempo_dialog);
tempo_dialog.run ();
if (tempo_dialog.run_status() == 0) {
double bpm = tempo_dialog.get_bpm ();
BBT_Time when;
tempo_dialog.get_bbt_time(when);
bpm = max (0.01, bpm);
begin_reversible_command (_("replace tempo mark"));
session->add_undo (session->tempo_map().get_memento());
session->tempo_map().replace_tempo (*section, Tempo (bpm));
session->tempo_map().move_tempo (*section, when);
session->add_redo_no_execute (session->tempo_map().get_memento());
commit_reversible_command ();
}
}
void
Editor::edit_tempo_marker (GtkCanvasItem *item)
{
Marker* marker;
TempoMarker* tempo_marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
if ((tempo_marker = dynamic_cast<TempoMarker*> (marker)) == 0) {
fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
/*NOTREACHED*/
}
edit_tempo_section (&tempo_marker->tempo());
}
void
Editor::edit_meter_marker (GtkCanvasItem *item)
{
Marker* marker;
MeterMarker* meter_marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
if ((meter_marker = dynamic_cast<MeterMarker*> (marker)) == 0) {
fatal << _("programming error: marker for meter is not a meter marker!") << endmsg;
/*NOTREACHED*/
}
edit_meter_section (&meter_marker->meter());
}
gint
Editor::real_remove_tempo_marker (TempoSection *section)
{
begin_reversible_command (_("remove tempo mark"));
session->add_undo (session->tempo_map().get_memento());
session->tempo_map().remove_tempo (*section);
session->add_redo_no_execute (session->tempo_map().get_memento());
commit_reversible_command ();
return FALSE;
}
void
Editor::remove_meter_marker (GtkCanvasItem* item)
{
Marker* marker;
MeterMarker* meter_marker;
if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
fatal << _("programming error: meter marker canvas item has no marker object pointer!") << endmsg;
/*NOTREACHED*/
}
if ((meter_marker = dynamic_cast<MeterMarker*> (marker)) == 0) {
fatal << _("programming error: marker for meter is not a meter marker!") << endmsg;
/*NOTREACHED*/
}
if (meter_marker->meter().movable()) {
Gtk::Main::idle.connect (bind (slot (*this, &Editor::real_remove_meter_marker), &meter_marker->meter()));
}
}
gint
Editor::real_remove_meter_marker (MeterSection *section)
{
begin_reversible_command (_("remove tempo mark"));
session->add_undo (session->tempo_map().get_memento());
session->tempo_map().remove_meter (*section);
session->add_redo_no_execute (session->tempo_map().get_memento());
commit_reversible_command ();
return FALSE;
}

View File

@@ -0,0 +1,239 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <cstdlib>
#include <cmath>
#include <string>
#include <pbd/error.h>
#include <pbd/pthread_utils.h>
#include "editor.h"
#include "audio_time_axis.h"
#include "regionview.h"
#include "region_selection.h"
#include <ardour/session.h>
#include <ardour/region.h>
#include <ardour/audioplaylist.h>
#include <ardour/audio_track.h>
#include <ardour/audioregion.h>
#include <ardour/diskstream.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace SigC;
using namespace Gtk;
Editor::TimeStretchDialog::TimeStretchDialog (Editor& e)
: ArdourDialog ("time stretch dialog"),
editor (e),
quick_button (_("Quick but Ugly")),
antialias_button (_("Skip Anti-aliasing")),
cancel_button (_("Cancel")),
action_button (_("Stretch/Shrink it"))
{
set_modal (true);
set_position (GTK_WIN_POS_MOUSE);
set_title (_("ardour: timestretch"));
set_name (N_("TimeStretchDialog"));
set_hide_on_stop (false);
add (packer);
packer.set_spacing (5);
packer.set_border_width (5);
packer.pack_start (upper_button_box);
packer.pack_start (progress_bar);
packer.pack_start (lower_button_box);
upper_button_box.set_homogeneous (true);
upper_button_box.set_spacing (5);
upper_button_box.set_border_width (5);
upper_button_box.pack_start (quick_button, true, true);
upper_button_box.pack_start (antialias_button, true, true);
lower_button_box.set_homogeneous (true);
lower_button_box.set_spacing (5);
lower_button_box.set_border_width (5);
lower_button_box.pack_start (action_button, true, true);
lower_button_box.pack_start (cancel_button, true, true);
action_button.set_name (N_("TimeStretchButton"));
cancel_button.set_name (N_("TimeStretchButton"));
quick_button.set_name (N_("TimeStretchButton"));
antialias_button.set_name (N_("TimeStretchButton"));
progress_bar.set_name (N_("TimeStretchProgress"));
action_button.clicked.connect (bind (slot (*this, &ArdourDialog::stop), 1));
}
gint
Editor::TimeStretchDialog::update_progress ()
{
progress_bar.set_percentage (request.progress);
return request.running;
}
void
Editor::TimeStretchDialog::cancel_timestretch_in_progress ()
{
status = -2;
request.running = false;
}
gint
Editor::TimeStretchDialog::delete_timestretch_in_progress (GdkEventAny* ev)
{
status = -2;
request.running = false;
return TRUE;
}
int
Editor::run_timestretch (AudioRegionSelection& regions, float fraction)
{
pthread_t thread;
if (current_timestretch == 0) {
current_timestretch = new TimeStretchDialog (*this);
}
current_timestretch->progress_bar.set_percentage (0.0f);
current_timestretch->first_cancel = current_timestretch->cancel_button.clicked.connect (bind (slot (*current_timestretch, &ArdourDialog::stop), -1));
current_timestretch->first_delete = current_timestretch->delete_event.connect (slot (*current_timestretch, &ArdourDialog::wm_close_event));
current_timestretch->run ();
if (current_timestretch->run_status() != 1) {
current_timestretch->close ();
return 1; /* no error, but we did nothing */
}
current_timestretch->status = 0;
current_timestretch->regions = regions;
current_timestretch->request.fraction = fraction;
current_timestretch->request.quick_seek = current_timestretch->quick_button.get_active();
current_timestretch->request.antialias = !current_timestretch->antialias_button.get_active();
current_timestretch->request.progress = 0.0f;
current_timestretch->request.running = true;
/* re-connect the cancel button and delete events */
current_timestretch->first_cancel.disconnect();
current_timestretch->first_delete.disconnect();
current_timestretch->cancel_button.clicked.connect (slot (current_timestretch, &TimeStretchDialog::cancel_timestretch_in_progress));
current_timestretch->delete_event.connect (slot (current_timestretch, &TimeStretchDialog::delete_timestretch_in_progress));
if (pthread_create_and_store ("timestretch", &thread, 0, timestretch_thread, current_timestretch)) {
current_timestretch->close ();
error << _("timestretch cannot be started - thread creation error") << endmsg;
return -1;
}
pthread_detach (thread);
SigC::Connection c = Main::timeout.connect (slot (current_timestretch, &TimeStretchDialog::update_progress), 100);
while (current_timestretch->request.running) {
gtk_main_iteration ();
}
c.disconnect ();
current_timestretch->close ();
return current_timestretch->status;
}
void
Editor::do_timestretch (TimeStretchDialog& dialog)
{
AudioTrack* at;
Playlist* playlist;
AudioRegion* new_region;
for (AudioRegionSelection::iterator i = dialog.regions.begin(); i != dialog.regions.end(); ) {
AudioRegion& aregion ((*i)->region);
TimeAxisView* tv = &(*i)->get_time_axis_view();
AudioTimeAxisView* atv;
AudioRegionSelection::iterator tmp;
tmp = i;
++tmp;
if ((atv = dynamic_cast<AudioTimeAxisView*> (tv)) == 0) {
i = tmp;
continue;
}
if ((at = dynamic_cast<AudioTrack*> (&atv->route())) == 0) {
i = tmp;
continue;
}
if ((playlist = at->disk_stream().playlist()) == 0) {
i = tmp;
continue;
}
dialog.request.region = &aregion;
if (!dialog.request.running) {
/* we were cancelled */
dialog.status = 1;
return;
}
if ((new_region = session->tempoize_region (dialog.request)) == 0) {
dialog.status = -1;
dialog.request.running = false;
return;
}
session->add_undo (playlist->get_memento());
playlist->replace_region (aregion, *new_region, aregion.position());
session->add_redo_no_execute (playlist->get_memento());
i = tmp;
}
dialog.status = 0;
dialog.request.running = false;
}
void*
Editor::timestretch_thread (void *arg)
{
PBD::ThreadCreated (pthread_self(), X_("TimeFX"));
TimeStretchDialog* tsd = static_cast<TimeStretchDialog*>(arg);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
tsd->editor.do_timestretch (*tsd);
return 0;
}

195
gtk2_ardour/editor_xpms Normal file
View File

@@ -0,0 +1,195 @@
/* Created with The GIMP */
#define hand_width 16
#define hand_height 16
#define hand_x_hot 3
#define hand_y_hot 0
static const gchar hand_bits[] = {
0x18, 0x00, 0x24, 0x00, 0x24, 0x00, 0x24, 0x00, 0xe4, 0x36, 0x24, 0x49,
0x27, 0x49, 0x25, 0x49, 0x25, 0x49, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40,
0x02, 0x40, 0x04, 0x60, 0xfc, 0x3f, 0xfc, 0x3f };
/* Created with The GIMP */
#define handmask_width 16
#define handmask_height 16
static const gchar handmask_bits[] = {
0x18, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0xfc, 0x36, 0xfc, 0x7f,
0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f,
0xfe, 0x7f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfc, 0x3f };
#define mag_width 16
#define mag_height 16
#define mag_x_hot 9
#define mag_y_hot 5
static const gchar mag_bits[] = {
0x7f, 0xe0, 0x3f, 0xc0, 0x1f, 0x8f, 0x8f, 0x9f, 0xcf, 0x3f, 0xcf, 0x3f,
0xcf, 0x3f, 0xcf, 0x3f, 0x8f, 0x1f, 0x1f, 0x8f, 0x0f, 0xc0, 0x47, 0xe0,
0xe3, 0xff, 0xf1, 0xff, 0xf8, 0xff, 0xfc, 0xff };
static const gchar magmask_bits[] = {
0x80, 0x1f, 0xc0, 0x3f, 0xe0, 0x70, 0x70, 0x66, 0x30, 0xc6, 0xb0, 0xdf,
0xb0, 0xdf, 0x30, 0xc6, 0x70, 0xe6, 0xe0, 0x70, 0xf0, 0x3f, 0xb8, 0x1f,
0x1c, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x03, 0x00 };
/* Created with The GIMP */
#define fader_cursor_width 25
#define fader_cursor_height 25
#define fader_cursor_x_hot 3
#define fader_cursor_y_hot 21
static const gchar fader_cursor_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x02, 0x01,
0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x01,
0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x01,
0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0xfe, 0x01,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00,
0x00, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00,
0x3e, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00,
0x00, 0x00, 0x00, 0x00 };
/* Created with The GIMP */
static const gchar fader_cursor_mask_bits[] = {
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01,
0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01,
0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01,
0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01,
0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00,
0x08, 0x00, 0x78, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x3e, 0x00, 0x78, 0x00,
0x7f, 0x00, 0x78, 0x00, 0x3e, 0x00, 0x78, 0x00, 0x1c, 0x00, 0x78, 0x00,
0x08, 0x00, 0x30, 0x00 };
#define speaker_cursor_width 16
#define speaker_cursor_height 26
#define speaker_cursor_x_hot 0
#define speaker_cursor_y_hot 0
static const gchar speaker_cursor_bits[] = {
0x00, 0xc0, 0x00, 0xc0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xcc, 0x00, 0xcc,
0xff, 0xc3, 0xff, 0xc3, 0x03, 0xc0, 0x03, 0xc0, 0xc3, 0xc0, 0xc3, 0xc0,
0xc3, 0xc0, 0xc3, 0xc0, 0xc3, 0xc0, 0xc3, 0xc0, 0x03, 0xc0, 0x03, 0xc0,
0xff, 0xc3, 0xff, 0xc3, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xf0, 0x00, 0xf0,
0x00, 0xc0, 0x00, 0xc0 };
#define speaker_cursor_mask_width 16
#define speaker_cursor_mask_height 26
#define speaker_cursor_mask_x_hot 0
#define speaker_cursor_mask_y_hot 0
static const gchar speaker_cursor_mask_bits[] = {
0x00, 0xc0, 0x00, 0xc0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xfc,
0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x3f, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xf0, 0x00, 0xf0,
0x00, 0xc0, 0x00, 0xc0 };
/* XPM */
static const gchar * zoom_in_button_xpm[] = {
"16 16 3 1",
" c None",
". c #000000",
"+ c #FFFFFF",
" ....... ",
" .+++++++. ",
" .+++++++++. ",
" .+++.....+++. ",
" .+++. + .+++.",
" .++. +.+ .++.",
" .++. ++.++ .++.",
" .++.+.....+.++.",
" .++. ++.++ .++.",
" .++. +.+ .++.",
" .+++. + .+++.",
" .+++.....+++. ",
" .+++++++++++. ",
".+++.+++++++. ",
".++. ....... ",
"... "};
/* XPM */
static const gchar * zoom_out_button_xpm[] = {
"16 16 3 1",
" c None",
". c #000000",
"+ c #FFFFFF",
" ....... ",
" .+++++++. ",
" .+++++++++. ",
" .+++.....+++. ",
" .+++. .+++.",
" .++. .++.",
" .++. +++++ .++.",
" .++.+.....+.++.",
" .++. +++++ .++.",
" .++. .++.",
" .+++. .+++.",
" .+++.....+++. ",
" .+++++++++++. ",
".+++.+++++++. ",
".++. ....... ",
"... "};
/* XPM */
static const gchar * zoom_out_full_button_xpm[] = {
"16 16 3 1",
" c None",
". c #000000",
"+ c #FFFFFF",
" ",
" ",
" ",
" ",
".... ....",
".++. .++.",
".++..........++.",
".++++++++++++++.",
".++++++++++++++.",
".++++++++++++++.",
".++..........++.",
".++. .++.",
".... ....",
" ",
" ",
" "};
/* XPM */
static const gchar * right_arrow_xpm[] = {
"12 15 3 1",
" c None",
". c #000000",
"+ c #FFFFFF",
" .+.. ",
" .++.. ",
" .+++.. ",
" ..+++.. ",
" ..+++.. ",
" ..+++.. ",
" ..+++.. ",
" ..+++. ",
" ..+++.. ",
" ..+++.. ",
" ..+++.. ",
" ..+++.. ",
" .+++.. ",
" .++.. ",
" .+.. "};
/* XPM */
static const gchar * left_arrow_xpm[] = {
"12 15 3 1",
" c None",
". c #000000",
"+ c #FFFFFF",
" ..+. ",
" ..++. ",
" ..+++. ",
" ..+++.. ",
" ..+++.. ",
" ..+++.. ",
" ..+++.. ",
" .+++.. ",
" ..+++.. ",
" ..+++.. ",
" ..+++.. ",
" ..+++.. ",
" ..+++. ",
" ..++. ",
" ..+. "};

26
gtk2_ardour/enums.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef __ardour_gtk_enums_h__
#define __ardour_gtk_enums_h__
#include <ardour/types.h>
enum WaveformShape {
Traditional,
Rectified
};
enum Width {
Wide,
Narrow,
};
#include <gtk-canvas/gtk-canvas.h>
struct SelectionRect {
GtkCanvasItem *rect;
GtkCanvasItem *end_trim;
GtkCanvasItem *start_trim;
uint32_t id;
};
#endif /* __ardour_gtk_enums_h__ */

1391
gtk2_ardour/export_dialog.cc Normal file

File diff suppressed because it is too large Load Diff

132
gtk2_ardour/export_dialog.h Normal file
View File

@@ -0,0 +1,132 @@
/*
Copyright (C) 1999-2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_export_dialog_h__
#define __ardour_export_dialog_h__
#include <gtk--.h>
#include <ardour/export.h>
#include "ardour_dialog.h"
#include <ardour/location.h>
class PublicEditor;
namespace ARDOUR {
class Session;
class AudioRegion;
}
class ExportDialog : public ArdourDialog
{
public:
ExportDialog (PublicEditor&, ARDOUR::AudioRegion* r = 0);
~ExportDialog ();
void connect_to_session (ARDOUR::Session*);
void set_range (jack_nframes_t start, jack_nframes_t end);
void start_export ();
private:
PublicEditor& editor;
ARDOUR::Session* session;
ARDOUR::AudioRegion* audio_region;
Gtk::VBox vpacker;
Gtk::VBox track_vpacker;
Gtk::HBox hpacker;
Gtk::HBox button_box;
Gtk::Table format_table;
Gtk::Frame format_frame;
Gtk::Label sample_rate_label;
Gtk::Combo sample_rate_combo;
Gtk::Label src_quality_label;
Gtk::Combo src_quality_combo;
Gtk::Label dither_type_label;
Gtk::Combo dither_type_combo;
Gtk::Label cue_file_label;
Gtk::Combo cue_file_combo;
Gtk::Label channel_count_label;
Gtk::Combo channel_count_combo;
Gtk::Label header_format_label;
Gtk::Combo header_format_combo;
Gtk::Label bitdepth_format_label;
Gtk::Combo bitdepth_format_combo;
Gtk::Label endian_format_label;
Gtk::Combo endian_format_combo;
Gtk::CheckButton cuefile_only_checkbox;
Gtk::Frame file_frame;
Gtk::Entry file_entry;
Gtk::HBox file_hbox;
Gtk::Button file_browse_button;
Gtk::Button ok_button;
Gtk::Button cancel_button;
Gtk::Label cancel_label;
Gtk::ProgressBar progress_bar;
Gtk::ScrolledWindow track_scroll;
Gtk::ScrolledWindow master_scroll;
Gtk::Button track_selector_button;
Gtk::CList track_selector;
Gtk::CList master_selector;
Gtk::FileSelection *file_selector;
ARDOUR::AudioExportSpecification spec;
static GdkPixmap *check_pixmap;
static GdkBitmap *check_mask;
static GdkPixmap *empty_pixmap;
static GdkBitmap *empty_mask;
static void *_thread (void *arg);
gint progress_timeout ();
SigC::Connection progress_connection;
void build_window ();
void end_dialog();
gint header_chosen (GdkEventAny *ignored);
gint channels_chosen (GdkEventAny *ignored);
gint bitdepth_chosen (GdkEventAny *ignored);
gint sample_rate_chosen (GdkEventAny *ignored);
gint cue_file_type_chosen(GdkEventAny *ignored);
gint track_selector_button_press_event (GdkEventButton *ev);
gint master_selector_button_press_event (GdkEventButton *ev);
void do_export_cd_markers (const string& path, const string& cuefile_type);
void export_cue_file (ARDOUR::Locations::LocationList& locations, const string& path);
void export_toc_file (ARDOUR::Locations::LocationList& locations, const string& path);
void do_export ();
gint change_focus_policy (GdkEventAny *, bool);
gint window_closed (GdkEventAny *ignored);
void track_selector_button_click ();
void initiate_browse ();
void finish_browse (int status);
void set_state();
void save_state();
static void* _export_region_thread (void *);
void export_region ();
};
#endif // __ardour_export_dialog_h__

138
gtk2_ardour/extra_bind.h Normal file
View File

@@ -0,0 +1,138 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_extra_bind_h__
#define __ardour_extra_bind_h__
#include <sigc++/adaptor.h>
#include <sigc++/scope.h>
namespace SigC
{
/****************************************************************
***** Adaptor Bind Slot 0 arguments, 3 hidden arguments
****************************************************************/
template <class R,
class C1, class C2, class C3>
struct AdaptorBindSlot0_3: public AdaptorSlot_
{
#ifdef SIGC_CXX_PARTIAL_SPEC
typedef R RType;
#else
typedef typename Trait<R>::type RType;
#endif
typedef Slot0<R> SlotType;
typedef Slot3<R,C1,C2,C3> InSlotType;
struct Node:public AdaptorNode
{
C1 c1_;
C2 c2_;
C3 c3_;
};
typedef CallDataObj2<typename SlotType::Func,Node> CallData;
static RType callback(void* d)
{
CallData* data=(CallData*)d;
Node* node=data->obj;
return ((typename InSlotType::Callback&)(node->data_))(
node->c1_,
node->c2_,
node->c3_);
}
static SlotData* create(SlotData *s,C1 c1, C2 c2, C3 c3)
{
SlotData* tmp=(SlotData*)s;
Node *node=new Node();
copy_callback(tmp,node);
node->c1_=c1;
node->c2_=c2;
node->c3_=c3;
CallData &data=reinterpret_cast<CallData&>(tmp->data_);
data.callback=&callback;
data.obj=node;
return tmp;
}
};
#ifndef SIGC_CXX_VOID_RETURN
#ifdef SIGC_CXX_PARTIAL_SPEC
template <
class C1,C2,C3>
struct AdaptorBindSlot0_3
<void,
C1,C2,C3> : public AdaptorSlot_
{
typedef void RType;
typedef Slot0<void> SlotType;
typedef Slot3<void,C1,C2,C3> InSlotType;
struct Node:public AdaptorNode
{
C1 c1_;
C2 c2_;
C3 c3_;
};
typedef CallDataObj2<typename SlotType::Func,Node> CallData;
static RType callback(void* d)
{
CallData* data=(CallData*)d;
Node* node=data->obj;
((typename InSlotType::Callback&)(node->data_))(
node->c1_,
node->c2_,
node->c3);
}
static SlotData* create(SlotData *s,C1 c1, C2 c2, C3 c3)
{
SlotData* tmp=(SlotData*)s;
Node *node=new Node();
copy_callback(tmp,node);
node->c1_=c1;
node->c2_=c2;
node->c3_=c3;
CallData &data=reinterpret_cast<CallData&>(tmp->data_);
data.callback=&callback;
data.obj=node;
return tmp;
}
};
#endif
#endif
template <class C1, class C2, class C3,
class R>
Slot0<R>
bind(const Slot3<R,C1,C2,C3> &s,
C1 c1, C2 c2, C3 c3)
{return AdaptorBindSlot0_3<R,
C1,C2,C3>::create(s.data(),c1,c2,c3);
}
} /* namespace */
#endif /* __ardour_extra_bind_h__ */

View File

@@ -0,0 +1,75 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <ardour/curve.h>
#include <ardour/route.h>
#include "gain_automation_time_axis.h"
#include "automation_line.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace Gtk;
GainAutomationTimeAxisView::GainAutomationTimeAxisView (Session& s, Route& r, PublicEditor& e, TimeAxisView& parent, Widget* p, std::string n, ARDOUR::Curve& c)
: AxisView (s),
AutomationTimeAxisView (s, r, e, parent, p, n, X_("gain"), ""),
curve (c)
{
}
GainAutomationTimeAxisView::~GainAutomationTimeAxisView ()
{
}
void
GainAutomationTimeAxisView::add_automation_event (GtkCanvasItem* item, GdkEvent* event, jack_nframes_t when, double y)
{
double x = 0;
gtk_canvas_item_w2i (canvas_display, &x, &y);
/* compute vertical fractional position */
y = 1.0 - (y / height);
/* map using line */
lines.front()->view_to_model_y (y);
_session.begin_reversible_command (_("add gain automation event"));
_session.add_undo (curve.get_memento());
curve.add (when, y);
_session.add_redo_no_execute (curve.get_memento());
_session.commit_reversible_command ();
_session.set_dirty ();
}
void
GainAutomationTimeAxisView::set_automation_state (AutoState state)
{
if (!ignore_state_request) {
route.set_gain_automation_state (state);
}
}

View File

@@ -0,0 +1,33 @@
#ifndef __ardour_gtk_gain_automation_time_axis_h__
#define __ardour_gtk_gain_automation_time_axis_h__
#include "automation_time_axis.h"
namespace ARDOUR {
class Redirect;
class Curve;
}
class GainAutomationTimeAxisView : public AutomationTimeAxisView
{
public:
GainAutomationTimeAxisView (ARDOUR::Session&,
ARDOUR::Route&,
PublicEditor&,
TimeAxisView& parent_axis,
Gtk::Widget* parent,
std::string name,
ARDOUR::Curve&);
~GainAutomationTimeAxisView();
void add_automation_event (GtkCanvasItem *item, GdkEvent *event, jack_nframes_t, double);
private:
ARDOUR::Curve& curve;
void automation_changed ();
void set_automation_state (ARDOUR::AutoState);
};
#endif /* __ardour_gtk_gain_automation_time_axis_h__ */

762
gtk2_ardour/gain_meter.cc Normal file
View File

@@ -0,0 +1,762 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#include <limits.h>
#include <ardour/io.h>
#include <ardour/route.h>
#include <ardour/route_group.h>
#include <ardour/session.h>
#include <ardour/session_route.h>
#include <ardour/dB.h>
#include <gtkmmext/utils.h>
#include <gtkmmext/pix.h>
#include <gtkmmext/fastmeter.h>
#include <gtkmmext/stop_signal.h>
#include <gtkmmext/barcontroller.h>
#include <midi++/manager.h>
#include <pbd/fastlog.h>
#include "ardour_ui.h"
#include "gain_meter.h"
#include "utils.h"
#include "logmeter.h"
#include "gui_thread.h"
#include <ardour/session.h>
#include <ardour/route.h>
#include "i18n.h"
#include "misc_xpms"
using namespace ARDOUR;
using namespace Gtkmmext;
using namespace Gtk;
using namespace SigC;
Signal0<void> GainMeter::ResetAllPeakDisplays;
Signal1<void,RouteGroup*> GainMeter::ResetGroupPeakDisplays;
Pix* GainMeter::slider_pix = 0;
int
GainMeter::setup_slider_pix ()
{
vector<const char **> xpms;
xpms.push_back (vslider_rail_xpm);
xpms.push_back (vslider_slider_xpm);
if ((slider_pix = get_pix ("sliders", xpms, false)) == 0) {
error << _("Cannot create slider pixmaps") << endmsg;
return -1;
}
slider_pix->ref ();
return 0;
}
GainMeter::GainMeter (IO& io, Session& s)
: _io (io),
_session (s),
gain_slider (0),
// 0.781787 is the value needed for gain to be set to 0.
gain_adjustment (0.781787, 0.0, 1.0, 0.01, 0.1),
gain_display (&gain_adjustment, "MixerStripGainDisplay"),
gain_unit_label (_("dbFS")),
meter_point_label (_("pre")),
top_table (1, 2)
{
if (slider_pix == 0) {
setup_slider_pix ();
}
ignore_toggle = false;
meter_menu = 0;
gain_slider = manage (new VSliderController (slider_pix,
&gain_adjustment,
& _io.midi_gain_control(),
false));
gain_slider->button_press_event.connect (slot (*this, &GainMeter::start_gain_touch));
gain_slider->button_release_event.connect (slot (*this, &GainMeter::end_gain_touch));
gain_slider->set_name ("MixerGainMeter");
if (_session.midi_port()) {
_io.set_midi_to_gain_function (slider_position_to_gain);
_io.set_gain_to_midi_function (gain_to_slider_position);
}
gain_display.set_print_func (_gain_printer, this);
set_usize_to_display_given_text (gain_display, "-86.0", 2, 2);
gain_unit_button.add (gain_unit_label);
gain_unit_button.set_name ("MixerStripGainUnitButton");
gain_unit_label.set_name ("MixerStripGainUnitButton");
top_table.set_col_spacings (2);
top_table.set_homogeneous (true);
top_table.attach (gain_unit_button, 0, 1, 0, 1);
Route* r;
if ((r = dynamic_cast<Route*> (&_io)) != 0) {
r->meter_change.connect (slot (*this, &GainMeter::meter_changed));
meter_point_button.add (meter_point_label);
meter_point_button.set_name ("MixerStripMeterPreButton");
meter_point_label.set_name ("MixerStripMeterPreButton");
switch (r->meter_point()) {
case MeterInput:
meter_point_label.set_text (_("input"));
break;
case MeterPreFader:
meter_point_label.set_text (_("pre"));
break;
case MeterPostFader:
meter_point_label.set_text (_("post"));
break;
}
/* TRANSLATORS: this string should be longest of the strings
used to describe meter points. In english, its "input".
*/
set_usize_to_display_given_text (meter_point_button, _("tupni"), 2, 2);
meter_point_button.button_press_event.connect (slot (*this, &GainMeter::meter_press));
meter_point_button.button_release_event.connect (slot (*this, &GainMeter::meter_release));
top_table.attach (meter_point_button, 1, 2, 0, 1);
}
gain_display_box.set_spacing (2);
gain_display_frame.set_shadow_type (GTK_SHADOW_IN);
gain_display_frame.set_name ("BaseFrame");
gain_display_frame.add (gain_display);
gain_display_box.pack_start (gain_display_frame, false, false);
peak_display.set_name ("MixerStripPeakDisplay");
set_usize_to_display_given_text (peak_display, "-86.0", 2, 2);
peak_display.add (peak_display_label);
peak_display_frame.set_shadow_type (GTK_SHADOW_IN);
peak_display_frame.set_name ("BaseFrame");
peak_display_frame.add (peak_display);
max_peak = minus_infinity();
peak_display_label.set_text (_("-inf"));
gain_display_box.pack_start (peak_display_frame, false, false);
meter_metric_area.set_usize (18, -1);
meter_metric_area.set_name ("MeterMetricsStrip");
meter_packer.show ();
gain_slider->show_all ();
meter_packer.set_spacing (2);
fader_box.set_spacing (2);
fader_box.pack_start (*gain_slider, false, false);
hbox.set_spacing (4);
hbox.pack_start (fader_box, false, false);
hbox.pack_start (meter_packer, false, false);
set_spacing (4);
pack_start (top_table, false, false);
pack_start (gain_display_box, false, false);
pack_start (hbox, false, false);
show_all ();
_io.gain_changed.connect (slot (*this, &GainMeter::gain_changed));
meter_metric_area.expose_event.connect (slot (*this, &GainMeter::meter_metrics_expose));
gain_adjustment.value_changed.connect (slot (*this, &GainMeter::gain_adjusted));
peak_display.button_release_event.connect (slot (*this, &GainMeter::peak_button_release));
_session.MeterHoldChanged.connect (slot (*this, &GainMeter::meter_hold_changed));
gain_changed (0);
update_gain_sensitive ();
ResetAllPeakDisplays.connect (slot (*this, &GainMeter::reset_peak_display));
ResetGroupPeakDisplays.connect (slot (*this, &GainMeter::reset_group_peak_display));
}
void
GainMeter::set_width (Width w)
{
switch (w) {
case Wide:
peak_display_frame.show_all();
break;
case Narrow:
peak_display_frame.hide_all();
break;
}
_width = w;
setup_meters ();
}
gint
GainMeter::meter_metrics_expose (GdkEventExpose *ev)
{
/* XXX optimize this so that it doesn't do it all everytime */
double fraction;
Gdk_Window win (meter_metric_area.get_window());
Gdk_GC fg_gc (meter_metric_area.get_style()->get_fg_gc (GTK_STATE_NORMAL));
Gdk_GC bg_gc (meter_metric_area.get_style()->get_bg_gc (GTK_STATE_NORMAL));
Gdk_Font font (meter_metric_area.get_style()->get_font());
gint x, y, width, height, depth;
gint pos;
int db_points[] = { -50, -10, -3, 0, 6 };
uint32_t i;
char buf[32];
GdkRectangle base_rect;
GdkRectangle draw_rect;
win.get_geometry (x, y, width, height, depth);
base_rect.width = width;
base_rect.height = height;
base_rect.x = 0;
base_rect.y = 0;
gdk_rectangle_intersect (&ev->area, &base_rect, &draw_rect);
win.draw_rectangle (bg_gc, true, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height);
for (i = 0; i < sizeof (db_points)/sizeof (db_points[0]); ++i) {
fraction = log_meter (db_points[i]);
pos = height - (gint) floor (height * fraction);
snprintf (buf, sizeof (buf), "%d", db_points[i]);
gint twidth;
gint lbearing;
gint rbearing;
gint ascent;
gint descent;
gdk_string_extents (font,
buf,
&lbearing,
&rbearing,
&twidth,
&ascent,
&descent);
win.draw_text (font, fg_gc, width - twidth, pos + ascent, buf, strlen (buf));
}
return TRUE;
}
GainMeter::~GainMeter ()
{
if (meter_menu) {
delete meter_menu;
}
for (vector<MeterInfo>::iterator i = meters.begin(); i != meters.end(); i++) {
if ((*i).meter) {
delete (*i).meter;
}
}
}
void
GainMeter::update_meters ()
{
vector<MeterInfo>::iterator i;
uint32_t n;
float peak;
char buf[32];
for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
if ((*i).packed) {
peak = _io.peak_input_power (n);
if (_session.meter_falloff() == 0.0f || peak > (*i).meter->get_user_level()) {
(*i).meter->set (log_meter (peak), peak);
}
if (peak > max_peak) {
max_peak = peak;
/* set peak display */
snprintf (buf, sizeof(buf), "%.1f", max_peak);
peak_display_label.set_text (buf);
if (max_peak >= 0.0f) {
peak_display.set_name ("MixerStripPeakDisplayPeak");
}
}
}
}
}
void
GainMeter::update_meters_falloff ()
{
vector<MeterInfo>::iterator i;
uint32_t n;
float dbpeak;
for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
if ((*i).packed) {
// just do falloff
//peak = (*i).meter->get_level() * _falloff_rate;
dbpeak = (*i).meter->get_user_level() - _session.meter_falloff();
dbpeak = std::max(dbpeak, -200.0f);
// cerr << "tmplevel: " << tmplevel << endl;
(*i).meter->set (log_meter (dbpeak), dbpeak);
}
}
}
void
GainMeter::meter_hold_changed()
{
ENSURE_GUI_THREAD(slot (*this, &GainMeter::meter_hold_changed));
vector<MeterInfo>::iterator i;
uint32_t n;
for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
(*i).meter->set_hold_count ((uint32_t) floor(_session.meter_hold()));
}
}
void
GainMeter::hide_all_meters ()
{
bool remove_metric_area = false;
for (vector<MeterInfo>::iterator i = meters.begin(); i != meters.end(); ++i) {
if ((*i).packed) {
remove_metric_area = true;
meter_packer.remove (*((*i).meter));
(*i).packed = false;
}
}
if (remove_metric_area) {
if (meter_metric_area.get_parent()) {
meter_packer.remove (meter_metric_area);
}
}
}
void
GainMeter::setup_meters ()
{
uint32_t nmeters = _io.n_outputs();
guint16 width;
hide_all_meters ();
Route* r;
if ((r = dynamic_cast<Route*> (&_io)) != 0) {
switch (r->meter_point()) {
case MeterPreFader:
case MeterInput:
nmeters = r->n_inputs();
break;
case MeterPostFader:
nmeters = r->n_outputs();
break;
}
} else {
nmeters = _io.n_outputs();
}
if (nmeters == 0) {
return;
}
if (_width == Wide) {
meter_packer.pack_start (meter_metric_area, false, false);
meter_metric_area.show_all ();
}
if (nmeters <= 2) {
width = regular_meter_width;
} else {
width = thin_meter_width;
}
while (meters.size() < nmeters) {
meters.push_back (MeterInfo());
}
for (uint32_t n = 0; n < nmeters; ++n) {
if (meters[n].width != width) {
delete meters[n].meter;
meters[n].meter = new FastMeter ((uint32_t) floor (_session.meter_hold()), width, FastMeter::Vertical);
meters[n].width = width;
meters[n].meter->add_events (GDK_BUTTON_RELEASE_MASK);
meters[n].meter->button_release_event.connect
(bind (slot (*this, &GainMeter::meter_button_release), n));
meters[n].meter->button_release_event.connect_after (slot (do_not_propagate));
}
meter_packer.pack_start (*meters[n].meter, false, false);
meters[n].meter->show_all ();
meters[n].packed = true;
}
}
gint
GainMeter::peak_button_release (GdkEventButton* ev)
{
/* reset peak label */
if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::Control|Keyboard::Shift)) {
ResetAllPeakDisplays ();
} else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
Route* r;
if ((r = dynamic_cast<Route*> (&_io)) != 0) {
ResetGroupPeakDisplays (r->mix_group());
}
} else {
reset_peak_display ();
}
return TRUE;
}
void
GainMeter::reset_peak_display ()
{
max_peak = minus_infinity();
peak_display_label.set_text (_("-inf"));
peak_display.set_name ("MixerStripPeakDisplay");
}
void
GainMeter::reset_group_peak_display (RouteGroup* group)
{
Route* r;
if ((r = dynamic_cast<Route*> (&_io)) != 0) {
if (group == r->mix_group()) {
reset_peak_display ();
}
}
}
gint
GainMeter::meter_button_release (GdkEventButton* ev, uint32_t which)
{
switch (ev->button) {
case 1:
meters[which].meter->clear();
max_peak = minus_infinity();
peak_display_label.set_text (_("-inf"));
peak_display.set_name ("MixerStripPeakDisplay");
break;
case 3:
// popup_meter_menu (ev);
break;
};
return TRUE;
}
void
GainMeter::popup_meter_menu (GdkEventButton *ev)
{
using namespace Menu_Helpers;
if (meter_menu == 0) {
meter_menu = new Gtk::Menu;
MenuList& items = meter_menu->items();
items.push_back (MenuElem ("-inf .. +0dBFS"));
items.push_back (MenuElem ("-10dB .. +0dBFS"));
items.push_back (MenuElem ("-4 .. +0dBFS"));
items.push_back (SeparatorElem());
items.push_back (MenuElem ("-inf .. -2dBFS"));
items.push_back (MenuElem ("-10dB .. -2dBFS"));
items.push_back (MenuElem ("-4 .. -2dBFS"));
}
meter_menu->popup (1, ev->time);
}
void
GainMeter::_gain_printer (char buf[32], Gtk::Adjustment& adj, void *arg)
{
static_cast<GainMeter *>(arg)->gain_printer (buf, adj);
}
void
GainMeter::gain_printer (char buf[32], Gtk::Adjustment& adj)
{
float v = adj.get_value();
if (v == 0.0) {
strcpy (buf, _("-inf"));
} else {
snprintf (buf, 32, "%.1f", coefficient_to_dB (slider_position_to_gain (v)));
}
}
void
GainMeter::gain_adjusted ()
{
if (!ignore_toggle) {
_io.set_gain (slider_position_to_gain (gain_adjustment.get_value()), this);
}
}
void
GainMeter::effective_gain_display ()
{
gfloat value = gain_to_slider_position (_io.effective_gain());
if (gain_adjustment.get_value() != value) {
ignore_toggle = true;
gain_adjustment.set_value (value);
ignore_toggle = false;
}
}
void
GainMeter::gain_changed (void *src)
{
Gtkmmext::UI::instance()->call_slot (slot (*this, &GainMeter::effective_gain_display));
}
gint
GainMeter::entry_focus_event (GdkEventFocus* ev)
{
if (ev->in) {
ARDOUR_UI::instance()->allow_focus (true);
} else {
ARDOUR_UI::instance()->allow_focus (false);
}
return TRUE;
}
void
GainMeter::set_meter_strip_name (string name)
{
meter_metric_area.set_name (name);
}
void
GainMeter::set_fader_name (string name)
{
gain_slider->set_name (name);
}
void
GainMeter::update_gain_sensitive ()
{
static_cast<Gtkmmext::SliderController*>(gain_slider)->set_sensitive (!(_io.gain_automation_state() & Play));
}
static MeterPoint
next_meter_point (MeterPoint mp)
{
switch (mp) {
case MeterInput:
return MeterPreFader;
break;
case MeterPreFader:
return MeterPostFader;
break;
case MeterPostFader:
return MeterInput;
break;
}
/*NOTREACHED*/
return MeterInput;
}
gint
GainMeter::meter_press(GdkEventButton* ev)
{
Route* _route;
wait_for_release = false;
if ((_route = dynamic_cast<Route*>(&_io)) == 0) {
return FALSE;
}
if (!ignore_toggle) {
if (Keyboard::is_context_menu_event (ev)) {
// no menu at this time.
} else {
if (ev->button == 2) {
// ctrl-button2 click is the midi binding click
// button2-click is "momentary"
if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control))) {
wait_for_release = true;
old_meter_point = _route->meter_point ();
}
}
if (ev->button == 1 || ev->button == 2) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
/* ctrl-shift-click applies change to all routes */
_session.foreach_route (this, &GainMeter::set_meter_point, next_meter_point (_route->meter_point()));
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
/* ctrl-click: solo mix group.
ctrl-button2 is MIDI learn.
*/
if (ev->button == 1) {
set_mix_group_meter_point (*_route, next_meter_point (_route->meter_point()));
}
} else {
/* click: solo this route */
_route->set_meter_point (next_meter_point (_route->meter_point()), this);
}
}
}
}
return stop_signal (meter_point_button, "button-press-event");
}
gint
GainMeter::meter_release(GdkEventButton* ev)
{
if(!ignore_toggle){
if (wait_for_release){
wait_for_release = false;
set_meter_point (*(dynamic_cast<Route*>(&_io)), old_meter_point);
stop_signal (meter_point_button, "button-release-event");
}
}
return TRUE;
}
void
GainMeter::set_meter_point (Route& route, MeterPoint mp)
{
route.set_meter_point (mp, this);
}
void
GainMeter::set_mix_group_meter_point (Route& route, MeterPoint mp)
{
RouteGroup* mix_group;
if((mix_group = route.mix_group()) != 0){
mix_group->apply (&Route::set_meter_point, mp, this);
} else {
route.set_meter_point (mp, this);
}
}
void
GainMeter::meter_changed (void *src)
{
Route* r;
ENSURE_GUI_THREAD (bind (slot (*this, &GainMeter::meter_changed), src));
if ((r = dynamic_cast<Route*> (&_io)) != 0) {
switch (r->meter_point()) {
case MeterInput:
meter_point_label.set_text (_("input"));
break;
case MeterPreFader:
meter_point_label.set_text (_("pre"));
break;
case MeterPostFader:
meter_point_label.set_text (_("post"));
break;
}
setup_meters ();
}
}
void
GainMeter::meter_point_clicked ()
{
Route* r;
if ((r = dynamic_cast<Route*> (&_io)) != 0) {
}
}
gint
GainMeter::start_gain_touch (GdkEventButton* ev)
{
_io.start_gain_touch ();
return FALSE;
}
gint
GainMeter::end_gain_touch (GdkEventButton* ev)
{
_io.end_gain_touch ();
return FALSE;
}

156
gtk2_ardour/gain_meter.h Normal file
View File

@@ -0,0 +1,156 @@
/*
Copyright (C) 2002 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_gtk_gain_meter_h__
#define __ardour_gtk_gain_meter_h__
#include <vector>
#include <ardour/types.h>
#include <gtk--.h>
#include <gtkmmext/slider_controller.h>
#include <gtkmmext/click_box.h>
#include "enums.h"
namespace ARDOUR {
class IO;
class Session;
class Route;
class RouteGroup;
}
namespace Gtkmmext {
class FastMeter;
class BarController;
class Pix;
}
class GainMeter : public Gtk::VBox
{
public:
GainMeter (ARDOUR::IO&, ARDOUR::Session&);
~GainMeter ();
void update_gain_sensitive ();
void update_meters ();
void update_meters_falloff ();
void effective_gain_display ();
void set_width (Width);
void setup_meters ();
void set_meter_strip_name (string name);
void set_fader_name (string name);
private:
ARDOUR::IO& _io;
ARDOUR::Session& _session;
bool ignore_toggle;
Gtkmmext::VSliderController *gain_slider;
Gtk::Adjustment gain_adjustment;
Gtk::Frame gain_display_frame;
Gtkmmext::ClickBox gain_display;
Gtk::Frame peak_display_frame;
Gtk::EventBox peak_display;
Gtk::Label peak_display_label;
Gtk::Button gain_unit_button;
Gtk::Label gain_unit_label;
Gtk::HBox gain_display_box;
Gtk::HBox fader_box;
Gtk::DrawingArea meter_metric_area;
Gtk::Button meter_point_button;
Gtk::Label meter_point_label;
Gtk::Table top_table;
Width _width;
gint meter_metrics_expose (GdkEventExpose *);
static void _gain_printer (char buf[32], Gtk::Adjustment&, void *);
void gain_printer (char buf[32], Gtk::Adjustment&);
struct MeterInfo {
Gtkmmext::FastMeter *meter;
gint16 width;
bool packed;
MeterInfo() {
meter = 0;
width = 0;
packed = false;
}
};
static const guint16 regular_meter_width = 5;
static const guint16 thin_meter_width = 2;
vector<MeterInfo> meters;
float max_peak;
Gtk::HBox hbox;
Gtk::HBox meter_packer;
void gain_adjusted ();
void gain_changed (void *);
void meter_point_clicked ();
void meter_changed (void *);
void gain_unit_changed ();
void hide_all_meters ();
gint meter_button_press (GdkEventButton*, uint32_t);
gint meter_button_release (GdkEventButton*, uint32_t);
gint peak_button_release (GdkEventButton*);
Gtk::Menu* meter_menu;
void popup_meter_menu (GdkEventButton*);
gint start_gain_touch (GdkEventButton*);
gint end_gain_touch (GdkEventButton*);
gint entry_focus_event (GdkEventFocus* ev);
void set_mix_group_meter_point (ARDOUR::Route&, ARDOUR::MeterPoint);
void set_meter_point (ARDOUR::Route&, ARDOUR::MeterPoint);
gint meter_release (GdkEventButton*);
gint meter_press (GdkEventButton*);
bool wait_for_release;
ARDOUR::MeterPoint old_meter_point;
void meter_hold_changed();
void reset_peak_display ();
void reset_group_peak_display (ARDOUR::RouteGroup*);
static SigC::Signal0<void> ResetAllPeakDisplays;
static SigC::Signal1<void,ARDOUR::RouteGroup*> ResetGroupPeakDisplays;
static Gtkmmext::Pix* slider_pix;
static int setup_slider_pix ();
};
#endif /* __ardour_gtk_gain_meter_h__ */

82
gtk2_ardour/gettext.h Normal file
View File

@@ -0,0 +1,82 @@
/* Convenience header for conditional use of GNU <libintl.h>.
Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published
by the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1
/* NLS can be disabled through the configure --disable-nls option. */
#if ENABLE_NLS
/* Get declarations of GNU message catalog functions. */
# include <libintl.h>
#else
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
chokes if dcgettext is defined as a macro. So include it now, to make
later inclusions of <locale.h> a NOP. We don't include <libintl.h>
as well because people using "gettext.h" will not include <libintl.h>,
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
is OK. */
#if defined(__sun)
# include <locale.h>
#endif
/* Disabled NLS.
The casts to 'const char *' serve the purpose of producing warnings
for invalid uses of the value returned from these functions.
On pre-ANSI systems without 'const', the config.h file is supposed to
contain "#define const". */
/* other headers may have included libintl.h */
# undef gettext
# undef dgettext
# undef dcgettext
# undef ngettext
# undef dngettext
# undef dcngettext
# undef textdomain
# undef bindtextdomain
# undef bind_textdomain_codeset
# define gettext(Msgid) ((const char *) (Msgid))
# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
# define ngettext(Msgid1, Msgid2, N) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define dngettext(Domainname, Msgid1, Msgid2, N) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define textdomain(Domainname) ((const char *) (Domainname))
# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
#endif
/* A pseudo function call that serves as a marker for the automated
extraction of messages, but does not call gettext(). The run-time
translation is done at a different place in the code.
The argument, String, should be a literal string. Concatenated strings
and other string expressions won't work.
The macro's expansion is not parenthesized, so that it is suitable as
initializer for static 'char[]' or 'const char[]' variables. */
#define gettext_noop(String) String
#endif /* _LIBGETTEXT_H */

View File

@@ -0,0 +1,68 @@
#include "canvas-simplerect.h"
#include "ghostregion.h"
#include "automation_time_axis.h"
#include "rgb_macros.h"
using namespace Editing;
GhostRegion::GhostRegion (AutomationTimeAxisView& atv, double initial_pos)
: trackview (atv)
{
group = gtk_canvas_item_new (GTK_CANVAS_GROUP(trackview.canvas_display),
gtk_canvas_group_get_type(),
"x", initial_pos,
"y", 0.0,
NULL);
base_rect = gtk_canvas_item_new (GTK_CANVAS_GROUP(group),
gtk_canvas_simplerect_get_type(),
"x1", (double) 0.0,
"y1", (double) 0.0,
"y2", (double) trackview.height,
"outline_what", (guint32) 0,
"outline_color_rgba", color_map[cGhostTrackBaseOutline],
"fill_color_rgba", color_map[cGhostTrackBaseFill],
NULL);
gtk_canvas_item_lower_to_bottom (group);
atv.add_ghost (this);
}
GhostRegion::~GhostRegion ()
{
GoingAway (this);
gtk_object_destroy (GTK_OBJECT(group));
}
void
GhostRegion::set_samples_per_unit (double spu)
{
for (vector<GtkCanvasItem*>::iterator i = waves.begin(); i != waves.end(); ++i) {
gtk_canvas_item_set ((*i), "samples_per_unit", spu, NULL);
}
}
void
GhostRegion::set_duration (double units)
{
gtk_canvas_item_set (base_rect, "x2", units, NULL);
}
void
GhostRegion::set_height ()
{
gdouble ht;
vector<GtkCanvasItem*>::iterator i;
uint32_t n;
gtk_canvas_item_set (base_rect, "y2", (double) trackview.height, NULL);
ht = ((trackview.height) / (double) waves.size());
for (n = 0, i = waves.begin(); i != waves.end(); ++i, ++n) {
gdouble yoff = n * ht;
gtk_canvas_item_set ((*i), "height", ht, "y", yoff, NULL);
}
}

47
gtk2_ardour/ghostregion.h Normal file
View File

@@ -0,0 +1,47 @@
/*
Copyright (C) 2004 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id$
*/
#ifndef __ardour_gtk_ghost_region_h__
#define __ardour_gtk_ghost_region_h__
#include <vector>
#include <sigc++/signal_system.h>
#include <gtk-canvas.h>
class AutomationTimeAxisView;
struct GhostRegion : public SigC::Object
{
AutomationTimeAxisView& trackview;
GtkCanvasItem* group;
GtkCanvasItem* base_rect;
std::vector<GtkCanvasItem*> waves;
GhostRegion (AutomationTimeAxisView& tv, double initial_unit_pos);
~GhostRegion ();
void set_samples_per_unit (double spu);
void set_duration (double units);
void set_height ();
SigC::Signal1<void,GhostRegion*> GoingAway;
};
#endif /* __ardour_gtk_ghost_region_h__ */

Some files were not shown because too many files have changed in this diff Show More