Alvaro, Kit Barnes, Eduardo de Barros Lima, Mathieu Bouchard,
Ole Joergen Broenner, Robert Buchholz, Vincenzo Ciancia, Luca de Cicco,
Michele Codutti, Robert Gerlach, Daniel German, Dirk Gerrits, Simon Guest,
-Lukasz Kaiser, Timo Kluck, David Kolibac, Danny Kukawka, Stefan Lembach,
-Bob McElrath, Andy Neitzke, David Planella, Marco Poletti, Alex Ray,
-Jean-Baptiste Rouquier, Victor Saase, Marco Souza, Mike Ter Louw,
+Lukasz Kaiser, Ian Woo Kim, Timo Kluck, David Kolibac, Danny Kukawka,
+Stefan Lembach, Bob McElrath, Andy Neitzke, David Planella, Marco Poletti,
+Alex Ray, Jean-Baptiste Rouquier, Victor Saase, Marco Souza, Mike Ter Louw,
Uwe Winter, Lu Zhihe.
(Let me know if you are missing from this list or if your name is
-This version:
+Version 0.4.7 (July 4, 2012):
- insert image tool (based on patches by Victor Saase and Simon Guest)
- renamed "Journal" menu to "Page"
- paste images and text directly from and to other applications
+ - lasso tool (based on patch by Ian Woo Kim)
Version 0.4.6 (May 22, 2012):
- win32 portability code (contributed by Dirk Gerrits)
-Version 0.4.6 (May 22, 2012)
-
-This release catches up with changes accumulated in the cvs repository.
+Version 0.4.7 (July 4, 2012)
Installation: see INSTALL
User's manual: see html-doc/manual.html
-Version 0.4.6 (May 22, 2012)
-
-This release catches up with changes accumulated in the cvs repository.
+Version 0.4.7 (July 4, 2012)
Installation: see INSTALL
User's manual: see html-doc/manual.html
dnl Process this file with autoconf to produce a configure script.
AC_INIT(configure.in)
-AM_INIT_AUTOMAKE(xournal, 0.4.6+image)
+AM_INIT_AUTOMAKE(xournal, 0.4.7)
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
Xournal User's Manual
</h2>
<p style="font-size: 0.95em; text-align: center; color: rgb(0,0,0)">
- Version 0.4.6
+ Version 0.4.7
</p>
<hr />
<p>
that the typesetting of the text may be slightly different in the
printout.
</p>
+<h3 class="subsub"> The image tool</h3>
+<p>
+ To insert a new image (from a file on disk), click at the location
+ where the upper-left corner is to be located. A file selection dialog
+ box pops up. Alternatively, images can be pasted directly from the
+ clipboard (without having to select the image tool). In both cases,
+ the newly inserted image is selected, and can be easily moved or resized
+ as with any selection.
+</p>
<h3 class="subsub"><img src="pixmaps/ruler.png"> The ruler</h3>
<p>
The ruler is not a tool by itself, but rather a special operating mode
or to a different journal) using the copy-paste toolbar buttons or the
corresponding entries of the Edit menu.
</p>
+<h3 class="subsub"><img src="pixmaps/lasso.png"> Lasso selection</h3>
+<p>
+ This tool lets you select an irregular shaped region of the current layer.
+ All the items which are entirely contained within the given region
+ are selected. As with the rectangle selection tool, the selection can be moved,
+ resized, copied and pasted.
+</p>
<h3 class="subsub"><img src="pixmaps/stretch.png"> Vertical space</h3>
<p>
This tool lets you insert or remove vertical space within the page:
The source code includes contributions by the following people:
Alvaro, Kit Barnes, Eduardo de Barros Lima, Mathieu Bouchard,
Ole Jørgen Brønner, Robert Buchholz, Vincenzo Ciancia, Luca de Cicco,
-Michele Codutti, Robert Gerlach, Daniel German, Dirk Gerrits,
-Lukasz Kaiser, Timo Kluck, David Kolibac, Danny Kukawka, Stefan Lembach,
-Bob McElrath, Andy Neitzke, David Planella, Marco Poletti, Alex Ray,
-Jean-Baptiste Rouquier, Marco Souza, Mike Ter Louw, Uwe Winter, Lu Zhihe.
+Michele Codutti, Robert Gerlach, Daniel German, Dirk Gerrits, Simon Guest,
+Lukasz Kaiser, Ian Woo Kim, Timo Kluck, David Kolibac, Danny Kukawka,
+Stefan Lembach, Bob McElrath, Andy Neitzke, David Planella, Marco Poletti,
+Alex Ray, Jean-Baptiste Rouquier, Victor Saase, Marco Souza, Mike Ter Louw,
+Uwe Winter, Lu Zhihe.
</p>
<p style="font-size:0.9em">(Let me know if you are missing from this list or
if your name is mis-spelled)</p>
<a name="changelog"></a>
<h2 class="subtitle">Version history</h2>
<p>
+Version 0.4.7 (July 4, 2012):
+<ul>
+ <li>insert image tool (based on patches by Victor Saase and Simon Guest)
+</li><li>renamed "Journal" menu to "Page"
+</li><li>paste images and text directly from and to other applications
+</li><li>lasso tool (based on patch by Ian Woo Kim)
+</ul>
+</p>
+<p>
Version 0.4.6 (May 22, 2012):
<ul>
<li>win32 portability code (contributed by Dirk Gerrits)
no extraneous whitespace should be inserted between the enclosing tags
and the text itself).
</p>
+<p>Starting with version 0.4.7, layers can also contain image items.
+The format of an image item is:
+<pre><image left="..." top="..." right="..." bottom="...">... data ...</image>
+</pre>
+The <i>left</i>, <i>top</i>, <i>right</i> and <i>bottom</i> attributes
+specify the bounding box to which the image is scaled, in page coordinates
+(measured in points from the top-left corner). The data is in base64-encoded
+PNG format (though any other base64-encoded format that can be loaded by
+gdk-pixbuf is currently accepted).
<hr />
<a name="installation"></a>
<h2 class="subtitle">Installation issues</h2>
#include "xo-misc.h"
#include "xo-file.h"
#include "xo-paint.h"
+#include "xo-selection.h"
#include "xo-print.h"
#include "xo-shapes.h"
on_toolsSelectRegion_activate (GtkMenuItem *menuitem,
gpointer user_data)
{
-
+ if (GTK_OBJECT_TYPE(menuitem) == GTK_TYPE_RADIO_MENU_ITEM) {
+ if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM (menuitem)))
+ return;
+ } else {
+ if (!gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON (menuitem)))
+ return;
+ }
+
+ if (ui.cur_mapping != 0 && !ui.button_switch_mapping) return; // not user-generated
+ if (ui.toolno[ui.cur_mapping] == TOOL_SELECTREGION) return;
+
+ ui.cur_mapping = 0; // don't use switch_mapping() (refreshes buttons too soon)
+ end_text();
+ ui.toolno[ui.cur_mapping] = TOOL_SELECTREGION;
+ update_mapping_linkings(-1);
+ update_tool_buttons();
+ update_tool_menu();
+ update_color_menu();
+ update_cursor();
}
do_eraser((GdkEvent *)event, ui.cur_brush->thickness/2,
ui.cur_brush->tool_options == TOOLOPT_ERASER_STROKES);
}
+ else if (ui.toolno[mapping] == TOOL_SELECTREGION) {
+ start_selectregion((GdkEvent *)event);
+ }
else if (ui.toolno[mapping] == TOOL_SELECTRECT) {
start_selectrect((GdkEvent *)event);
}
else if (ui.cur_item_type == ITEM_ERASURE) {
finalize_erasure();
}
+ else if (ui.cur_item_type == ITEM_SELECTREGION) {
+ finalize_selectregion();
+ }
else if (ui.cur_item_type == ITEM_SELECTRECT) {
finalize_selectrect();
}
else if (ui.cur_item_type == ITEM_ERASURE) {
finalize_erasure();
}
+ else if (ui.cur_item_type == ITEM_SELECTREGION) {
+ finalize_selectregion();
+ }
else if (ui.cur_item_type == ITEM_SELECTRECT) {
finalize_selectrect();
}
do_eraser((GdkEvent *)event, ui.cur_brush->thickness/2,
ui.cur_brush->tool_options == TOOLOPT_ERASER_STROKES);
}
+ else if (ui.cur_item_type == ITEM_SELECTREGION) {
+ continue_selectregion((GdkEvent *)event);
+ }
else if (ui.cur_item_type == ITEM_SELECTRECT) {
get_pointer_coords((GdkEvent *)event, pt);
ui.selection->bbox.right = pt[0];
#include "xo-paint.h"
#include "xo-image.h"
-const char *tool_names[NUM_TOOLS] = {"pen", "eraser", "highlighter", "text", "", "selectrect", "vertspace", "hand", "image"};
+const char *tool_names[NUM_TOOLS] = {"pen", "eraser", "highlighter", "text", "selectregion", "selectrect", "vertspace", "hand", "image"};
const char *color_names[COLOR_MAX] = {"black", "blue", "red", "green",
"gray", "lightblue", "lightgreen", "magenta", "orange", "yellow", "white"};
const char *bgtype_names[3] = {"solid", "pixmap", "pdf"};
g_strdup_printf("%d", PDFTOPPM_PRINTING_DPI));
update_keyval("tools", "startup_tool",
- _(" selected tool at startup (pen, eraser, highlighter, selectrect, vertspace, hand)"),
+ _(" selected tool at startup (pen, eraser, highlighter, selectregion, selectrect, vertspace, hand, image)"),
g_strdup(tool_names[ui.startuptool]));
update_keyval("tools", "pen_color",
_(" default pen color"),
_(" default highlighter is in shape recognizer mode (true/false)"),
g_strdup(ui.default_brushes[TOOL_HIGHLIGHTER].recognizer?"true":"false"));
update_keyval("tools", "btn2_tool",
- _(" button 2 tool (pen, eraser, highlighter, text, selectrect, vertspace, hand)"),
+ _(" button 2 tool (pen, eraser, highlighter, text, selectregion, selectrect, vertspace, hand, image)"),
g_strdup(tool_names[ui.toolno[1]]));
update_keyval("tools", "btn2_linked",
_(" button 2 brush linked to primary brush (true/false) (overrides all other settings)"),
_(" button 2 eraser mode (eraser only)"),
g_strdup_printf("%d", ui.brushes[1][TOOL_ERASER].tool_options));
update_keyval("tools", "btn3_tool",
- _(" button 3 tool (pen, eraser, highlighter, text, selectrect, vertspace, hand)"),
+ _(" button 3 tool (pen, eraser, highlighter, text, selectregion, selectrect, vertspace, hand, image)"),
g_strdup(tool_names[ui.toolno[2]]));
update_keyval("tools", "btn3_linked",
_(" button 3 brush linked to primary brush (true/false) (overrides all other settings)"),
"can-activate-accel", G_CALLBACK(can_accel), NULL);
g_signal_connect((gpointer) GET_COMPONENT("toolsText"),
"can-activate-accel", G_CALLBACK(can_accel), NULL);
-/* g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRegion"),
- "can-activate-accel", G_CALLBACK(can_accel), NULL); */
+ g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRegion"),
+ "can-activate-accel", G_CALLBACK(can_accel), NULL);
g_signal_connect((gpointer) GET_COMPONENT("toolsSelectRectangle"),
"can-activate-accel", G_CALLBACK(can_accel), NULL);
g_signal_connect((gpointer) GET_COMPONENT("toolsVerticalSpace"),
{
gtk_widget_hide(GET_COMPONENT("filePrintOptions"));
gtk_widget_hide(GET_COMPONENT("journalFlatten"));
- gtk_widget_hide(GET_COMPONENT("toolsSelectRegion"));
- gtk_widget_hide(GET_COMPONENT("buttonSelectRegion"));
- gtk_widget_hide(GET_COMPONENT("button2SelectRegion"));
- gtk_widget_hide(GET_COMPONENT("button3SelectRegion"));
gtk_widget_hide(GET_COMPONENT("helpIndex"));
/* config file only works with glib 2.6 and beyond */
#include <gtk/gtk.h>
#include <libgnomecanvas/libgnomecanvas.h>
#include <libart_lgpl/art_vpath_dash.h>
+#include <libart_lgpl/art_svp_point.h>
+#include <libart_lgpl/art_svp_vpath.h>
#include "xournal.h"
#include "xo-callbacks.h"
double x1, x2, y1, y2;
GList *itemlist;
struct Item *item;
-
ui.cur_item_type = ITEM_NONE;
update_font_button();
}
+
+void start_selectregion(GdkEvent *event)
+{
+ double pt[2];
+ reset_selection();
+
+ ui.cur_item_type = ITEM_SELECTREGION;
+ ui.selection = g_new(struct Selection, 1);
+ ui.selection->type = ITEM_SELECTREGION;
+ ui.selection->items = NULL;
+ ui.selection->layer = ui.cur_layer;
+
+ get_pointer_coords(event, pt);
+ ui.selection->bbox.left = ui.selection->bbox.right = pt[0];
+ ui.selection->bbox.top = ui.selection->bbox.bottom = pt[1];
+
+ realloc_cur_path(1);
+ ui.cur_path.num_points = 1;
+ ui.cur_path.coords[0] = ui.cur_path.coords[2] = pt[0];
+ ui.cur_path.coords[1] = ui.cur_path.coords[3] = pt[1];
+
+ ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
+ gnome_canvas_polygon_get_type(), "width-pixels", 1,
+ "outline-color-rgba", 0x000000ff,
+ "fill-color-rgba", 0x80808040,
+ NULL);
+ make_dashed(ui.selection->canvas_item);
+ update_cursor();
+}
+
+void continue_selectregion(GdkEvent *event)
+{
+ double *pt;
+
+ realloc_cur_path(ui.cur_path.num_points+1);
+ pt = ui.cur_path.coords + 2*ui.cur_path.num_points;
+ get_pointer_coords(event, pt);
+ if (hypot(pt[0]-pt[-2], pt[1]-pt[-1]) < PIXEL_MOTION_THRESHOLD/ui.zoom)
+ return; // not a meaningful motion
+ ui.cur_path.num_points++;
+ if (ui.cur_path.num_points>2)
+ gnome_canvas_item_set(ui.selection->canvas_item,
+ "points", &ui.cur_path, NULL);
+}
+
+/* check whether a point, resp. an item, is inside a lasso selection */
+
+gboolean hittest_point(ArtSVP *lassosvp, double x, double y)
+{
+ return art_svp_point_wind(lassosvp, x, y)%2;
+}
+
+gboolean hittest_item(ArtSVP *lassosvp, struct Item *item)
+{
+ int i;
+
+ if (item->type == ITEM_STROKE) {
+ for (i=0; i<item->path->num_points; i++)
+ if (!hittest_point(lassosvp, item->path->coords[2*i], item->path->coords[2*i+1]))
+ return FALSE;
+ return TRUE;
+ }
+ else
+ return (hittest_point(lassosvp, item->bbox.left, item->bbox.top) &&
+ hittest_point(lassosvp, item->bbox.right, item->bbox.top) &&
+ hittest_point(lassosvp, item->bbox.left, item->bbox.bottom) &&
+ hittest_point(lassosvp, item->bbox.right, item->bbox.bottom));
+}
+
+void finalize_selectregion(void)
+{
+ GList *itemlist;
+ struct Item *item;
+ ArtVpath *vpath;
+ ArtSVP *lassosvp;
+ int i, n;
+ double *pt;
+
+ ui.cur_item_type = ITEM_NONE;
+
+ // build SVP for the lasso path
+ n = ui.cur_path.num_points;
+ vpath = g_malloc((n+2)*sizeof(ArtVpath));
+ for (i=0; i<n; i++) {
+ vpath[i].x = ui.cur_path.coords[2*i];
+ vpath[i].y = ui.cur_path.coords[2*i+1];
+ }
+ vpath[n].x = vpath[0].x; vpath[n].y = vpath[0].y;
+ vpath[0].code = ART_MOVETO;
+ for (i=1; i<=n; i++) vpath[i].code = ART_LINETO;
+ vpath[n+1].code = ART_END;
+ lassosvp = art_svp_from_vpath(vpath);
+ g_free(vpath);
+
+ // see which items we selected
+ for (itemlist = ui.selection->layer->items; itemlist!=NULL; itemlist = itemlist->next) {
+ item = (struct Item *)itemlist->data;
+ if (hittest_item(lassosvp, item)) {
+ // update the selection bbox
+ if (ui.selection->items==NULL || ui.selection->bbox.left>item->bbox.left)
+ ui.selection->bbox.left = item->bbox.left;
+ if (ui.selection->items==NULL || ui.selection->bbox.right<item->bbox.right)
+ ui.selection->bbox.right = item->bbox.right;
+ if (ui.selection->items==NULL || ui.selection->bbox.top>item->bbox.top)
+ ui.selection->bbox.top = item->bbox.top;
+ if (ui.selection->items==NULL || ui.selection->bbox.bottom<item->bbox.bottom)
+ ui.selection->bbox.bottom = item->bbox.bottom;
+ // add the item
+ ui.selection->items = g_list_append(ui.selection->items, item);
+ }
+ }
+ art_svp_free(lassosvp);
+
+ if (ui.selection->items == NULL) {
+ // if we clicked inside a text zone or image?
+ pt = ui.cur_path.coords;
+ item = click_is_in_text_or_image(ui.selection->layer, pt[0], pt[1]);
+ if (item!=NULL) {
+ for (i=0; i<n; i++, pt+=2) {
+ if (pt[0]<item->bbox.left || pt[0]>item->bbox.right || pt[1]<item->bbox.top || pt[1]>item->bbox.bottom)
+ { item = NULL; break; }
+ }
+ }
+ if (item!=NULL) {
+ ui.selection->items = g_list_append(ui.selection->items, item);
+ g_memmove(&(ui.selection->bbox), &(item->bbox), sizeof(struct BBox));
+ }
+ }
+
+ if (ui.selection->items == NULL) reset_selection();
+ else { // make a selection rectangle instead of the lasso shape
+ gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item));
+ ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group,
+ gnome_canvas_rect_get_type(), "width-pixels", 1,
+ "outline-color-rgba", 0x000000ff,
+ "fill-color-rgba", 0x80808040,
+ "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right,
+ "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL);
+ make_dashed(ui.selection->canvas_item);
+ ui.selection->type = ITEM_SELECTRECT;
+ }
+
+ update_cursor();
+ update_copy_paste_enabled();
+ update_font_button();
+}
+
+
+/*** moving/resizing the selection ***/
+
gboolean start_movesel(GdkEvent *event)
{
double pt[2];
if (ui.cur_layer != ui.selection->layer) return FALSE;
get_pointer_coords(event, pt);
- if (ui.selection->type == ITEM_SELECTRECT) {
+ if (ui.selection->type == ITEM_SELECTRECT || ui.selection->type == ITEM_SELECTREGION) {
if (pt[0]<ui.selection->bbox.left || pt[0]>ui.selection->bbox.right ||
pt[1]<ui.selection->bbox.top || pt[1]>ui.selection->bbox.bottom)
return FALSE;
get_pointer_coords(event, pt);
- if (ui.selection->type == ITEM_SELECTRECT) {
+ if (ui.selection->type == ITEM_SELECTRECT || ui.selection->type == ITEM_SELECTREGION) {
resize_margin = RESIZE_MARGIN/ui.zoom;
hmargin = (ui.selection->bbox.right-ui.selection->bbox.left)*0.3;
if (hmargin>resize_margin) hmargin = resize_margin;
void start_selectrect(GdkEvent *event);
void finalize_selectrect(void);
+void start_selectregion(GdkEvent *event);
+void finalize_selectregion(void);
+void continue_selectregion(GdkEvent *event);
gboolean start_movesel(GdkEvent *event);
void start_vertspace(GdkEvent *event);
#define ITEM_RESIZESEL 22
#define ITEM_RECOGNIZER 23
#define ITEM_IMAGE 24
+#define ITEM_SELECTREGION 25
typedef struct Layer {
GList *items; // the items on the layer, from bottom to top
} Journal;
typedef struct Selection {
- int type; // ITEM_SELECTRECT, ITEM_MOVESEL_VERT
+ int type; // ITEM_SELECTRECT, ITEM_MOVESEL_VERT, ITEM_SELECTREGION
BBox bbox; // the rectangle bbox of the selection
struct Layer *layer; // the layer on which the selection lives
double anchor_x, anchor_y, last_x, last_y; // for selection motion