OSDN Git Service

implement parts layout
[bbk/bchanf.git] / src / tools / panel_generator.rb
1 #
2 # panel_generator.rb
3 #
4 # Copyright (c) 2012 project bchan
5 #
6 # This software is provided 'as-is', without any express or implied
7 # warranty. In no event will the authors be held liable for any damages
8 # arising from the use of this software.
9 #
10 # Permission is granted to anyone to use this software for any purpose,
11 # including commercial applications, and to alter it and redistribute it
12 # freely, subject to the following restrictions:
13 #
14 # 1. The origin of this software must not be misrepresented; you must not
15 #    claim that you wrote the original software. If you use this software
16 #    in a product, an acknowledgment in the product documentation would be
17 #    appreciated but is not required.
18 #
19 # 2. Altered source versions must be plainly marked as such, and must not be
20 #    misrepresented as being the original software.
21 #
22 # 3. This notice may not be removed or altered from any source
23 #    distribution.
24 #
25
26 require 'yaml'
27 require 'erb'
28 require 'jcode'
29
30 def conv_euc_to_TCArray(str)
31   ret = Array.new();
32   str.each_char do |x|
33     i = x.length - 1;
34     val = 0;
35     x.each_byte do |ch|
36       val += ch << (8 * i);
37       i -= 1;
38     end
39     ret.push(val & 0x7f7f);
40   end 
41   ret;
42 end
43
44 def conv_TCArray_to_hex_definition(a)
45   str = String.new();
46   a.each do |x|
47     str += "0x" + x.to_s(16) + ", "
48   end
49   str += "TNULL";
50 end
51
52 def calc_euc_to_TCArray_length(str)
53   str = conv_euc_to_TCArray(str);
54   return str.length;
55 end
56
57 class PanelItem
58   attr_accessor :yaml
59   def initialize(yaml)
60     @yaml = yaml;
61   end
62   def type
63     @yaml["type"]
64   end
65   def name
66     @yaml["name"]
67   end
68   def item_text()
69     @yaml["text"]
70   end
71   def width
72     if @yaml["size"] != nil and @yaml["size"]["h"]
73       return @yaml["size"]["h"]
74     end
75   end
76   def height
77     if @yaml["size"] != nil and @yaml["size"]["v"]
78       return @yaml["size"]["v"]
79     end
80   end
81   def item_text_to_hex_definition()
82     conv_TCArray_to_hex_definition(conv_euc_to_TCArray(@yaml["text"]));
83   end
84   def item_text_length_in_TC
85     return calc_euc_to_TCArray_length(@yaml["text"]);
86   end
87
88   def generate_pnl_item_value(i, left, top)
89     return "";
90   end
91 end
92
93 class PanelFixedTextItem < PanelItem
94   def width
95     w = super;
96     if w != nil
97       return w;
98     end
99     return 16 * item_text_length_in_TC;
100   end
101   def height
102     h = super;
103     if h != nil
104       return h;
105     end
106     return 16;
107   end
108
109   def generate_pnl_item_value(i, left, top)
110     script = <<-EOS
111         pnl_item[<%= i %>].itype = TEXT_ITEM|ATR_TEXT;
112         pnl_item[<%= i %>].info = 0;
113         pnl_item[<%= i %>].ir = (RECT){{<%= left %>,<%= top %>,<%= left %>+<%= self.width %>,<%= top %>+<%= self.height %>}};
114         pnl_item[<%= i %>].desc = 0;
115         pnl_item[<%= i %>].dnum = 0;
116         pnl_item[<%= i %>].ptr = (H*)(TC[]){<%= self.item_text_to_hex_definition() %>};
117     EOS
118
119     erb = ERB.new(script, nil, '-');
120     erb.result(binding)
121   end
122 end
123
124 class PanelNullItem < PanelItem
125   def generate_pnl_item_value(i, left, top)
126     script = <<-EOS
127         pnl_item[<%= i %>].itype = NULL_ITEM;
128         pnl_item[<%= i %>].info = 0;
129         pnl_item[<%= i %>].ir = (RECT){{<%= left %>,<%= top %>,<%= left %>+<%= self.width %>,<%= top %>+<%= self.height %>}};
130         pnl_item[<%= i %>].desc = 0;
131         pnl_item[<%= i %>].dnum = 0;
132         pnl_item[<%= i %>].ptr = NULL;
133     EOS
134
135     erb = ERB.new(script, nil, '-');
136     erb.result(binding)
137   end
138 end
139
140 class PanelButtonItem < PanelItem
141   def width
142     w = super;
143     if w != nil
144       return w;
145     end
146     return 16 * item_text_length_in_TC + 16;
147   end
148   def height
149     h = super;
150     if h != nil
151       return h;
152     end
153     return 24;
154   end
155
156   def generate_pnl_item_value(i, left, top)
157     script = <<-EOS
158         pnl_item[<%= i %>].itype = PARTS_ITEM;
159         pnl_item[<%= i %>].info = 0;
160         pnl_item[<%= i %>].ir = (RECT){{<%= left %>,<%= top %>,<%= left %>+<%= self.width %>,<%= top %>+<%= self.height%>}};
161         pnl_item[<%= i %>].desc = 0;
162         pnl_item[<%= i %>].dnum = 0;
163         pnl_item[<%= i %>].ptr = (H*)&(SWSEL){MS_PARTS|P_DISP, (RECT){{0, 0, <%= self.width %>, <%= self.height %>}}, 0, (TC[]){MC_STR, <%= self.item_text_to_hex_definition() %>}, {0, 0, -1, 0}};
164     EOS
165
166     erb = ERB.new(script, nil, '-');
167     erb.result(binding)
168   end
169 end
170
171 def generate_parts(type, a)
172   case type
173   when "fixedtext"
174     return PanelFixedTextItem.new(a);
175   when "null_item"
176     return PanelNullItem.new(a);
177   when "button"
178     return PanelButtonItem.new(a);
179   end
180 end
181
182 class PanelLine
183   attr_accessor :yaml, :items
184   def initialize(yaml)
185     @yaml = yaml;
186     @items = Array.new();
187     if yaml["items"] != nil
188       yaml["items"].each { |a|
189         i = generate_parts(a["type"], a)
190         @items.push(i);
191       };
192     end
193   end
194   def layout
195     case @yaml["layout"]
196     when "flush left", "flush right", "centering", "justification"
197       return @yaml["layout"];
198     else
199       return "flush left"
200     end
201   end
202
203   def height
204     h = 0;
205     @items.each { |item|
206       if h < item.height
207         h = item.height;
208       end
209     }
210     return h;
211   end
212   def width(margin)
213     w = 0;
214     @items.each { |item|
215       w += item.width + margin;
216     }
217     return w;
218   end
219 end
220
221 class Panel
222   attr_accessor :yaml, :lines, :margin_left, :margin_top, :margin_right, :margine_bottom, :panel_padding_left, :panel_padding_top, :panel_padding_right, :panel_padding_bottom
223   def initialize(yaml)
224     @yaml = yaml;
225     @lines = Array.new();
226     if yaml["lines"] != nil
227       yaml["lines"].each { |a|
228         l = PanelLine.new(a);
229         @lines.push(l);
230       };
231     end
232     @margin_left = 4;
233     @margin_top = 4;
234     @margin_right = 4;
235     @margin_bottom = 4;
236     @panel_padding_left = 20;
237     @panel_padding_top = 20;
238     @panel_padding_right = 20;
239     @panel_padding_bottom = 20;
240   end
241   def panel_name()
242     @yaml["panel_name"]
243   end
244   def panel_function_name()
245     self.panel_name();
246   end
247   def panel_result_type_name()
248     self.panel_name().upcase + "_RESULT";
249   end
250   def panel_arguments()
251     ""
252   end
253
254   def each_item()
255     @lines.each { |l|
256       l.items.each { |i|
257         yield(i);
258       }
259     }
260   end
261   def number_items
262     n = 0;
263     each_item() { |i|
264       n += 1;
265     }
266     return n;
267   end
268   def each_item_type(type)
269     @lines.each { |l|
270       l.items.each { |i|
271         if i.type == type
272           yield(i);
273         end
274       }
275     }
276   end
277
278   def content_width
279     w = @margin_left + @margin_right;
280     @lines.each { |line|
281       w2 = @margin_left + line.width(@margin_left + @margin_right) + @margin_right;
282       if w2 > w
283         w = w2
284       end
285     }
286     return w;
287   end
288   def content_height
289     h = 0;
290     @lines.each { |line|
291       h += @margin_top + line.height + @margin_bottom;
292     }
293     return h;
294   end
295
296   def generate_header_retval_definition()
297     script = <<-EOS
298 enum <%= panel_result_type_name() %>_ {
299 <%- self.each_item_type("button") do |i| -%>
300         <%= panel_result_type_name().upcase %>_<%= i.name().upcase %>,
301 <%- end -%>
302 };
303 typedef enum <%= panel_result_type_name() %>_ <%= panel_result_type_name() %>;
304     EOS
305
306     erb = ERB.new(script, nil, '-');
307     erb.result(binding)
308   end
309   def generate_header_function()
310     script = <<-EOS
311 IMPORT <%= panel_result_type_name() %> <%= panel_function_name() %>(<%= panel_arguments() %>);
312     EOS
313
314     erb = ERB.new(script, nil, '-');
315     erb.result(binding)
316   end
317
318   def calc_line_layout_left(content_width, line)
319     case line.layout
320     when "flush left", "justification"
321       return @panel_padding_left + @margin_left;
322     when "flush right"
323       return @panel_padding_left + content_width - line.width;
324     when "centering"
325       return @panel_padding_left + (content_width - line.width) / 2;
326     end
327   end
328   def calc_line_layout_item_margin(content_width, line)
329     case line.layout
330     when "justification"
331       return @margin_right + @margin_left + (content_width - line.width(@margin_left + @margin_right)) / (line.items.length - 1);
332     else
333       return @margin_right + @margin_left;
334     end
335   end
336
337   def generate_source_function_pnl_item_value_each()
338     cw = self.content_width;
339     n = 0;
340     top = @panel_padding_top + @margin_top;
341     @lines.each { |l|
342       left = self.calc_line_layout_left(cw, l);
343       margin = self.calc_line_layout_item_margin(cw, l);
344       l.items.each { |i|
345         s = i.generate_pnl_item_value(n, left, top);
346         yield(s);
347         n += 1;
348         left += i.width + margin;
349       }
350       top += l.height + @margin_bottom + @margin_top;
351     }
352   end
353   def generate_source_function_ret_handler()
354     n = 0;
355     script = <<-EOS
356 <%- self.each_item() do |i| -%><%- if i.type == "button" -%>
357                         if (itemno == (<%= n %> + 1)) {
358                                 ret = <%= panel_result_type_name().upcase %>_<%= i.name().upcase %>;
359                                 break;
360                         }
361 <%- end -%><%- n += 1 -%><%- end -%>
362     EOS
363
364     erb = ERB.new(script, nil, '-');
365     erb.result(binding)
366   end
367
368   def generate_source_function_function_name()
369     script = <<-EOS
370 EXPORT <%= panel_result_type_name() %> <%= panel_function_name() %>(<%= panel_arguments() %>)
371     EOS
372
373     erb = ERB.new(script, nil, '-');
374     erb.result(binding)
375   end
376
377   def generate_source_function_pnl_item_value()
378     script = <<-EOS
379 <%- self.generate_source_function_pnl_item_value_each() do |s| -%><%= s %><%- end -%>
380     EOS
381
382     erb = ERB.new(script, nil, '-');
383     erb.result(binding)
384   end
385
386   def generate_source_function()
387     script = <<-EOS
388 <%= self.generate_source_function_function_name() %>{
389         PNL_ITEM pnl_item[<%= number_items %>];
390         PNID pnid0;
391         PNT p0 = {0x8000,0x8000};
392         WEVENT wev0;
393         W stat,itemno;
394         <%= panel_result_type_name().upcase %> ret;
395         PANEL pnl = {
396                 2,0x48,0,
397                 {{0, 0, <%= self.panel_padding_left + self.content_width + self.panel_padding_right %>, <%= self.panel_padding_top + self.content_height + self.panel_padding_bottom %>}},
398                 0,
399                 <%= number_items %>,
400                 pnl_item
401         };
402
403 <%= self.generate_source_function_pnl_item_value() %>
404         pnid0 = pcre_pnl(&pnl, &p0);
405         if (pnid0 < 0) {
406                 DP_ER("pcre_pnl error", pnid0);
407                 return pnid0;
408         }
409
410         for (;;) {
411                 ret = -1;
412                 stat = pact_pnl(pnid0, &wev0.e, &itemno);
413                 switch (stat) {
414                 case    P_EVENT:
415                         if (wev0.s.type == EV_DEVICE) {
416                                 oprc_dev(&wev0.e, NULL, 0);
417                         }
418                         continue;
419                 default:
420 <%= self.generate_source_function_ret_handler() %>
421                         if (itemno >= 0) {
422                                 continue;
423                         }
424                 case    0x5001:
425 <%= self.generate_source_function_ret_handler() %>
426                         if (itemno >= 0) {
427                                 continue;
428                         }
429                         break;
430                 }
431                 if (ret != -1) {
432                         break;
433                 }
434         }
435
436         pdel_pnl(pnid0);
437
438         return ret;
439 }
440
441     EOS
442
443     erb = ERB.new(script, nil, '-');
444     erb.result(binding)
445   end
446 end
447
448 class PanelData
449   attr_accessor :yaml, :panels, :name
450   def initialize(yaml)
451     @yaml = yaml;
452     @panels = Array.new();
453     yaml["panels"].each { |a|
454       p = Panel.new(a);
455       @panels.push(p);
456     };
457   end
458   def lisence_header()
459     @yaml["generator"]["lisence_header"]
460   end
461   def lisence_source()
462     @yaml["generator"]["lisence_source"]
463   end
464   def filename_header()
465     @yaml["generator"]["output_header"]
466   end
467
468   def generate_header()
469     script = <<-EOS
470 <%- @panels.each do |p| -%>
471 <%= p.generate_header_retval_definition() %>
472 <%= p.generate_header_function() %>
473 <%- end -%>
474     EOS
475
476     erb = ERB.new(script, nil, '-');
477     erb.result(binding)
478   end
479   def generate_source_include_files()
480     script = <<-EOS
481 #include    "<%= self.filename_header() %>"
482
483 #include        <bstdio.h>
484 #include        <bstdlib.h>
485 #include        <tcode.h>
486 #include        <tstring.h>
487 #include        <btron/btron.h>
488 #include        <btron/hmi.h>
489 #include        <btron/vobj.h>
490
491 #if PANEL_DEBUG
492 # define DP(arg) printf arg
493 # define DP_ER(msg, err) printf("%s (%d/%x)\\n", msg, err>>16, err)
494 #else
495 # define DP(arg) /**/
496 # define DP_ER(msg, err) /**/
497 #endif
498
499     EOS
500
501     erb = ERB.new(script, nil, '-');
502     erb.result(binding)
503   end
504   def generate_source()
505     script = <<-EOS
506 <%- @panels.each do |p| -%>
507 <%= p.generate_source_function() %>
508 <%- end -%>
509     EOS
510
511     erb = ERB.new(script, nil, '-');
512     erb.result(binding)
513   end
514 end
515
516 def generate_header(filename, data)
517   fd = File.open(filename, "w");
518   fd.puts data.lisence_header();
519   fd.puts <<-EOS
520
521 /* This file is automatically generated. */
522
523 #include    <basic.h>
524 #include        <btron/dp.h>
525 #include        <btron/hmi.h>
526
527   EOS
528   fd.puts "#ifndef __" + filename.upcase.gsub(/\./, '_') + "__";
529   fd.puts "#define __" + filename.upcase.gsub(/\./, '_') + "__";
530   fd.puts "\n";
531   fd.puts data.generate_header();
532   fd.puts "#endif\n"
533   fd.close
534 end
535
536 def generate_source(filename, data)
537   fd = File.open(filename, "w");
538   fd.puts data.lisence_source();
539   fd.puts <<-EOS
540
541 /* This file is automatically generated. */
542
543   EOS
544   fd.puts data.generate_source_include_files();
545
546   fd.puts data.generate_source();
547   fd.close
548 end 
549
550 $KCODE = "EUC"
551
552 yaml = YAML.load_file(ARGV[0]);
553 data = PanelData.new(yaml);
554
555 fname_header = yaml["generator"]["output_header"]
556 fname_source = yaml["generator"]["output_source"]
557
558 generate_header(fname_header, data);
559 generate_source(fname_source, data);