~centralelyon2010/inkscape/imagelinks2

« back to all changes in this revision

Viewing changes to src/dialogs/tiledialog.cpp

  • Committer: Ted Gould
  • Date: 2008-11-21 05:24:08 UTC
  • Revision ID: ted@canonical.com-20081121052408-tilucis2pjrrpzxx
MergeĀ fromĀ fe-moved

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * A simple dialog for creating grid type arrangements of selected objects
3
 
 *
4
 
 * Authors:
5
 
 *   Bob Jamison ( based off trace dialog)
6
 
 *   John Cliff
7
 
 *   Other dudes from The Inkscape Organization
8
 
 *
9
 
 * Copyright (C) 2004 Bob Jamison
10
 
 * Copyright (C) 2004 John Cliff
11
 
 *
12
 
 * Released under GNU GPL, read the file 'COPYING' for more information
13
 
 */
14
 
//#define DEBUG_GRID_ARRANGE 1
15
 
 
16
 
#ifdef HAVE_CONFIG_H
17
 
# include <config.h>
18
 
#endif
19
 
 
20
 
 
21
 
#include <gtk/gtkdialog.h> //for GTK_RESPONSE* types
22
 
#include <gtk/gtksizegroup.h>
23
 
#include <glibmm/i18n.h>
24
 
#include <gtkmm/stock.h>
25
 
 
26
 
#include "verbs.h"
27
 
#include "preferences.h"
28
 
#include "inkscape.h"
29
 
#include "desktop-handles.h"
30
 
#include "selection.h"
31
 
#include "document.h"
32
 
#include "sp-item.h"
33
 
#include "widgets/icon.h"
34
 
#include "tiledialog.h"
35
 
 
36
 
 
37
 
 
38
 
/*
39
 
 *    Sort items by their x co-ordinates, taking account of y (keeps rows intact)
40
 
 *
41
 
 *    <0 *elem1 goes before *elem2
42
 
 *    0  *elem1 == *elem2
43
 
 *    >0  *elem1 goes after *elem2
44
 
 */
45
 
int
46
 
sp_compare_x_position(SPItem *first, SPItem *second)
47
 
{
48
 
    using Geom::X;
49
 
    using Geom::Y;
50
 
 
51
 
    boost::optional<Geom::Rect> a = first->getBounds(sp_item_i2doc_affine(first));
52
 
    boost::optional<Geom::Rect> b = second->getBounds(sp_item_i2doc_affine(second));
53
 
 
54
 
    if ( !a || !b ) {
55
 
        // FIXME?
56
 
        return 0;
57
 
    }
58
 
 
59
 
    double const a_height = a->dimensions()[Y];
60
 
    double const b_height = b->dimensions()[Y];
61
 
    
62
 
    bool a_in_b_vert = false;
63
 
    if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) {
64
 
        a_in_b_vert = true;
65
 
    } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) {
66
 
        a_in_b_vert = true;
67
 
    } else if (b->min()[Y] == a->min()[Y]) {
68
 
        a_in_b_vert = true;
69
 
    } else {
70
 
        a_in_b_vert = false;
71
 
    }
72
 
 
73
 
    if (!a_in_b_vert) {
74
 
        return -1;
75
 
    }
76
 
    if (a_in_b_vert && a->min()[X] > b->min()[X]) {
77
 
        return 1;
78
 
    }
79
 
    if (a_in_b_vert && a->min()[X] < b->min()[X]) {
80
 
        return -1;
81
 
    }
82
 
    return 0;
83
 
}
84
 
 
85
 
/*
86
 
 *    Sort items by their y co-ordinates.
87
 
 */
88
 
int
89
 
sp_compare_y_position(SPItem *first, SPItem *second)
90
 
{
91
 
    boost::optional<Geom::Rect> a = first->getBounds(sp_item_i2doc_affine(first));
92
 
    boost::optional<Geom::Rect> b = second->getBounds(sp_item_i2doc_affine(second));
93
 
 
94
 
    if ( !a || !b ) {
95
 
        // FIXME?
96
 
        return 0;
97
 
    }
98
 
 
99
 
    if (a->min()[Geom::Y] > b->min()[Geom::Y]) {
100
 
        return 1;
101
 
    }
102
 
    if (a->min()[Geom::Y] < b->min()[Geom::Y]) {
103
 
        return -1;
104
 
    }
105
 
    
106
 
    return 0;
107
 
}
108
 
 
109
 
namespace Inkscape {
110
 
namespace UI {
111
 
namespace Dialog {
112
 
 
113
 
 
114
 
//#########################################################################
115
 
//## E V E N T S
116
 
//#########################################################################
117
 
 
118
 
/*
119
 
 *
120
 
 * This arranges the selection in a grid pattern.
121
 
 *
122
 
 */
123
 
 
124
 
void TileDialog::Grid_Arrange ()
125
 
{
126
 
 
127
 
    int cnt,row_cnt,col_cnt,a,row,col;
128
 
    double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y,cx,cy;
129
 
    double total_col_width,total_row_height;
130
 
    col_width = 0;
131
 
    row_height = 0;
132
 
    total_col_width=0;
133
 
    total_row_height=0;
134
 
 
135
 
    // check for correct numbers in the row- and col-spinners
136
 
    on_col_spinbutton_changed();
137
 
    on_row_spinbutton_changed();
138
 
 
139
 
    // set padding to manual values
140
 
    paddingx = XPadSpinner.get_value();
141
 
    paddingy = YPadSpinner.get_value();
142
 
 
143
 
    std::vector<double> row_heights;
144
 
    std::vector<double> col_widths;
145
 
    std::vector<double> row_ys;
146
 
    std::vector<double> col_xs;
147
 
 
148
 
    int NoOfCols = NoOfColsSpinner.get_value_as_int();
149
 
    int NoOfRows = NoOfRowsSpinner.get_value_as_int();
150
 
 
151
 
    width = 0;
152
 
    for (a=0;a<NoOfCols; a++){
153
 
        col_widths.push_back(width);
154
 
    }
155
 
 
156
 
    height = 0;
157
 
    for (a=0;a<NoOfRows; a++){
158
 
        row_heights.push_back(height);
159
 
    }
160
 
    grid_left = 99999;
161
 
    grid_top = 99999;
162
 
 
163
 
    SPDesktop *desktop = getDesktop();
164
 
    sp_document_ensure_up_to_date(sp_desktop_document(desktop));
165
 
 
166
 
    Inkscape::Selection *selection = sp_desktop_selection (desktop);
167
 
    const GSList *items = selection->itemList();
168
 
    cnt=0;
169
 
    for (; items != NULL; items = items->next) {
170
 
        SPItem *item = SP_ITEM(items->data);
171
 
        boost::optional<Geom::Rect> b = item->getBounds(sp_item_i2doc_affine(item));
172
 
        if (!b) {
173
 
            continue;
174
 
        }
175
 
 
176
 
        width = b->dimensions()[Geom::X];
177
 
        height = b->dimensions()[Geom::Y];
178
 
 
179
 
        cx = b->midpoint()[Geom::X];
180
 
        cy = b->midpoint()[Geom::Y];
181
 
 
182
 
        if (b->min()[Geom::X] < grid_left) {
183
 
            grid_left = b->min()[Geom::X];
184
 
        }
185
 
        if (b->min()[Geom::Y] < grid_top) {
186
 
            grid_top = b->min()[Geom::Y];
187
 
        }
188
 
        if (width > col_width) {
189
 
            col_width = width;
190
 
        }
191
 
        if (height > row_height) {
192
 
            row_height = height;
193
 
        }
194
 
    }
195
 
 
196
 
 
197
 
    // require the sorting done before we can calculate row heights etc.
198
 
 
199
 
    const GSList *items2 = selection->itemList();
200
 
    GSList *rev = g_slist_copy((GSList *) items2);
201
 
    GSList *sorted = NULL;
202
 
    rev = g_slist_sort(rev, (GCompareFunc) sp_compare_y_position);
203
 
    sorted = g_slist_sort(rev, (GCompareFunc) sp_compare_x_position);
204
 
 
205
 
 
206
 
    // Calculate individual Row and Column sizes if necessary
207
 
 
208
 
 
209
 
        cnt=0;
210
 
        const GSList *sizes = sorted;
211
 
        for (; sizes != NULL; sizes = sizes->next) {
212
 
            SPItem *item = SP_ITEM(sizes->data);
213
 
            boost::optional<Geom::Rect> b = item->getBounds(sp_item_i2doc_affine(item));
214
 
            if (b) {
215
 
                width = b->dimensions()[Geom::X];
216
 
                height = b->dimensions()[Geom::Y];
217
 
                if (width > col_widths[(cnt % NoOfCols)]) {
218
 
                    col_widths[(cnt % NoOfCols)] = width;
219
 
                }
220
 
                if (height > row_heights[(cnt / NoOfCols)]) {
221
 
                    row_heights[(cnt / NoOfCols)] = height;
222
 
                }
223
 
            }
224
 
 
225
 
            cnt++;
226
 
        }
227
 
 
228
 
 
229
 
    /// Make sure the top and left of the grid dont move by compensating for align values.
230
 
    if (RowHeightButton.get_active()){
231
 
        grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign));
232
 
    }
233
 
    if (ColumnWidthButton.get_active()){
234
 
        grid_left = grid_left - (((col_width - col_widths[0]) /2)*(HorizAlign));
235
 
    }
236
 
 
237
 
    #ifdef DEBUG_GRID_ARRANGE
238
 
     g_print("\n cx = %f cy= %f gridleft=%f",cx,cy,grid_left);
239
 
    #endif
240
 
 
241
 
    // Calculate total widths and heights, allowing for columns and rows non uniformly sized.
242
 
 
243
 
