Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Srashti Mittal
purr-data
Commits
505f8c88
Commit
505f8c88
authored
Aug 16, 2020
by
Guillem Bartrina
Browse files
abstraction saving feature (squashed)
parent
cfb218c7
Changes
8
Hide whitespace changes
Inline
Side-by-side
pd/nw/locales/en/translation.json
View file @
505f8c88
...
...
@@ -285,6 +285,16 @@
"cancel"
:
"Cancel"
,
"cancel_tt"
:
"Don't save any changes, and don't close the patch"
},
"abstract_dialog"
:
{
"prompt"
:
"Would you like to turn the identical subpatches into abstractions?
\n
Candidates found in the subpatch tree, from root canvas: "
,
"note"
:
"Note: this can't be undone all at once – any changes made in subpatches can be undone from that subpatch"
,
"single"
:
"Only this one"
,
"single_tt"
:
"Replace the subpatch you just saved with the corresponding abstraction"
,
"all"
:
"All candidates"
,
"all_tt"
:
"Replace all subpatches in the subpatch tree identical to the one you just saved with the corresponding abstraction"
,
"none"
:
"None"
,
"none_tt"
:
"Do not replace any subpatch"
},
"find"
:
{
"placeholder"
:
"Search in Canvas"
,
"search"
:
"Search"
,
...
...
@@ -294,6 +304,7 @@
"menu"
:
{
"props"
:
"Properties"
,
"open"
:
"Open"
,
"saveas"
:
"Save as"
,
"help"
:
"Help"
,
"front"
:
"Bring to Front"
,
"back"
:
"Send to Back"
...
...
pd/nw/pd_canvas.html
View file @
505f8c88
...
...
@@ -77,6 +77,30 @@
<span
data-i18n=
"canvas.save_dialog.cancel"
></span>
</button>
</div>
</dialog>
<dialog
id=
"abstract_dialog"
>
<h4><span
style=
"white-space: pre-line"
data-i18n=
"canvas.abstract_dialog.prompt"
></span>
<span
id=
"abstract_dialog_candidates"
></span>
</h4>
<h5>
<span
data-i18n=
"canvas.abstract_dialog.note"
></span>
</h5>
<div
class=
"abstract_submit_buttons"
>
<button
type=
"button"
id=
"abstract_single_button"
data-i18n=
"[title]canvas.abstract_dialog.single_tt"
>
<span
data-i18n=
"canvas.abstract_dialog.single"
></span>
</button>
<button
type=
"button"
id=
"abstract_all_button"
data-i18n=
"[title]canvas.abstract_dialog.all_tt"
>
<span
data-i18n=
"canvas.abstract_dialog.all"
></span>
</button>
<button
type=
"button"
id=
"abstract_none_button"
data-i18n=
"[title]canvas.abstract_dialog.none_tt"
>
<span
data-i18n=
"canvas.abstract_dialog.none"
></span>
</button>
</div>
</dialog>
<div
id=
"hscroll"
style=
"background-color: rgba(0, 0, 0, 0.267); position: fixed; left: 0px; bottom: 0px; border-radius: 0px; width: 10px; height: 5px; visibility: hidden;"
></div>
<div
id=
"vscroll"
style=
"background-color: rgba(0, 0, 0, 0.267); position: fixed; right: 0px; top: 0px; border-radius: 0px; width: 5px; height: 10px; visibility: hidden;"
></div>
...
...
pd/nw/pd_canvas.js
View file @
505f8c88
...
...
@@ -1357,6 +1357,12 @@ function create_popup_menu(name) {
pdgui
.
popup_action
(
name
,
1
);
}
}));
popup_menu
.
append
(
new
gui
.
MenuItem
({
label
:
l
(
"
canvas.menu.saveas
"
),
click
:
function
()
{
pdgui
.
popup_action
(
name
,
5
);
}
}));
popup_menu
.
append
(
new
gui
.
MenuItem
({
label
:
l
(
"
canvas.menu.help
"
),
click
:
function
()
{
...
...
pd/nw/pdgui.js
View file @
505f8c88
...
...
@@ -1185,6 +1185,48 @@ function gui_canvas_menuclose(cid_for_dialog, cid, force) {
},
450
);
}
function
canvas_abstract_callback
(
cid_for_dialog
,
cid
,
matches
)
{
var
nw
=
patchwin
[
cid_for_dialog
],
w
=
nw
.
window
,
doc
=
w
.
document
,
dialog
=
doc
.
getElementById
(
"
abstract_dialog
"
),
dialog_candidates
=
doc
.
getElementById
(
"
abstract_dialog_candidates
"
),
single_button
=
doc
.
getElementById
(
"
abstract_single_button
"
),
all_button
=
doc
.
getElementById
(
"
abstract_all_button
"
),
none_button
=
doc
.
getElementById
(
"
abstract_none_button
"
);
dialog_candidates
.
textContent
=
matches
.
toString
();
dialog_candidates
.
title
=
matches
.
toString
()
all_button
.
disabled
=
(
matches
===
1
);
single_button
.
onclick
=
function
()
{
dialog
.
close
();
w
.
canvas_events
[
w
.
canvas_events
.
get_previous_state
()]();
pdsend
(
cid
,
"
dialog
"
,
0
);
};
all_button
.
onclick
=
function
()
{
dialog
.
close
();
w
.
canvas_events
[
w
.
canvas_events
.
get_previous_state
()]();
pdsend
(
cid
,
"
dialog
"
,
1
);
};
none_button
.
onclick
=
function
()
{
dialog
.
close
();
w
.
canvas_events
[
w
.
canvas_events
.
get_previous_state
()]();
}
w
.
canvas_events
.
none
();
w
.
setTimeout
(
function
()
{
dialog
.
showModal
();
},
150
);
}
function
gui_canvas_abstract
(
cid_for_dialog
,
cid
,
matches
)
{
setTimeout
(
function
()
{
canvas_abstract_callback
(
cid_for_dialog
,
cid
,
matches
);
},
450
);
}
function
gui_quit_dialog
()
{
gui_raise_pd_window
();
var
reply
=
pd_window
.
window
.
confirm
(
"
Really quit?
"
);
...
...
@@ -4885,7 +4927,7 @@ function zoom_kludge(zoom_level) {
return
zfactor
;
}
function
gui_canvas_popup
(
cid
,
xpos
,
ypos
,
canprop
,
canopen
,
isobject
)
{
function
gui_canvas_popup
(
cid
,
xpos
,
ypos
,
canprop
,
canopen
,
cansaveas
,
isobject
)
{
// Get page coords for top of window, in case we're scrolled
gui
(
cid
).
get_nw_window
(
function
(
nw_win
)
{
// ico@vt.edu updated win_left and win_top for the 0.46.2
...
...
@@ -4908,6 +4950,7 @@ function gui_canvas_popup(cid, xpos, ypos, canprop, canopen, isobject) {
//popup_coords[1] = ypos;
popup_menu
[
cid
].
items
[
0
].
enabled
=
canprop
;
popup_menu
[
cid
].
items
[
1
].
enabled
=
canopen
;
popup_menu
[
cid
].
items
[
2
].
enabled
=
cansaveas
;
// We'll use "isobject" to enable/disable "To Front" and "To Back"
//isobject;
...
...
pd/src/g_editor.c
View file @
505f8c88
...
...
@@ -2179,6 +2179,246 @@ void canvas_undo_font(t_canvas *x, void *z, int action)
}
}
/* ------------------------------- abstract feature --------------------- */
static
t_class
*
abstracthandler_class
;
typedef
struct
abstracthandler
{
t_object
x_obj
;
t_symbol
*
sym
;
/* symbol bound to the object */
t_canvas
*
dialog
;
/* canvas where the dialog will be displayed */
t_canvas
*
tarjet
;
/* tarjet subpatch */
char
*
path
;
/* abstraction path */
t_binbuf
*
subpatch
;
/* subpatch contents */
}
t_abstracthandler
;
static
void
*
abstracthandler_new
(
void
)
{
t_abstracthandler
*
x
=
(
t_abstracthandler
*
)
pd_new
(
abstracthandler_class
);
char
namebuf
[
80
];
sprintf
(
namebuf
,
"ah%lx"
,
(
t_int
)
x
);
x
->
sym
=
gensym
(
namebuf
);
pd_bind
(
&
x
->
x_obj
.
ob_pd
,
x
->
sym
);
return
(
x
);
}
static
void
abstracthandler_free
(
t_abstracthandler
*
x
)
{
freebytes
(
x
->
path
,
MAXPDSTRING
);
binbuf_free
(
x
->
subpatch
);
pd_unbind
(
&
x
->
x_obj
.
ob_pd
,
x
->
sym
);
}
/* gobj_activate, canvas_addtobuf and canvas_buftotex toghether and simplified*/
static
void
do_rename_light
(
t_gobj
*
z
,
t_glist
*
glist
,
const
char
*
text
)
{
t_rtext
*
y
=
glist_findrtext
(
glist
,
(
t_text
*
)
z
);
glist
->
gl_editor
->
e_textedfor
=
y
;
char
*
buf
=
getbytes
(
strlen
(
text
)
+
1
);
strcpy
(
buf
,
text
);
rtext_settext
(
y
,
buf
,
strlen
(
text
)
+
1
);
glist
->
gl_editor
->
e_textdirty
=
1
;
canvas_dirty
(
glist
,
1
);
glist
->
gl_editor
->
e_onmotion
=
MA_NONE
;
//necessary?
}
/* traverses the whole subtree of the given canvas/patch, replacing all subpatches identical to the
given one with an abstraction */
static
int
do_replace_subpatches
(
t_canvas
*
x
,
const
char
*
label
,
t_binbuf
*
original
)
{
t_selection
*
list
=
0
;
int
edi
=
0
,
num
=
0
;
/* editor is needed in order to do the operations below */
if
(
label
&&
!
x
->
gl_editor
)
{
canvas_create_editor
(
x
);
edi
=
1
;
}
t_gobj
*
y
,
*
yn
;
canvas_undo_add
(
x
,
UNDO_SEQUENCE_START
,
"replace"
,
"subpatch replacements have been redone. "
"All other possible replacements within other (sub)patches have not been affected"
);
for
(
y
=
x
->
gl_list
;
y
;
y
=
yn
)
{
yn
=
y
->
g_next
;
/* dirty hack,
'canvas_stowconnections' inside 'glist_deselect'
rearranges the glist */
if
(
pd_class
(
&
y
->
g_pd
)
==
canvas_class
&&
!
canvas_isabstraction
((
t_canvas
*
)
y
))
{
t_binbuf
*
tmp
=
binbuf_new
(),
*
tmps
=
binbuf_new
();
gobj_save
((
t_gobj
*
)
y
,
tmp
);
int
i
=
0
,
j
=
binbuf_getnatom
(
tmp
)
-
2
;
t_atom
*
v
=
binbuf_getvec
(
tmp
);
while
(
v
[
i
].
a_type
!=
A_SEMI
)
i
++
;
i
++
;
while
(
v
[
j
].
a_type
!=
A_SEMI
)
j
--
;
binbuf_restore
(
tmps
,
j
-
i
+
1
,
v
+
i
);
binbuf_free
(
tmp
);
if
(
binbuf_match
(
original
,
tmps
,
0
)
&&
binbuf_getnatom
(
original
)
==
binbuf_getnatom
(
tmps
))
{
if
(
label
)
{
binbuf_free
(
tmps
);
glist_noselect
(
x
);
glist_select
(
x
,
y
);
do_rename_light
(
y
,
x
,
label
);
glist_deselect
(
x
,
y
);
}
else
num
++
;
}
else
{
binbuf_free
(
tmps
);
/* all the non-matching subpatches are stored in a list, */
t_selection
*
new
=
(
t_selection
*
)
getbytes
(
sizeof
(
t_selection
));
new
->
sel_what
=
y
;
new
->
sel_next
=
list
;
list
=
new
;
}
}
}
canvas_undo_add
(
x
,
UNDO_SEQUENCE_END
,
"replace"
,
"subpatch replacements have been undone. "
"All other possible replacements within other (sub)patches have not been affected"
);
if
(
edi
)
canvas_destroy_editor
(
x
);
t_selection
*
z
,
*
zn
;
/* the function is called recursively on each non-matching canvas.
this has been left for last due to a visual bug that happens if
they are explored as soon as they are traversed*/
for
(
z
=
list
;
z
;
z
=
zn
)
{
zn
=
z
->
sel_next
;
num
+=
do_replace_subpatches
((
t_canvas
*
)
z
->
sel_what
,
label
,
original
);
freebytes
(
z
,
sizeof
(
t_selection
));
}
return
num
;
}
static
void
abstracthandler_callback
(
t_abstracthandler
*
x
,
t_symbol
*
s
)
{
char
fullpath
[
MAXPDSTRING
],
label
[
MAXPDSTRING
],
*
dir
,
*
filename
,
*
o
=
s
->
s_name
;
memset
(
fullpath
,
'\0'
,
MAXPDSTRING
);
memset
(
label
,
'\0'
,
MAXPDSTRING
);
sys_unbashfilename
(
s
->
s_name
,
fullpath
);
if
(
strlen
(
fullpath
)
<
3
||
strcmp
(
fullpath
+
strlen
(
fullpath
)
-
3
,
".pd"
))
strcat
(
fullpath
,
".pd"
);
filename
=
strrchr
(
fullpath
,
'/'
)
+
1
;
fullpath
[(
int
)
filename
-
(
int
)
fullpath
-
1
]
=
'\0'
;
dir
=
fullpath
;
int
flag
,
prefix
=
0
;
if
(
flag
=
sys_relativizepath
(
canvas_getdir
(
canvas_getrootfor
(
x
->
tarjet
))
->
s_name
,
dir
,
label
))
{
int
len
=
strlen
(
label
),
creator
,
fd
=
-
1
;
if
(
len
&&
label
[
len
-
1
]
!=
'/'
)
label
[
len
]
=
'/'
;
strncat
(
label
,
filename
,
strlen
(
filename
)
-
3
);
/* check if there is a creator with the same name or if it's one of the built-in methods */
t_symbol
*
sym
=
gensym
(
label
);
creator
=
(
sym
==
&
s_bang
||
sym
==
&
s_float
||
sym
==
&
s_symbol
||
sym
==
&
s_blob
||
sym
==
&
s_list
||
sym
==
&
s_anything
||
zgetfn
(
&
pd_objectmaker
,
sym
));
if
(
!
len
&&
creator
)
{
prefix
=
1
;
creator
=
0
;
}
/* check if there in an abstraction with the same name in the search path */
if
(
!
creator
)
{
char
opendir
[
MAXPDSTRING
],
*
filenameptr
;
fd
=
canvas_open
(
canvas_getrootfor
(
x
->
tarjet
),
label
,
".pd"
,
opendir
,
&
filenameptr
,
MAXPDSTRING
,
0
);
//high load
if
(
fd
>
0
)
{
sys_close
(
fd
);
/* check if we are overwriting the file */
if
(
!
strncmp
(
dir
,
opendir
,
(
int
)
filenameptr
-
(
int
)
opendir
-
1
))
fd
=
-
1
;
}
}
flag
=
!
(
creator
||
(
fd
>
0
));
if
(
flag
&&
prefix
)
{
strcpy
(
label
,
"./"
);
strncat
(
label
,
filename
,
strlen
(
filename
)
-
3
);
}
else
if
(
!
flag
)
post
(
"warning: couldn't use relative path, there is a coincidence in the creator list or the search path"
);
}
if
(
!
flag
)
/* absolute path is required */
{
memset
(
label
,
'\0'
,
MAXPDSTRING
);
strcpy
(
label
,
dir
);
strcat
(
label
,
"/"
);
strncat
(
label
,
filename
,
strlen
(
filename
)
-
3
);
/* should check if 'filename' is one of the built-in special methods
in order to inform the user about the nameclash problem */
}
x
->
path
=
(
char
*
)
getbytes
(
MAXPDSTRING
);
strcpy
(
x
->
path
,
label
);
/* save the subpatch into a separated pd file */
t_atom
at
[
3
];
SETSYMBOL
(
at
,
gensym
(
filename
));
SETSYMBOL
(
at
+
1
,
gensym
(
dir
));
SETFLOAT
(
at
+
2
,
0
.
f
);
x
->
tarjet
->
gl_env
=
0xF1A6
;
/* gl_env is set to non-zero in order to save the subcanvas as a root canvas */
typedmess
(
&
x
->
tarjet
->
gl_pd
,
gensym
(
"savetofile"
),
3
,
at
);
x
->
tarjet
->
gl_env
=
0
;
t_binbuf
*
tmp
=
binbuf_new
(),
*
tmps
=
binbuf_new
();
gobj_save
((
t_gobj
*
)
x
->
tarjet
,
tmp
);
/* only the internals are kept, the position on the parent canvas may differ */
int
i
=
0
,
j
=
binbuf_getnatom
(
tmp
)
-
2
,
matches
;
t_atom
*
v
=
binbuf_getvec
(
tmp
);
while
(
v
[
i
].
a_type
!=
A_SEMI
)
i
++
;
i
++
;
while
(
v
[
j
].
a_type
!=
A_SEMI
)
j
--
;
binbuf_restore
(
tmps
,
j
-
i
+
1
,
v
+
i
);
binbuf_free
(
tmp
);
matches
=
do_replace_subpatches
(
canvas_getrootfor
(
x
->
tarjet
),
0
,
tmps
);
x
->
subpatch
=
tmps
;
/* trigger the frontend dialog for replacing options */
gui_vmess
(
"gui_canvas_abstract"
,
"xsi"
,
x
->
dialog
,
x
->
sym
->
s_name
,
matches
);
}
static
void
abstracthandler_dialog
(
t_abstracthandler
*
x
,
t_floatarg
val
)
{
if
(
x
->
tarjet
==
x
->
dialog
)
canvas_vis
(
x
->
dialog
,
0
);
t_canvas
*
owner
=
x
->
tarjet
->
gl_owner
,
*
root
=
canvas_getrootfor
(
x
->
tarjet
);
int
all
=
val
;
if
(
!
all
)
{
/* change the text of the subpatch object to create the abstraction,
emulating the procedure done by the user. could be simplified */
int
edi
=
0
;
if
(
!
owner
->
gl_editor
)
{
canvas_create_editor
(
owner
);
edi
=
1
;
}
glist_noselect
(
owner
);
glist_select
(
owner
,
x
->
tarjet
);
do_rename_light
(
x
->
tarjet
,
owner
,
x
->
path
);
glist_deselect
(
owner
,
x
->
tarjet
);
if
(
edi
)
canvas_destroy_editor
(
owner
);
/* select '[args]' slice
canvas_editmode(owner, 1);
t_gobj *abst = glist_nth(owner, glist_getindex(owner, 0)-1);
int len = strlen(x->path);
glist_select(owner, abst);
gobj_activate(abst, owner, (0b1 << 31) | (((len+1) & 0x7FFF) << 16) | ((len+7) & 0xFFFF)); */
}
else
{
do_replace_subpatches
(
root
,
x
->
path
,
x
->
subpatch
);
}
pd_free
(
&
x
->
x_obj
.
ob_pd
);
}
void
abstracthandler_setup
(
void
)
{
abstracthandler_class
=
class_new
(
gensym
(
"abstracthandler"
),
0
,
abstracthandler_free
,
sizeof
(
t_abstracthandler
),
CLASS_NOINLET
,
0
);
class_addmethod
(
abstracthandler_class
,
(
t_method
)
abstracthandler_callback
,
gensym
(
"callback"
),
A_SYMBOL
,
0
);
class_addmethod
(
abstracthandler_class
,
(
t_method
)
abstracthandler_dialog
,
gensym
(
"dialog"
),
A_FLOAT
,
0
);
}
/* ------------------------ event handling ------------------------ */
static
char
*
cursorlist
[]
=
{
...
...
@@ -2271,7 +2511,7 @@ static void canvas_rightclick(t_canvas *x, int xpos, int ypos, t_gobj *y_sel)
{
//fprintf(stderr,"e_onmotion=%d\n",x->gl_editor->e_onmotion);
if
(
x
->
gl_editor
->
e_onmotion
!=
MA_NONE
)
return
;
int
canprop
,
canopen
,
isobject
;
int
canprop
,
canopen
,
isobject
,
cansaveas
;
t_gobj
*
y
=
NULL
;
int
x1
,
y1
,
x2
,
y2
,
scalar_has_canvas
=
0
;
if
(
x
->
gl_editor
->
e_selection
)
...
...
@@ -2328,12 +2568,19 @@ static void canvas_rightclick(t_canvas *x, int xpos, int ypos, t_gobj *y_sel)
// LATER: consider enabling help and perhaps even limited properties...
return
;
}
gui_vmess
(
"gui_canvas_popup"
,
"xiiiii"
,
/* saveas option, only if it's a canvas and it isn't an abstraction */
cansaveas
=
(
canopen
&&
pd_class
(
&
y
->
g_pd
)
==
canvas_class
&&
!
canvas_isabstraction
((
t_canvas
*
)
y
));
/* or if it is the background of a subpatch */
cansaveas
=
(
cansaveas
||
(
!
y
&&
canvas_getrootfor
(
x
)
!=
x
&&
!
canvas_isabstraction
((
t_canvas
*
)
x
)));
gui_vmess
(
"gui_canvas_popup"
,
"xiiiiii"
,
x
,
xpos
,
ypos
,
canprop
,
canopen
,
cansaveas
,
isobject
);
}
...
...
@@ -3078,6 +3325,22 @@ void canvas_done_popup(t_canvas *x, t_float which, t_float xpos,
vmess
(
&
y
->
g_pd
,
gensym
(
"menu-open"
),
""
);
return
;
}
else
if
(
which
==
5
)
/* saveas */
{
t_abstracthandler
*
ah
=
abstracthandler_new
();
ah
->
tarjet
=
y
;
ah
->
dialog
=
x
;
char
buf
[
MAXPDSTRING
];
sprintf
(
buf
,
"%s/%s.pd"
,
canvas_getdir
(
canvas_getrootfor
(
y
))
->
s_name
,
((
t_canvas
*
)
y
)
->
gl_name
->
s_name
);
gui_vmess
(
"gui_savepanel"
,
"xss"
,
x
,
ah
->
sym
->
s_name
,
buf
);
return
;
}
else
if
(
which
==
2
)
/* help */
{
char
*
dir
;
...
...
@@ -3146,6 +3409,21 @@ void canvas_done_popup(t_canvas *x, t_float which, t_float xpos,
}
else
if
(
which
==
2
)
open_via_helppath
(
"intro.pd"
,
canvas_getdir
((
t_canvas
*
)
x
)
->
s_name
);
if
(
which
==
5
)
{
t_abstracthandler
*
ah
=
abstracthandler_new
();
ah
->
tarjet
=
x
;
ah
->
dialog
=
x
;
char
buf
[
MAXPDSTRING
];
sprintf
(
buf
,
"%s/%s.pd"
,
canvas_getdir
(
canvas_getrootfor
(
x
))
->
s_name
,
((
t_canvas
*
)
x
)
->
gl_name
->
s_name
);
gui_vmess
(
"gui_savepanel"
,
"xss"
,
x
,
ah
->
sym
->
s_name
,
buf
);
}
}
extern
t_class
*
my_canvas_class
;
// for ignoring runtime clicks and resizing
...
...
@@ -7815,6 +8093,8 @@ void g_editor_setup(void)
gensym("
disconnect
"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
/* -------------- copy buffer ------------------ */
copy_binbuf = binbuf_new();
abstracthandler_setup();
}
void canvas_editor_for_class(t_class *c)
...
...
pd/src/g_rtext.c
View file @
505f8c88
...
...
@@ -587,6 +587,10 @@ void rtext_activate(t_rtext *x, int state)
glist
->
gl_editor
->
e_textedfor
=
0
;
x
->
x_active
=
0
;
}
/* check if it has a window */
if
(
!
glist
->
gl_havewindow
)
return
;
rtext_senditup
(
x
,
SEND_UPDATE
,
&
w
,
&
h
,
&
indx
);
/* hack...
state = 0 no editing
...
...
pd/src/g_undo.c
View file @
505f8c88
...
...
@@ -110,6 +110,7 @@ void canvas_undo_undo(t_canvas *x)
if
(
UNDO_SEQUENCE_END
==
x
->
u_last
->
type
)
{
int
sequence_depth
=
1
;
if
(
x
->
u_last
->
data
)
post
(
"undo info: %s"
,
(
char
*
)
x
->
u_last
->
data
);
while
((
x
->
u_last
=
x
->
u_last
->
prev
)
&&
(
UNDO_INIT
!=
x
->
u_last
->
type
))
{
...
...
@@ -120,6 +121,7 @@ void canvas_undo_undo(t_canvas *x)
break
;
case
UNDO_SEQUENCE_END
:
sequence_depth
++
;
if
(
x
->
u_last
->
data
)
post
(
"undo info: %s"
,
(
char
*
)
x
->
u_last
->
data
);
break
;
default:
canvas_undo_doit
(
x
,
x
->
u_last
,
UNDO_UNDO
);
...
...
@@ -176,6 +178,7 @@ void canvas_undo_redo(t_canvas *x)
if
(
UNDO_SEQUENCE_START
==
x
->
u_last
->
type
)
{
int
sequence_depth
=
1
;
if
(
x
->
u_last
->
data
)
post
(
"redo info: %s"
,
(
char
*
)
x
->
u_last
->
data
);
while
(
x
->
u_last
->
next
&&
(
x
->
u_last
=
x
->
u_last
->
next
))
{
switch
(
x
->
u_last
->
type
)
...
...
@@ -185,6 +188,7 @@ void canvas_undo_redo(t_canvas *x)
break
;
case
UNDO_SEQUENCE_START
:
sequence_depth
++
;
if
(
x
->
u_last
->
data
)
post
(
"redo info: %s"
,
(
char
*
)
x
->
u_last
->
data
);
break
;
default:
canvas_undo_doit
(
x
,
x
->
u_last
,
UNDO_REDO
);
...
...
pd/src/s_path.c
View file @
505f8c88
...
...
@@ -195,6 +195,60 @@ int sys_isabsolutepath(const char *dir)
}
}
int
sys_relativizepath
(
const
char
*
from
,
const
char
*
to
,
char
*
result
)
{
char
fromext
[
FILENAME_MAX
];
sys_unbashfilename
(
from
,
fromext
);
char
toext
[
FILENAME_MAX
];
sys_unbashfilename
(
to
,
toext
);
int
i
=
0
,
j
;
while
(
fromext
[
i
]
&&
toext
[
i
]
&&
fromext
[
i
]
==
toext
[
i
])
i
++
;
if
(
!
i
)
return
0
;
j
=
i
;
if
(
fromext
[
i
])
while
(
i
>
0
&&
fromext
[
i
]
!=
'/'
)
i
--
;
if
(
toext
[
j
])
while
(
j
>
0
&&
toext
[
j
]
!=
'/'
)
j
--
;
if
(
fromext
[
i
])
{
int
k
=
0
;
while
(
fromext
[
i
])
{
if
(
fromext
[
i
]
==
'/'
)
{
if
(
k
==
0
)
{
strcpy
(
result
+
k
,
".."
);
k
+=
2
;
}
else
{
strcpy
(
result
+
k
,
"/.."
);
k
+=
3
;
}
}
i
++
;
}
if
(
toext
[
j
])
{
result
[
k
]
=
'/'
;
strcpy
(
result
+
k
+
1
,
toext
+
j
+
1
);
}
}
else
if
(
!
fromext
[
i
]
&&
toext
[
j
])
{
strcpy
(
result
,
toext
+
j
+
1
);
}
else
{
strcpy
(
result
,
""
);
}
return
1
;
}
/******************* Utility functions used below ******************/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment