]> mj.ucw.cz Git - paperjam.git/blob - cmds.cc
More general syntax of pipelines
[paperjam.git] / cmds.cc
1 #include <cassert>
2 #include <cstdlib>
3 #include <cstdio>
4
5 #include "jam.h"
6
7 /*** null ***/
8
9 class null_cmd : public cmd_exec {
10   vector<page *> process(vector<page *> &pages) { return pages; }
11 };
12
13 static const arg_def no_args[] = {
14   { NULL,       0 }
15 };
16
17 static cmd_exec *null_ctor(cmd *c UNUSED)
18 {
19   return new null_cmd;
20 }
21
22 /*** move ***/
23
24 class move_cmd : public cmd_exec {
25 public:
26   double x, y;
27   vector<page *> process(vector<page *> &pages);
28 };
29
30 class xform_page : public page {
31   page *orig_page;
32 public:
33   pdf_matrix xform;
34   void render(page_out *out, pdf_matrix xform);
35   xform_page(page *_orig, double _w, double _h) : page(_w, _h), orig_page(_orig) { }
36 };
37
38 void xform_page::render(page_out *out, pdf_matrix parent_xform)
39 {
40   orig_page->render(out, xform * parent_xform);
41 }
42
43 vector<page *> move_cmd::process(vector<page *> &pages)
44 {
45   vector<page *> out;
46   for (auto p: pages)
47     {
48       xform_page *q = new xform_page(p, p->width, p->height);
49       q->xform.shift(x, y);
50       out.push_back(q);
51     }
52   return out;
53 }
54
55 static const arg_def move_args[] = {
56   { "x",        AT_DIMEN | AT_MANDATORY | AT_POSITIONAL },
57   { "y",        AT_DIMEN | AT_MANDATORY | AT_POSITIONAL },
58   { NULL,       0 }
59 };
60
61 static cmd_exec *move_ctor(cmd *c)
62 {
63   move_cmd *m = new move_cmd;
64   m->x = c->args.at(0)->as_double(0);
65   m->y = c->args.at(1)->as_double(0);
66   return m;
67 }
68
69 /*** scale ***/
70
71 class scale_cmd : public cmd_exec {
72 public:
73   double x_factor, y_factor;
74   vector<page *> process(vector<page *> &pages);
75 };
76
77 vector<page *> scale_cmd::process(vector<page *> &pages)
78 {
79   vector<page *> out;
80   for (auto p: pages)
81     {
82       xform_page *q = new xform_page(p, x_factor*p->width, y_factor*p->height);
83       q->xform.scale(x_factor, y_factor);
84       out.push_back(q);
85     }
86   return out;
87 }
88
89 static const arg_def scale_args[] = {
90   { "x",        AT_DOUBLE | AT_MANDATORY | AT_POSITIONAL },
91   { "y",        AT_DOUBLE | AT_POSITIONAL },
92   { NULL,       0 }
93 };
94
95 static cmd_exec *scale_ctor(cmd *c)
96 {
97   scale_cmd *s = new scale_cmd;
98   s->x_factor = c->args.at(0)->as_double(1);
99   s->y_factor = c->args.at(1)->as_double(s->x_factor);
100   return s;
101 }
102
103 /*** rotate ***/
104
105 class rotate_cmd : public cmd_exec {
106 public:
107   int deg;
108   vector<page *> process(vector<page *> &pages);
109 };
110
111 vector<page *> rotate_cmd::process(vector<page *> &pages)
112 {
113   vector<page *> out;
114   for (auto p: pages)
115     {
116       xform_page *q = new xform_page(p, p->width, p->height);
117       switch (deg)
118         {
119         case 0:
120           break;
121         case 90:
122           q->xform.rotate_deg(-90);
123           q->xform.shift(0, p->width);
124           swap(q->width, q->height);
125           break;
126         case 180:
127           q->xform.rotate_deg(180);
128           q->xform.shift(p->width, p->height);
129           break;
130         case 270:
131           q->xform.rotate_deg(90);
132           q->xform.shift(p->height, 0);
133           swap(q->width, q->height);
134           break;
135         default:
136           abort();
137         }
138       out.push_back(q);
139     }
140   return out;
141 }
142
143 static const arg_def rotate_args[] = {
144   { "angle",    AT_INT | AT_MANDATORY | AT_POSITIONAL },
145   { NULL,       0 }
146 };
147
148 static cmd_exec *rotate_ctor(cmd *c)
149 {
150   rotate_cmd *r = new rotate_cmd;
151   r->deg = c->args.at(0)->as_int(0) % 360;
152   if (r->deg < 0)
153     r->deg += 360;
154   if (r->deg % 90)
155     die("Rotate requires a multiple of 90 degrees");
156   return r;
157 }
158
159 /*** select ***/
160
161 class select_cmd : public cmd_exec {
162 public:
163   pipeline *pipe;
164   vector<page *> process(vector<page *> &pages);
165 };
166
167 static int validate_page_index(vector<page *> &pages, int idx)
168 {
169   if (idx >= 1 && idx <= (int) pages.size())
170     return idx - 1;
171   if (idx <= -1 && idx >= (int) -pages.size())
172     return idx + pages.size();
173   die("Page index %d out of range", idx);
174 }
175
176 vector<page *> select_cmd::process(vector<page *> &pages)
177 {
178   vector<page *> out;
179   for (auto pb: pipe->branches)
180     {
181       vector<page *> selected;
182       for (auto ps: pb->selectors)
183         {
184           int f = validate_page_index(pages, ps.from);
185           int t = validate_page_index(pages, ps.to);
186           int step = (f <= t) ? 1 : -1;
187           for (int i=f; f<=t; f += step)
188             selected.push_back(pages[i]);
189         }
190       auto processed = run_command_list(pb->commands, selected);
191       for (auto p: processed)
192         out.push_back(p);
193     }
194   return out;
195 }
196
197 static cmd_exec *select_ctor(cmd *c)
198 {
199   select_cmd *r = new select_cmd;
200   r->pipe = c->pipe;
201   return r;
202 }
203
204 /*** Command table ***/
205
206 const cmd_def cmd_table[] = {
207   { "null",     no_args,        0,      null_ctor       },
208   { "move",     move_args,      0,      move_ctor       },
209   { "scale",    scale_args,     0,      scale_ctor      },
210   { "rotate",   rotate_args,    0,      rotate_ctor     },
211   { "select",   no_args,        1,      select_ctor     },
212   { NULL,       NULL,           0,      NULL    }
213 };