    if (ColumnWidthButton.get_active()){
244
 
        total_col_width = col_width * NoOfCols;
245
 
        col_widths.clear();
246
 
        for (a=0;a<NoOfCols; a++){
247
 
            col_widths.push_back(col_width);
248
 
        }
249
 
    } else {
250
 
        for (a = 0; a < (int)col_widths.size(); a++)
251
 
        {
252
 
          total_col_width += col_widths[a] ;
253
 
        }
254
 
    }
255
 
 
256
 
    if (RowHeightButton.get_active()){
257
 
        total_row_height = row_height * NoOfRows;
258
 
        row_heights.clear();
259
 
        for (a=0;a<NoOfRows; a++){
260
 
            row_heights.push_back(row_height);
261
 
        }
262
 
    } else {
263
 
        for (a = 0; a < (int)row_heights.size(); a++)
264
 
        {
265
 
          total_row_height += row_heights[a] ;
266
 
        }
267
 
    }
268
 
 
269
 
 
270
 
    boost::optional<Geom::Rect> sel_bbox = selection->bounds();
271
 
    // Fit to bbox, calculate padding between rows accordingly.
272
 
    if ( sel_bbox && !SpaceManualRadioButton.get_active() ){
273
 
#ifdef DEBUG_GRID_ARRANGE
274
 
g_print("\n row = %f     col = %f selection x= %f selection y = %f", total_row_height,total_col_width, b.extent(Geom::X), b.extent(Geom::Y));
275
 
#endif
276
 
        paddingx = (sel_bbox->width() - total_col_width) / (NoOfCols -1);
277
 
        paddingy = (sel_bbox->height() - total_row_height) / (NoOfRows -1);
278
 
    }
279
 
 
280
 
/*
281
 
    Horizontal align  - Left    = 0
282
 
                        Centre  = 1
283
 
                        Right   = 2
284
 
 
285
 
    Vertical align    - Top     = 0
286
 
                        Middle  = 1
287
 
                        Bottom  = 2
288
 
 
289
 
    X position is calculated by taking the grids left co-ord, adding the distance to the column,
290
 
   then adding 1/2 the spacing multiplied by the align variable above,
291
 
   Y position likewise, takes the top of the grid, adds the y to the current row then adds the padding in to align it.
292
 
 
293
 
*/
294
 
 
295
 
    // Calculate row and column x and y coords required to allow for columns and rows which are non uniformly sized.
296
 
 
297
 
    for (a=0;a<NoOfCols; a++){
298
 
        if (a<1) col_xs.push_back(0);
299
 
        else col_xs.push_back(col_widths[a-1]+paddingx+col_xs[a-1]);
300
 
    }
301
 
 
302
 
 
303
 
    for (a=0;a<NoOfRows; a++){
304
 
        if (a<1) row_ys.push_back(0);
305
 
        else row_ys.push_back(row_heights[a-1]+paddingy+row_ys[a-1]);
306
 
    }
307
 
 
308
 
    cnt=0;
309
 
  for (row_cnt=0; ((sorted != NULL) && (row_cnt<NoOfRows)); row_cnt++) {
310
 
 
311
 
             GSList *current_row = NULL;
312
 
             for (col_cnt = 0; ((sorted != NULL) && (col_cnt<NoOfCols)); col_cnt++) {
313
 
                 current_row = g_slist_append (current_row, sorted->data);
314
 
                 sorted = sorted->next;
315
 
             }
316
 
 
317
 
             for (; current_row != NULL; current_row = current_row->next) {
318
 
                 SPItem *item=SP_ITEM(current_row->data);
319
 
                 Inkscape::XML::Node *repr = SP_OBJECT_REPR(item);
320
 
                 boost::optional<Geom::Rect> b = item->getBounds(sp_item_i2doc_affine(item));
321
 
                 Geom::Point min;
322
 
                 if (b) {
323
 
                     width = b->dimensions()[Geom::X];
324
 
                     height = b->dimensions()[Geom::Y];
325
 
                     min = b->min();
326
 
                 } else {
327
 
                     width = height = 0;
328
 
                     min = Geom::Point(0, 0);
329
 
                 }
330
 
 
331
 
                 row = cnt / NoOfCols;
332
 
                 col = cnt % NoOfCols;
333
 
 
334
 
                 new_x = grid_left + (((col_widths[col] - width)/2)*HorizAlign) + col_xs[col];
335
 
                 new_y = grid_top + (((row_heights[row] - height)/2)*VertAlign) + row_ys[row];
336
 
 
337
 
                 // signs are inverted between x and y due to y inversion
338
 
                 Geom::Point move = Geom::Point(new_x - min[Geom::X], min[Geom::Y] - new_y);
339
 
                 Geom::Matrix const affine = Geom::Matrix(Geom::Translate(move));
340
 
                 sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * affine);
341
 
                 sp_item_write_transform(item, repr, item->transform,  NULL);
342
 
                 SP_OBJECT (current_row->data)->updateRepr();
343
 
                 cnt +=1;
344
 
             }
345
 
