summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Merry <dev@randomguy3.me.uk>2013-03-26 12:54:41 +0000
committerAlex Merry <dev@randomguy3.me.uk>2013-03-26 12:54:41 +0000
commit3bfdc232f22f0fa5be20e0b603a8287626ec0c2f (patch)
treee54537047ac72238bc4eb2cd467d12e3a48b6939
parent0f969b6ced7e9ebcbe4bc4e17867ff32d67f27bb (diff)
Add edge anchor editing to GTK port
Includes functions for testing if an anchor is valid.
-rw-r--r--tikzit/src/common/NSString+Tikz.h3
-rw-r--r--tikzit/src/common/NSString+Tikz.m7
-rw-r--r--tikzit/src/common/TikzGraphAssembler.h10
-rw-r--r--tikzit/src/common/TikzGraphAssembler.m39
-rw-r--r--tikzit/src/gtk/PropertiesPane.h2
-rw-r--r--tikzit/src/gtk/PropertiesPane.m127
-rw-r--r--tikzit/src/gtk/PropertyListEditor.m6
7 files changed, 179 insertions, 15 deletions
diff --git a/tikzit/src/common/NSString+Tikz.h b/tikzit/src/common/NSString+Tikz.h
index 639e269..ea6ea40 100644
--- a/tikzit/src/common/NSString+Tikz.h
+++ b/tikzit/src/common/NSString+Tikz.h
@@ -19,7 +19,8 @@
@interface NSString (Tikz)
- (NSString*) tikzEscapedString;
- - (BOOL) isValidTikz;
+ - (BOOL) isValidTikzPropertyNameOrValue;
+ - (BOOL) isValidAnchor;
@end
// vi:ft=objc:noet:ts=4:sts=4:sw=4
diff --git a/tikzit/src/common/NSString+Tikz.m b/tikzit/src/common/NSString+Tikz.m
index 8b11ad2..520ffd3 100644
--- a/tikzit/src/common/NSString+Tikz.m
+++ b/tikzit/src/common/NSString+Tikz.m
@@ -16,6 +16,7 @@
*/
#import "NSString+Tikz.h"
+#import "TikzGraphAssembler.h"
@implementation NSString (Tikz)
@@ -31,7 +32,7 @@
}
}
-- (BOOL) isValidTikz {
+- (BOOL) isValidTikzPropertyNameOrValue {
NSUInteger length = [self length];
unsigned int brace_depth = 0;
unsigned int escape = 0;
@@ -53,6 +54,10 @@
return !escape && brace_depth == 0;
}
+- (BOOL) isValidAnchor {
+ return [TikzGraphAssembler validateTikzEdgeAnchor:self];
+}
+
@end
// vi:ft=objc:noet:ts=4:sts=4:sw=4
diff --git a/tikzit/src/common/TikzGraphAssembler.h b/tikzit/src/common/TikzGraphAssembler.h
index c365128..3403969 100644
--- a/tikzit/src/common/TikzGraphAssembler.h
+++ b/tikzit/src/common/TikzGraphAssembler.h
@@ -100,6 +100,16 @@
*/
+ (BOOL)validateTikzPropertyNameOrValue:(NSString*)tikz;
+/**
+ * Validate an edge anchor
+ *
+ * Checks that the given string will successfully lex if used as an anchor for
+ * and edge
+ * @param tikz the string to validate
+ * @return YES if the string can be used as an edge anchor, NO otherwise
+ */
++ (BOOL)validateTikzEdgeAnchor:(NSString*)tikz;
+
@end
// vi:ft=objc:noet:ts=4:sts=4:sw=4
diff --git a/tikzit/src/common/TikzGraphAssembler.m b/tikzit/src/common/TikzGraphAssembler.m
index c49298f..6b191a2 100644
--- a/tikzit/src/common/TikzGraphAssembler.m
+++ b/tikzit/src/common/TikzGraphAssembler.m
@@ -113,21 +113,44 @@
}
+ (BOOL)validateTikzPropertyNameOrValue:(NSString*)tikz {
- BOOL r;
-
- NSString * testTikz = [NSString stringWithFormat: @"{%@}", tikz];
-
+ BOOL valid;
+
+ NSString * testTikz = [NSString stringWithFormat: @"{%@}", tikz];
+
void *scanner;
yylex_init (&scanner);
yyset_extra(nil, scanner);
yy_scan_string([testTikz UTF8String], scanner);
YYSTYPE lval;
YYLTYPE lloc;
- yylex(&lval, &lloc, scanner);
- r = !(yyget_leng(scanner) < [testTikz length]);
+ int result = yylex(&lval, &lloc, scanner);
+ valid = (result == DELIMITEDSTRING) &&
+ (yyget_leng(scanner) == [testTikz length]);
yylex_destroy(scanner);
-
- return r;
+
+ return valid;
+}
+
++ (BOOL)validateTikzEdgeAnchor:(NSString*)tikz {
+ BOOL valid = YES;
+
+ NSString * testTikz = [NSString stringWithFormat: @"(1.%@)", tikz];
+
+ void *scanner;
+ yylex_init (&scanner);
+ yyset_extra(nil, scanner);
+ yy_scan_string([testTikz UTF8String], scanner);
+ YYSTYPE lval;
+ YYLTYPE lloc;
+ valid = valid && (yylex(&lval, &lloc, scanner) == LEFTPARENTHESIS);
+ valid = valid && (yylex(&lval, &lloc, scanner) == REFSTRING);
+ valid = valid && (yylex(&lval, &lloc, scanner) == FULLSTOP);
+ valid = valid && (yylex(&lval, &lloc, scanner) == REFSTRING);
+ valid = valid && (yylex(&lval, &lloc, scanner) == RIGHTPARENTHESIS);
+ valid = valid && (lloc.last_column == [testTikz length]);
+ yylex_destroy(scanner);
+
+ return valid;
}
@end
diff --git a/tikzit/src/gtk/PropertiesPane.h b/tikzit/src/gtk/PropertiesPane.h
index bde4424..c76efae 100644
--- a/tikzit/src/gtk/PropertiesPane.h
+++ b/tikzit/src/gtk/PropertiesPane.h
@@ -53,6 +53,8 @@
GtkToggleButton *edgeNodeToggle;
GtkWidget *edgeNodePropsWidget;
GtkEntry *edgeNodeLabelEntry;
+ GtkEntry *edgeSourceAnchorEntry;
+ GtkEntry *edgeTargetAnchorEntry;
}
@property (retain) TikzDocument *document;
diff --git a/tikzit/src/gtk/PropertiesPane.m b/tikzit/src/gtk/PropertiesPane.m
index c42dded..ba43298 100644
--- a/tikzit/src/gtk/PropertiesPane.m
+++ b/tikzit/src/gtk/PropertiesPane.m
@@ -33,6 +33,8 @@ static GtkWidget *createBoldLabel (const gchar *text);
static void node_label_changed_cb (GtkEditable *widget, PropertiesPane *pane);
static void edge_node_label_changed_cb (GtkEditable *widget, PropertiesPane *pane);
static void edge_node_toggled_cb (GtkToggleButton *widget, PropertiesPane *pane);
+static void edge_source_anchor_changed_cb (GtkEditable *widget, PropertiesPane *pane);
+static void edge_target_anchor_changed_cb (GtkEditable *widget, PropertiesPane *pane);
// }}}
@interface PropertiesPane (Notifications)
@@ -42,6 +44,8 @@ static void edge_node_toggled_cb (GtkToggleButton *widget, PropertiesPane *pane)
- (void) nodeLabelEdited:(NSString*)newValue;
- (void) edgeNodeLabelEdited:(NSString*)newValue;
- (void) edgeNodeToggled:(BOOL)newValue;
+- (BOOL) edgeSourceAnchorEdited:(NSString*)newValue;
+- (BOOL) edgeTargetAnchorEdited:(NSString*)newValue;
@end
@interface PropertiesPane (Private)
@@ -186,6 +190,45 @@ static void edge_node_toggled_cb (GtkToggleButton *widget, PropertiesPane *pane)
split,
FALSE, FALSE, 0);
+ GtkWidget *anchorTable = gtk_table_new (2, 2, FALSE);
+
+ label = gtk_label_new ("Source anchor:");
+ gtk_table_attach_defaults (GTK_TABLE (anchorTable), label,
+ 0, 1, 0, 1);
+ edgeSourceAnchorEntry = GTK_ENTRY (gtk_entry_new ());
+ g_object_ref_sink (edgeSourceAnchorEntry);
+ gtk_table_attach_defaults (GTK_TABLE (anchorTable),
+ GTK_WIDGET (edgeSourceAnchorEntry),
+ 1, 2, 0, 1);
+ g_signal_connect (G_OBJECT (edgeSourceAnchorEntry),
+ "changed",
+ G_CALLBACK (edge_source_anchor_changed_cb),
+ self);
+
+ label = gtk_label_new ("Target anchor:");
+ gtk_table_attach_defaults (GTK_TABLE (anchorTable), label,
+ 0, 1, 1, 2);
+ edgeTargetAnchorEntry = GTK_ENTRY (gtk_entry_new ());
+ g_object_ref_sink (edgeTargetAnchorEntry);
+ gtk_table_attach_defaults (GTK_TABLE (anchorTable),
+ GTK_WIDGET (edgeTargetAnchorEntry),
+ 1, 2, 1, 2);
+ g_signal_connect (G_OBJECT (edgeTargetAnchorEntry),
+ "changed",
+ G_CALLBACK (edge_target_anchor_changed_cb),
+ self);
+
+ gtk_widget_show_all (anchorTable);
+ gtk_box_pack_start (GTK_BOX (edgePropsWidget),
+ anchorTable,
+ FALSE, FALSE, 0);
+
+ split = gtk_hseparator_new ();
+ gtk_widget_show (split);
+ gtk_box_pack_start (GTK_BOX (edgePropsWidget),
+ split,
+ FALSE, FALSE, 0);
+
edgeNodeToggle = GTK_TOGGLE_BUTTON (gtk_check_button_new_with_label ("Child node"));
g_object_ref_sink (edgeNodeToggle);
gtk_widget_show (GTK_WIDGET (edgeNodeToggle));
@@ -229,6 +272,8 @@ static void edge_node_toggled_cb (GtkToggleButton *widget, PropertiesPane *pane)
g_object_unref (edgeNodeToggle);
g_object_unref (edgeNodePropsWidget);
g_object_unref (edgeNodeLabelEntry);
+ g_object_unref (edgeSourceAnchorEntry);
+ g_object_unref (edgeTargetAnchorEntry);
g_object_unref (layout);
@@ -325,7 +370,7 @@ static void edge_node_toggled_cb (GtkToggleButton *widget, PropertiesPane *pane)
return;
}
- if ([newValue isValidTikz]) {
+ if ([newValue isValidTikzPropertyNameOrValue]) {
Node *node = [sel anyObject];
[document startModifyNode:node];
[node setLabel:newValue];
@@ -351,7 +396,7 @@ static void edge_node_toggled_cb (GtkToggleButton *widget, PropertiesPane *pane)
return;
}
- if ([newValue isValidTikz]) {
+ if ([newValue isValidTikzPropertyNameOrValue]) {
[document startModifyEdge:edge];
[[edge edgeNode] setLabel:newValue];
[document endModifyEdge];
@@ -377,6 +422,48 @@ static void edge_node_toggled_cb (GtkToggleButton *widget, PropertiesPane *pane)
[document endModifyEdge];
}
+- (BOOL) edgeSourceAnchorEdited:(NSString*)newValue {
+ if (blockUpdates)
+ return YES;
+
+ NSSet *sel = [[document pickSupport] selectedEdges];
+ if ([sel count] != 1) {
+ NSLog(@"Expected single edge selected; got %lu", [sel count]);
+ return YES;
+ }
+
+ Edge *edge = [sel anyObject];
+ if ([newValue isValidAnchor]) {
+ [document startModifyEdge:edge];
+ [edge setSourceAnchor:newValue];
+ [document endModifyEdge];
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
+- (BOOL) edgeTargetAnchorEdited:(NSString*)newValue {
+ if (blockUpdates)
+ return YES;
+
+ NSSet *sel = [[document pickSupport] selectedEdges];
+ if ([sel count] != 1) {
+ NSLog(@"Expected single edge selected; got %lu", [sel count]);
+ return YES;
+ }
+
+ Edge *edge = [sel anyObject];
+ if ([newValue isValidAnchor]) {
+ [document startModifyEdge:edge];
+ [edge setTargetAnchor:newValue];
+ [document endModifyEdge];
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
@end
// }}}
// {{{ Private
@@ -419,6 +506,12 @@ static void edge_node_toggled_cb (GtkToggleButton *widget, PropertiesPane *pane)
Edge *e = [edgeSel anyObject];
[edgePropDelegate setEdge:e];
[edgeProps setData:[e data]];
+ gtk_entry_set_text (edgeSourceAnchorEntry,
+ [[e sourceAnchor] UTF8String]);
+ gtk_entry_set_text (edgeTargetAnchorEntry,
+ [[e targetAnchor] UTF8String]);
+ widget_clear_error (GTK_WIDGET (edgeSourceAnchorEntry));
+ widget_clear_error (GTK_WIDGET (edgeTargetAnchorEntry));
widget_clear_error (GTK_WIDGET (edgeNodeLabelEntry));
if ([e hasEdgeNode]) {
gtk_toggle_button_set_active (edgeNodeToggle, TRUE);
@@ -635,6 +728,36 @@ static void edge_node_toggled_cb (GtkToggleButton *toggle, PropertiesPane *pane)
[pool drain];
}
+static void edge_source_anchor_changed_cb (GtkEditable *editable, PropertiesPane *pane) {
+ if (!gtk_widget_is_sensitive (GTK_WIDGET (editable))) {
+ // clearly wasn't the user editing
+ return;
+ }
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSString *newValue = gtk_editable_get_string (editable, 0, -1);
+ if (![pane edgeSourceAnchorEdited:newValue])
+ widget_set_error (GTK_WIDGET (editable));
+
+ [pool drain];
+}
+
+static void edge_target_anchor_changed_cb (GtkEditable *editable, PropertiesPane *pane) {
+ if (!gtk_widget_is_sensitive (GTK_WIDGET (editable))) {
+ // clearly wasn't the user editing
+ return;
+ }
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSString *newValue = gtk_editable_get_string (editable, 0, -1);
+ if (![pane edgeTargetAnchorEdited:newValue])
+ widget_set_error (GTK_WIDGET (editable));
+
+ [pool drain];
+}
+
// }}}
// vim:ft=objc:ts=8:et:sts=4:sw=4:foldmethod=marker
diff --git a/tikzit/src/gtk/PropertyListEditor.m b/tikzit/src/gtk/PropertyListEditor.m
index 428050e..9760618 100644
--- a/tikzit/src/gtk/PropertyListEditor.m
+++ b/tikzit/src/gtk/PropertyListEditor.m
@@ -245,7 +245,7 @@ static void selection_changed_cb (GtkTreeSelection *selection,
@implementation PropertyListEditor (Private)
- (void) updatePath:(gchar*)pathStr withValue:(NSString*)newText {
- if (![newText isValidTikz])
+ if (![newText isValidTikzPropertyNameOrValue])
return;
GtkTreeIter iter;
@@ -276,7 +276,7 @@ static void selection_changed_cb (GtkTreeSelection *selection,
}
- (void) updatePath:(gchar*)pathStr withName:(NSString*)newText {
- if (![newText isValidTikz])
+ if (![newText isValidTikzPropertyNameOrValue])
return;
GtkTreeIter iter;
@@ -478,7 +478,7 @@ static void text_changed_cb (GtkEditable *editable, PropertyListEditor *pane)
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *newValue = gtk_editable_get_string (editable, 0, -1);
- if (![newValue isValidTikz]) {
+ if (![newValue isValidTikzPropertyNameOrValue]) {
widget_set_error (GTK_WIDGET (editable));
} else {
widget_clear_error (GTK_WIDGET (editable));