             g_slist_free (current_row);
346
 
    }
347
 
 
348
 
    sp_document_done (sp_desktop_document (desktop), SP_VERB_SELECTION_GRIDTILE, 
349
 
                      _("Arrange in a grid"));
350
 
 
351
 
}
352
 
 
353
 
 
354
 
//#########################################################################
355
 
//## E V E N T S
356
 
//#########################################################################
357
 
 
358
 
 
359
 
void TileDialog::_apply()
360
 
{
361
 
        Grid_Arrange();
362
 
}
363
 
 
364
 
 
365
 
/**
366
 
 * changed value in # of columns spinbox.
367
 
 */
368
 
void TileDialog::on_row_spinbutton_changed()
369
 
{
370
 
    // quit if run by the attr_changed listener
371
 
    if (updating) {
372
 
            return;
373
 
        }
374
 
 
375
 
    // in turn, prevent listener from responding
376
 
    updating = true;
377
 
    SPDesktop *desktop = getDesktop();
378
 
 
379
 
    Inkscape::Selection *selection = sp_desktop_selection (desktop);
380
 
 
381
 
    GSList const *items = selection->itemList();
382
 
    int selcount = g_slist_length((GSList *)items);
383
 
 
384
 
    double PerCol = ceil(selcount / NoOfColsSpinner.get_value());
385
 
    NoOfRowsSpinner.set_value(PerCol);
386
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
387
 
    prefs->setDouble("/dialogs/gridtiler/NoOfCols", NoOfColsSpinner.get_value());
388
 
    updating=false;
389
 
}
390
 
 
391
 
/**
392
 
 * changed value in # of rows spinbox.
393
 
 */
394
 
void TileDialog::on_col_spinbutton_changed()
395
 
{
396
 
    // quit if run by the attr_changed listener
397
 
    if (updating) {
398
 
            return;
399
 
        }
400
 
 
401
 
    // in turn, prevent listener from responding
402
 
    updating = true;
403
 
    SPDesktop *desktop = getDesktop();
404
 
    Inkscape::Selection *selection = sp_desktop_selection (desktop);
405
 
 
406
 
    GSList const *items = selection->itemList();
407
 
    int selcount = g_slist_length((GSList *)items);
408
 
 
409
 
    double PerRow = ceil(selcount / NoOfRowsSpinner.get_value());
410
 
    NoOfColsSpinner.set_value(PerRow);
411
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
412
 
    prefs->setDouble("/dialogs/gridtiler/NoOfCols", PerRow);
413
 
 
414
 
    updating=false;
415
 
}
416
 
 
417
 
/**
418
 
 * changed value in x padding spinbox.
419
 
 */
420
 
void TileDialog::on_xpad_spinbutton_changed()
421
 
{
422
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
423
 
    prefs->setDouble("/dialogs/gridtiler/XPad", XPadSpinner.get_value());
424
 
 
425
 
}
426
 
 
427
 
/**
428
 
 * changed value in y padding spinbox.
429
 
 */
430
 
void TileDialog::on_ypad_spinbutton_changed()
431
 
{
432
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
433
 
    prefs->setDouble("/dialogs/gridtiler/YPad", YPadSpinner.get_value());
434
 
}
435
 
 
436
 
 
437
 
/**
438
 
 * checked/unchecked autosize Rows button.
439
 
 */
440
 
void TileDialog::on_RowSize_checkbutton_changed()
441
 
{
442
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
443
 
    if (RowHeightButton.get_active()) {
444
 
        prefs->setDouble("/dialogs/gridtiler/AutoRowSize", 20);
445
 
    } else {
446
 
        prefs->setDouble("/dialogs/gridtiler/AutoRowSize", -20);
447
 
    }
448
 
    RowHeightBox.set_sensitive ( !RowHeightButton.get_active());
449
 
}
450
 
 
451
 
/**
452
 
 * checked/unchecked autosize Rows button.
453
 
 */
454
 
void TileDialog::on_ColSize_checkbutton_changed()
455
 
{
456
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
457
 
    if (ColumnWidthButton.get_active()) {
458
 
        prefs->setDouble("/dialogs/gridtiler/AutoColSize", 20);
459
 
    } else {
460
 
        prefs->setDouble("/dialogs/gridtiler/AutoColSize", -20);
461
 
    }
462
 
    ColumnWidthBox.set_sensitive ( !ColumnWidthButton.get_active());
463
 
}
464
 
 
465
 
/**
466
 
 * changed value in columns spinbox.
467
 
 */
468
 
void TileDialog::on_rowSize_spinbutton_changed()
469
 
{
470
 
    // quit if run by the attr_changed listener
471
 
    if (updating) {
472
 
            return;
473
 
        }
474
 
 
475
 
    // in turn, prevent listener from responding
476
 
    updating = true;
477
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
478
 
    prefs->setDouble("/dialogs/gridtiler/RowHeight", RowHeightSpinner.get_value());
479
 
    updating=false;
480
 
 
481
 
}
482
 
 
483
 
/**
484
 
 * changed value in rows spinbox.
485
 
 */
486
 
void TileDialog::on_colSize_spinbutton_changed()
487
 
{
488
 
    // quit if run by the attr_changed listener
489
 
    if (updating) {
490
 
            return;
491
 
        }
492
 
 
493
 
    // in turn, prevent listener from responding
494
 
    updating = true;
495
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
496
 
    prefs->setDouble("/dialogs/gridtiler/ColWidth", ColumnWidthSpinner.get_value());
497
 
    updating=false;
498
 
 
499
 
}
500
 
 
501
 
/**
502
 
 * changed Radio button in Spacing group.
503
 
 */
504
 
void TileDialog::Spacing_button_changed()
505
 
{
506
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
507
 
    if (SpaceManualRadioButton.get_active()) {
508
 
        prefs->setDouble("/dialogs/gridtiler/SpacingType", 20);
509
 
    } else {
510
 
        prefs->setDouble("/dialogs/gridtiler/SpacingType", -20);
511
 
    }
512
 
 
513
 
    SizesHBox.set_sensitive ( SpaceManualRadioButton.get_active());
514
 
}
515
 
 
516
 
/**
517
 
 * changed Radio button in Vertical Align group.
518
 
 */
519
 
void TileDialog::VertAlign_changed()
520
 
{
521
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
522
 
    if (VertTopRadioButton.get_active()) {
523
 
        VertAlign = 0;
524
 
        prefs->setInt("/dialogs/gridtiler/VertAlign", 0);
525
 
    } else if (VertCentreRadioButton.get_active()){
526
 
        VertAlign = 1;
527
 
        prefs->setInt("/dialogs/gridtiler/VertAlign", 1);
528
 
    } else if (VertBotRadioButton.get_active()){
529
 
        VertAlign = 2;
530
 
        prefs->setInt("/dialogs/gridtiler/VertAlign", 2);
531
 
    }
532
 
}
533
 
 
534
 
/**
535
 
 * changed Radio button in Vertical Align group.
536
 
 */
537
 
void TileDialog::HorizAlign_changed()
538
 
{
539
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
540
 
    if (HorizLeftRadioButton.get_active()) {
541
 
        HorizAlign = 0;
542
 
        prefs->setInt("/dialogs/gridtiler/HorizAlign", 0);
543
 
    } else if (HorizCentreRadioButton.get_active()){
544
 
        HorizAlign = 1;
545
 
        prefs->setInt("/dialogs/gridtiler/HorizAlign", 1);
546
 
    } else if (HorizRightRadioButton.get_active()){
547
 
        HorizAlign = 2;
548
 
        prefs->setInt("/dialogs/gridtiler/HorizAlign", 2);
549
 
    }
550
 
}
551
 
 
552
 
/**
553
 
 * Desktop selection changed
554
 
 */
555
 
void TileDialog::updateSelection()
556
 
{
557
 
    // quit if run by the attr_changed listener
558
 
    if (updating) {
559
 
        return;
560
 
    }
561
 
 
562
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
563
 
    double col_width = 0;
564
 
    double row_height = 0;
565
 
    // in turn, prevent listener from responding
566
 
    updating = true;
567
 
    SPDesktop *desktop = getDesktop();
568
 
    Inkscape::Selection *selection = sp_desktop_selection (desktop);
569
 
    const GSList *items = selection->itemList();
570
 
    int selcount = g_slist_length((GSList *)items);
571
 
 
572
 
    if (NoOfColsSpinner.get_value()>1 && NoOfRowsSpinner.get_value()>1){
573
 
        // Update the number of rows assuming number of columns wanted remains same.
574
 
        double NoOfRows = ceil(selcount / NoOfColsSpinner.get_value());
575
 
        NoOfRowsSpinner.set_value(NoOfRows);
576
 
 
577
 
        // if the selection has less than the number set for one row, reduce it appropriately
578
 
        if (selcount<NoOfColsSpinner.get_value()) {
579
 
            double NoOfCols = ceil(selcount / NoOfRowsSpinner.get_value());
580
 
            NoOfColsSpinner.set_value(NoOfCols);
581
 
            prefs->setInt("/dialogs/gridtiler/NoOfCols", NoOfCols);
582
 
        }
583
 
    } else {
584
 
        double PerRow = ceil(sqrt(selcount));
585
 
        double PerCol = ceil(sqrt(selcount));
586
 
        NoOfRowsSpinner.set_value(PerRow);
587
 
        NoOfColsSpinner.set_value(PerCol);
588
 
        prefs->setInt("/dialogs/gridtiler/NoOfCols", static_cast<int>(PerCol));
589
 
 
590
 
    }
591
 
 
592
 
    updating=false;
593
 
 
594
 
}
595
 
 
596
 
 
597
 
 
598
 
/*##########################
599
 
## Experimental
600
 
##########################*/
601
 
 
602
 
static void updateSelectionCallback(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, TileDialog *dlg)
603
 
{
604
 
    TileDialog *tledlg = (TileDialog *) dlg;
605
 
    tledlg->updateSelection();
606
 
}
607
 
 
608
 
 
609
 
//#########################################################################
610
 
//## C O N S T R U C T O R    /    D E S T R U C T O R
611
 
//#########################################################################
612
 
/**
613
 
 * Constructor
614
 
 */
615
 
TileDialog::TileDialog()
616
 
    : UI::Widget::Panel("", "/dialogs/gridtiler", SP_VERB_SELECTION_GRIDTILE)
617
 
{
618
 
     // bool used by spin button callbacks to stop loops where they change each other.
619
 
    updating = false;
620
 
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
621
 
 
622
 
    // could not do this in gtkmm - there's no Gtk::SizeGroup public constructor (!)
623
 
    GtkSizeGroup *_col1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
624
 
    GtkSizeGroup *_col2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
625
 
    GtkSizeGroup *_col3 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
626
 
 
627
 
    {
628
 
        // Selection Change signal
629
 
        g_signal_connect ( G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (updateSelectionCallback), this);
630
 
    }
631
 
 
632
 
    Gtk::Box *contents = _getContents();
633
 
 
634
 
#define MARGIN 2
635
 
 
636
 
    //##Set up the panel
637
 
 
638
 
    SPDesktop *desktop = getDesktop();
639
 
 
640
 
    Inkscape::Selection *selection = sp_desktop_selection (desktop);
641
 
    int selcount = 1;
642
 
    if (!selection->isEmpty()) {
643
 
        GSList const *items = selection->itemList();
644
 
        selcount = g_slist_length((GSList *)items);
645
 
    }
646
 
 
647
 
 
648
 
    /*#### Number of Rows ####*/
649
 
 
650
 
    double PerRow = ceil(sqrt(selcount));
651
 
    double PerCol = ceil(sqrt(selcount));
652
 
 
653
 
    #ifdef DEBUG_GRID_ARRANGE
654
 
        g_print("/n PerRox = %f PerCol = %f selcount = %d",PerRow,PerCol,selcount);
655
 
    #endif
656
 
 
657
 
    NoOfRowsLabel.set_label(_("Rows:"));
658
 
    NoOfRowsBox.pack_start(NoOfRowsLabel, false, false, MARGIN);
659
 
 
660
 
    NoOfRowsSpinner.set_digits(0);
661
 
    NoOfRowsSpinner.set_increments(1, 5);
662
 
    NoOfRowsSpinner.set_range(1.0, 100.0);
663
 
    NoOfRowsSpinner.set_value(PerCol);
664
 
    NoOfRowsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_col_spinbutton_changed));
665
 
    tips.set_tip(NoOfRowsSpinner, _("Number of rows"));
666
 
    NoOfRowsBox.pack_start(NoOfRowsSpinner, false, false, MARGIN);
667
 
    gtk_size_group_add_widget(_col1, (GtkWidget *) NoOfRowsBox.gobj());
668
 
 
669
 
    RowHeightButton.set_label(_("Equal height"));
670
 
    double AutoRow = prefs->getDouble("/dialogs/gridtiler/AutoRowSize", 15);
671
 
    if (AutoRow>0)
672
 
         AutoRowSize=true;
673
 
    else
674
 
         AutoRowSize=false;
675
 
    RowHeightButton.set_active(AutoRowSize);
676
 
 
677
 
    NoOfRowsBox.pack_start(RowHeightButton, false, false, MARGIN);
678
 
 
679
 
    tips.set_tip(RowHeightButton, _("If not set, each row has the height of the tallest object in it"));
680
 
    RowHeightButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_RowSize_checkbutton_changed));
681
 
 
682
 
 {
683
 
        /*#### Radio buttons to control vertical alignment ####*/
684
 
 
685
 
        VertAlignLabel.set_label(_("Align:"));
686
 
        VertAlignHBox.pack_start(VertAlignLabel, false, false, MARGIN);
687
 
 
688
 
        VertTopRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
689
 
        VertAlignGroup = VertTopRadioButton.get_group();
690
 
        VertAlignVBox.pack_start(VertTopRadioButton, false, false, 0);
691
 
 
692
 
        VertCentreRadioButton.set_group(VertAlignGroup);
693
 
        VertCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
694
 
        VertAlignVBox.pack_start(VertCentreRadioButton, false, false, 0);
695
 
 
696
 
        VertBotRadioButton.set_group(VertAlignGroup);
697
 
        VertBotRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::VertAlign_changed));
698
 
        VertAlignVBox.pack_start(VertBotRadioButton, false, false, 0);
699
 
 
700
 
        VertAlign = prefs->getInt("/dialogs/gridtiler/VertAlign", 1);
701
 
        if (VertAlign == 0) {
702
 
            VertTopRadioButton.set_active(TRUE);
703
 
        }
704
 
        else if (VertAlign == 1) {
705
 
            VertCentreRadioButton.set_active(TRUE);
706
 
        }
707
 
        else if (VertAlign == 2){
708
 
            VertBotRadioButton.set_active(TRUE);
709
 
        }
710
 
        VertAlignHBox.pack_start(VertAlignVBox, false, false, MARGIN);
711
 
        NoOfRowsBox.pack_start(VertAlignHBox, false, false, MARGIN);
712
 
    }
713
 
 
714
 
    SpinsHBox.pack_start(NoOfRowsBox, false, false, MARGIN);
715
 
 
716
 
 
717
 
    /*#### Label for X ####*/
718
 
    padXByYLabel.set_label(" ");
719
 
    XByYLabelVBox.pack_start(padXByYLabel, false, false, MARGIN);
720
 
    XByYLabel.set_markup(" &#215; ");
721
 
    XByYLabelVBox.pack_start(XByYLabel, false, false, MARGIN);
722
 
    SpinsHBox.pack_start(XByYLabelVBox, false, false, MARGIN);
723
 
    gtk_size_group_add_widget(_col2, (GtkWidget *) XByYLabelVBox.gobj());
724
 
 
725
 
    /*#### Number of columns ####*/
726
 
 
727
 
    NoOfColsLabel.set_label(_("Columns:"));
728
 
    NoOfColsBox.pack_start(NoOfColsLabel, false, false, MARGIN);
729
 
 
730
 
    NoOfColsSpinner.set_digits(0);
731
 
    NoOfColsSpinner.set_increments(1, 5);
732
 
    NoOfColsSpinner.set_range(1.0, 100.0);
733
 
    NoOfColsSpinner.set_value(PerRow);
734
 
    NoOfColsSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_row_spinbutton_changed));
735
 
    tips.set_tip(NoOfColsSpinner, _("Number of columns"));
736
 
    NoOfColsBox.pack_start(NoOfColsSpinner, false, false, MARGIN);
737
 
    gtk_size_group_add_widget(_col3, (GtkWidget *) NoOfColsBox.gobj());
738
 
 
739
 
    ColumnWidthButton.set_label(_("Equal width"));
740
 
    double AutoCol = prefs->getDouble("/dialogs/gridtiler/AutoColSize", 15);
741
 
    if (AutoCol>0)
742
 
         AutoColSize=true;
743
 
    else
744
 
         AutoColSize=false;
745
 
    ColumnWidthButton.set_active(AutoColSize);
746
 
    NoOfColsBox.pack_start(ColumnWidthButton, false, false, MARGIN);
747
 
 
748
 
    tips.set_tip(ColumnWidthButton, _("If not set, each column has the width of the widest object in it"));
749
 
    ColumnWidthButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::on_ColSize_checkbutton_changed));
750
 
 
751
 
 
752
 
    {
753
 
        /*#### Radio buttons to control horizontal alignment ####*/
754
 
 
755
 
        HorizAlignLabel.set_label(_("Align:"));
756
 
        HorizAlignVBox.pack_start(HorizAlignLabel, false, false, MARGIN);
757
 
 
758
 
        HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut
759
 
 
760
 
        HorizLeftRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
761
 
        HorizAlignGroup = HorizLeftRadioButton.get_group();
762
 
        HorizAlignHBox.pack_start(HorizLeftRadioButton, false, false, 0);
763
 
 
764
 
        HorizCentreRadioButton.set_group(HorizAlignGroup);
765
 
        HorizCentreRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
766
 
        HorizAlignHBox.pack_start(HorizCentreRadioButton, false, false, 0);
767
 
 
768
 
        HorizRightRadioButton.set_group(HorizAlignGroup);
769
 
        HorizRightRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::HorizAlign_changed));
770
 
        HorizAlignHBox.pack_start(HorizRightRadioButton, false, false, 0);
771
 
 
772
 
        HorizAlignHBox.pack_start(*(new Gtk::HBox()), true, true, 0); // centering strut
773
 
 
774
 
        HorizAlign = prefs->getInt("/dialogs/gridtiler/HorizAlign", 1);
775
 
        if (HorizAlign == 0) {
776
 
            HorizLeftRadioButton.set_active(TRUE);
777
 
        }
778
 
        else if (HorizAlign == 1) {
779
 
            HorizCentreRadioButton.set_active(TRUE);
780
 
        }
781
 
        else if (HorizAlign == 2) {
782
 
            HorizRightRadioButton.set_active(TRUE);
783
 
        }
784
 
        HorizAlignVBox.pack_start(HorizAlignHBox, false, false, MARGIN);
785
 
        NoOfColsBox.pack_start(HorizAlignVBox, false, false, MARGIN);
786
 
    }
787
 
 
788
 
    SpinsHBox.pack_start(NoOfColsBox, false, false, MARGIN);
789
 
 
790
 
    TileBox.pack_start(SpinsHBox, false, false, MARGIN);
791
 
 
792
 
    {
793
 
        /*#### Radio buttons to control spacing manually or to fit selection bbox ####*/
794
 
        SpaceByBBoxRadioButton.set_label(_("Fit into selection box"));
795
 
        SpaceByBBoxRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed));
796
 
        SpacingGroup = SpaceByBBoxRadioButton.get_group();
797
 
 
798
 
        SpacingVBox.pack_start(SpaceByBBoxRadioButton, false, false, MARGIN);
799
 
 
800
 
        SpaceManualRadioButton.set_label(_("Set spacing:"));
801
 
        SpaceManualRadioButton.set_group(SpacingGroup);
802
 
        SpaceManualRadioButton.signal_toggled().connect(sigc::mem_fun(*this, &TileDialog::Spacing_button_changed));
803
 
        SpacingVBox.pack_start(SpaceManualRadioButton, false, false, MARGIN);
804
 
 
805
 
        TileBox.pack_start(SpacingVBox, false, false, MARGIN);
806
 
    }
807
 
 
808
 
    {
809
 
        /*#### Y Padding ####*/
810
 
 
811
 
        GtkWidget *i = sp_icon_new (Inkscape::ICON_SIZE_MENU, "clonetiler_per_row");
812
 
        YPadBox.pack_start (*(Glib::wrap(i)), false, false, MARGIN);
813
 
 
814
 
        YPadSpinner.set_digits(1);
815
 
        YPadSpinner.set_increments(0.2, 2);
816
 
        YPadSpinner.set_range(-10000, 10000);
817
 
        double YPad = prefs->getDouble("/dialogs/gridtiler/YPad", 15);
818
 
        YPadSpinner.set_value(YPad);
819
 
        YPadBox.pack_start(YPadSpinner, true, true, MARGIN);
820
 
        tips.set_tip(YPadSpinner, _("Vertical spacing between rows (px units)"));
821
 
        YPadSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_ypad_spinbutton_changed));
822
 
        gtk_size_group_add_widget(_col1, (GtkWidget *) YPadBox.gobj());
823
 
 
824
 
        SizesHBox.pack_start(YPadBox, false, false, MARGIN);
825
 
    }
826
 
 
827
 
    {
828
 
    Gtk::HBox *spacer = new Gtk::HBox;
829
 
    SizesHBox.pack_start(*spacer, false, false, 0);
830
 
    gtk_size_group_add_widget(_col2, (GtkWidget *) spacer->gobj());
831
 
    }
832
 
 
833
 
    {
834
 
        /*#### X padding ####*/
835
 
 
836
 
        GtkWidget *i = sp_icon_new (Inkscape::ICON_SIZE_MENU, "clonetiler_per_column");
837
 
        XPadBox.pack_start (*(Glib::wrap(i)), false, false, MARGIN);
838
 
 
839
 
        XPadSpinner.set_digits(1);
840
 
        XPadSpinner.set_increments(0.2, 2);
841
 
        XPadSpinner.set_range(-10000, 10000);
842
 
        double XPad = prefs->getDouble("/dialogs/gridtiler/XPad", 15);
843
 
        XPadSpinner.set_value(XPad);
844
 
        XPadBox.pack_start(XPadSpinner, true, true, MARGIN);
845
 
        tips.set_tip(XPadSpinner, _("Horizontal spacing between columns (px units)"));
846
 
        XPadSpinner.signal_changed().connect(sigc::mem_fun(*this, &TileDialog::on_xpad_spinbutton_changed));
847
 
        gtk_size_group_add_widget(_col3, (GtkWidget *) XPadBox.gobj());
848
 
 
849
 
        SizesHBox.pack_start(XPadBox, false, false, MARGIN);
850
 
    }
851
 
 
852
 
 
853
 
    TileBox.pack_start(SizesHBox, false, false, MARGIN);
854
 
 
855
 
    contents->pack_start(TileBox);
856
 
 
857
 
    double SpacingType = prefs->getDouble("/dialogs/gridtiler/SpacingType", 15);
858
 
    if (SpacingType>0) {
859
 
        ManualSpacing=true;
860
 
    } else {
861
 
        ManualSpacing=false;
862
 
    }
863
 
    SpaceManualRadioButton.set_active(ManualSpacing);
864
 
    SpaceByBBoxRadioButton.set_active(!ManualSpacing);
865
 
    SizesHBox.set_sensitive (ManualSpacing);
866
 
 
867
 
    //## The OK button
868
 
    TileOkButton = addResponseButton(_("Arrange"), GTK_RESPONSE_APPLY);
869
 
    tips.set_tip((*TileOkButton), _("Arrange selected objects"));
870
 
 
871
 
    show_all_children();
872
 
}
873
 
 
874
 
} //namespace Dialog
875
 
} //namespace UI
876
 
} //namespace Inkscape
877
 
 
878
 
/*
879
 
  Local Variables:
880
 
  mode:c++
881
 
  c-file-style:"stroustrup"
882
 
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
883
 
  indent-tabs-mode:nil
884
 
  fill-column:99
885
 
  End:
886
 
*/
887
 
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 ::