1# data file for the Fltk User Interface Designer (fluid)
2version 1.0304
3header_name {.h}
4code_name {.cc}
5comment {MidiLearnUI.h} {not_in_source in_header
6}
7
8comment {MidiLearnUI.cc} {in_source not_in_header
9}
10
11comment {Copyright (C) 2016-2020, Will Godfrey
12
13This file is part of yoshimi, which is free software: you can redistribute
14it and/or modify it under the terms of the GNU Library General Public
15License as published by the Free Software Foundation; either version 2 of
16the License, or (at your option) any later version.
17
18yoshimi is distributed in the hope that it will be useful, but WITHOUT ANY
19WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20FOR A PARTICULAR PURPOSE.   See the GNU General Public License (version 2 or
21later) for more details.
22
23You should have received a copy of the GNU General Public License along with
24yoshimi; if not, write to the Free Software Foundation, Inc., 51 Franklin
25Street, Fifth Floor, Boston, MA  02110-1301, USA.
26
27} {selected in_source in_header
28}
29
30decl {\#include <FL/fl_ask.H>
31    \#include "Misc/Config.h"
32    \#include "Misc/SynthEngine.h"} {private global
33}
34
35decl {using namespace std;} {public local
36}
37
38decl {\#include "MasterUI.h"} {private global
39}
40
41decl {\#include "Misc/SynthEngine.h"} {private local
42}
43
44decl {\#include "UI/MiscGui.h"
45    \#include "EffUI.h"
46    \#include "BankUI.h"
47    \#include "ADnoteUI.h"
48    \#include "SUBnoteUI.h"
49    \#include "PADnoteUI.h"
50    \#include "UI/WidgetMWSlider.h"
51    \#include "UI/WidgetSpinner.h"
52    \#include "UI/WidgetCheckButton.h"
53    \#include "Params/Controller.h"} {public global
54}
55
56decl {\#include "Misc/FileMgrFuncs.h"
57    using file::findLeafName;} {private local
58}
59
60decl {\#include "Misc/FormatFuncs.h"
61    using func::asHexString;} {private local
62}
63
64decl {\#include "Misc/TextMsgBuffer.h"
65
66    namespace { // Implementation details...
67        TextMsgBuffer& textMsgBuffer = TextMsgBuffer::instance();
68    }} {private local
69}
70
71class MidiLearnKitItem {: {public Fl_Group}
72} {
73  Function {make_window()} {} {
74    Fl_Window midilearnkititem {
75      xywh {8 649 825 20} type Double hide
76      class Fl_Group
77    } {
78      Fl_Group midilearnkititemgroup {
79        xywh {56 -4 745 23} box FLAT_BOX
80      } {
81        Fl_Spinner CCcounter {
82          class WidgetSpinner
83          callback {send_data(0, MIDILEARN::control::CCorChannel);}
84          tooltip {Continuous Controller to recognise} xywh {80 0 43 15} labelsize 12 minimum 0 maximum 129 value 14 textsize 12
85        }
86        Fl_Button {} {
87          callback {// does nothing - hides spinner arrows}
88          xywh {114 0 15 16} box FLAT_BOX down_box FLAT_BOX
89        }
90        Fl_Button nrpn {
91          label {8888 h}
92          tooltip {NRPN value} xywh {76 0 49 15} box THIN_DOWN_BOX down_box THIN_DOWN_BOX color 247 selection_color 7 labelsize 12 hide
93        }
94        Fl_Light_Button sevenbit {
95          callback {send_data(0, MIDILEARN::control::sevenBit);}
96          tooltip {Set for 7bit NRPN} xywh {59 0 13 15} box NO_BOX color 28 selection_color 1 hide
97        }
98        Fl_Choice channelchoice {
99          callback {send_data(0, 48);}
100          tooltip {Incoming channel} xywh {137 0 39 15} down_box BORDER_BOX selection_color 49 labelsize 12 textsize 12
101        } {
102          MenuItem chan1 {
103            label 1
104            xywh {0 0 26 15} labelsize 11
105          }
106          MenuItem chan2 {
107            label 2
108            xywh {10 10 26 15} labelsize 11
109          }
110          MenuItem chan3 {
111            label 3
112            xywh {20 20 26 15} labelsize 11
113          }
114          MenuItem chan4 {
115            label 4
116            xywh {30 30 26 15} labelsize 11
117          }
118          MenuItem chan5 {
119            label 5
120            xywh {40 40 26 15} labelsize 11
121          }
122          MenuItem chan6 {
123            label 6
124            xywh {50 50 26 15} labelsize 11
125          }
126          MenuItem chan7 {
127            label 7
128            xywh {60 60 26 15} labelsize 11
129          }
130          MenuItem chan8 {
131            label 8
132            xywh {70 70 26 15} labelsize 11
133          }
134          MenuItem chan9 {
135            label 9
136            xywh {80 80 26 15} labelsize 11
137          }
138          MenuItem chan10 {
139            label 10
140            xywh {90 90 26 15} labelsize 11
141          }
142          MenuItem chan11 {
143            label 11
144            xywh {100 100 26 15} labelsize 11
145          }
146          MenuItem chan12 {
147            label 12
148            xywh {110 110 26 15} labelsize 11
149          }
150          MenuItem chan13 {
151            label 13
152            xywh {120 120 26 15} labelsize 11
153          }
154          MenuItem chan14 {
155            label 14
156            xywh {130 130 26 15} labelsize 11
157          }
158          MenuItem chan15 {
159            label 15
160            xywh {140 140 26 15} labelsize 11
161          }
162          MenuItem chan16 {
163            label 16
164            xywh {150 150 26 15} labelsize 11
165          }
166          MenuItem chanAll {
167            label All
168            xywh {160 160 26 15} labelsize 11
169          }
170        }
171        Fl_Check_Button compresscheck {
172          class Fl_Check_Button2
173          callback {//
174          send_data(0, MIDILEARN::control::limit);}
175          tooltip {Limit or compress incoming value} xywh {324 0 15 15} down_box DOWN_BOX labelfont 1 align 4
176        }
177        Fl_Check_Button blockcheck {
178          class Fl_Check_Button2
179          callback {//
180          send_data(0, MIDILEARN::control::block);}
181          tooltip {Stop any later lines (or system controls) responding to this CC/Channel pair} xywh {360 0 20 15} down_box DOWN_BOX labelfont 1 align 4
182        }
183        Fl_Light_Button activity {
184          callback {//
185          if (o->value() != 0)
186              o->value(0);
187          else
188              o->value(1);}
189          xywh {180 0 13 15} box NO_BOX color 15 selection_color 2
190        }
191        Fl_Spinner minval {
192          class WidgetSpinner
193          callback {send_data(0, MIDILEARN::control::minimum);}
194          tooltip {Minimum % to pass on} xywh {197 0 52 15} type Float labelsize 12 minimum 0 step 0.5 value 0 textsize 12
195        }
196        Fl_Button {} {
197          callback {// does nothing - hides spinner arrows}
198          xywh {240 0 15 16} box FLAT_BOX down_box FLAT_BOX
199        }
200        Fl_Spinner maxval {
201          class WidgetSpinner
202          callback {//
203          send_data(0, MIDILEARN::control::maximum);}
204          tooltip {Maximim % to pass on} xywh {261 0 52 15} type Float labelsize 12 minimum 0 step 0.5 value 100 textsize 12
205        }
206        Fl_Button {} {
207          callback {// does nothing - hides spinner arrows}
208          xywh {303 0 15 16} box FLAT_BOX down_box FLAT_BOX
209        }
210        Fl_Button commandName {
211          label text
212          callback {//
213          send_data(0, MIDILEARN::control::deleteLine);}
214          tooltip {To delete, hold CTRL and click here.} xywh {395 0 400 15} box THIN_DOWN_BOX color 247 selection_color 247 labelfont 1 labelsize 10 align 64
215        }
216      }
217      Fl_Check_Button mutecheck {
218        class Fl_Check_Button2
219        callback {//
220        if (o->value())
221            midilearnkititemgroup->deactivate();
222        else
223            midilearnkititemgroup->activate();
224        send_data(0, MIDILEARN::control::mute);}
225        tooltip {Completely ignore this line} xywh {39 0 21 15} down_box DOWN_BOX labelfont 1 align 4
226        code0 {o->copy_label(to_string(n + 1).c_str());}
227      }
228    }
229  }
230  Function {send_data(int action, int control)} {} {
231    code {//
232    bool doit = true;
233    int type = 0;
234    int CC = UNUSED;
235    int chan = UNUSED;
236    int min = UNUSED;
237    int max = UNUSED;
238    switch (control)
239    {
240        case MIDILEARN::control::block:
241            if (blockcheck->value() != 0)
242                type = 1;
243            break;
244        case MIDILEARN::control::limit:
245            if (compresscheck->value() != 0)
246                type = 2;
247            break;
248        case MIDILEARN::control::mute:
249            if (mutecheck->value() != 0)
250                type = 4;
251            break;
252        case MIDILEARN::control::sevenBit:
253            if (sevenbit->value() != 0)
254               type = 16;
255            break;
256        case MIDILEARN::control::minimum:
257            min = lrint(minval->value() * 2.0f);
258            break;
259        case MIDILEARN::control::maximum:
260            max = lrint(maxval->value() * 2.0f);
261            break;
262        case MIDILEARN::control::deleteLine:
263            doit = (Fl::event_state(FL_CTRL) != 0);
264            if (doit)
265                doit = (choice(synth, "", "Yes", "No", "Remove line " + to_string( n + 1) + " " + commandName->label() + "?") > 1);
266            break;
267        case MIDILEARN::control::CCorChannel:
268            CC = lrint(CCcounter->value());
269            break;
270        case 48:
271            chan = lrint(channelchoice->value());
272            control = MIDILEARN::control::CCorChannel;
273            break;
274    }
275    if (doit)
276        collect_data(synth, n, action, type, control, TOPLEVEL::section::midiLearn, CC, chan, min, max, UNUSED, 0);} {}
277  }
278  Function {MidiLearnKitItem(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} {
279    code {n=0;} {}
280  }
281  Function {~MidiLearnKitItem()} {} {
282    code {//
283    midilearnkititem->hide();
284    delete(midilearnkititem);} {}
285  }
286  Function {init(SynthEngine *synth_, int n_)} {} {
287    code {//
288    synth = synth_;
289    n = n_;
290    make_window();
291    show();
292    end();} {}
293  }
294  decl {int n;} {private local
295  }
296  decl {char label[50];} {private local
297  }
298  decl {SynthEngine *synth;} {private local
299  }
300  decl {unsigned char stat;} {public local
301  }
302  Function {kitRscale(float dScale)} {} {
303    code {//
304    int size11 = int(11 * dScale);
305    int size12 = int(12 * dScale);
306    int size14 = int(14 * dScale);
307
308    chan1->labelsize(size11);
309    chan2->labelsize(size11);
310    chan3->labelsize(size11);
311    chan4->labelsize(size11);
312    chan5->labelsize(size11);
313    chan6->labelsize(size11);
314    chan7->labelsize(size11);
315    chan8->labelsize(size11);
316    chan9->labelsize(size11);
317    chan10->labelsize(size11);
318    chan11->labelsize(size11);
319    chan12->labelsize(size11);
320    chan13->labelsize(size11);
321    chan14->labelsize(size11);
322    chan15->labelsize(size11);
323    chan16->labelsize(size11);
324    chanAll->labelsize(size11);
325
326    CCcounter->labelsize(size12);
327        CCcounter->textsize(size12);
328    nrpn->labelsize(size12);
329    sevenbit->labelsize(size14);
330    channelchoice->labelsize(size12);
331        channelchoice->textsize(size12);
332    compresscheck->labelsize(size14);
333    blockcheck->labelsize(size14);
334    activity->labelsize(size14);
335    minval->labelsize(size12);
336        minval->textsize(size12);
337    maxval->labelsize(size12);
338        maxval->textsize(size12);
339    mutecheck->labelsize(size12);
340    commandName->labelsize(int(10 * dScale));
341
342     midilearnkititem->redraw();} {}
343  }
344}
345
346class MidiLearnUI {} {
347  Function {make_window()} {} {
348    Fl_Window midilearnwindow {
349      label {Midi Learn}
350      callback {close->do_callback();}
351      tooltip {Editor for all learned controllers.
352CTRL-right click on any knob/slider/button to learn.
353Note: Adding/deleting entries or changing CC/Chan will renumber the lines.} xywh {7 694 820 285} type Double hide resizable
354      code0 {send_data(TOPLEVEL::action::lowPrio, MIDILEARN::control::sendRefreshRequest, 0, 3);}
355      code1 {learnDW = o->w(); learnDH = o->h();}
356      code2 {o->size_range(learnDW, learnDH, 0, 0, 0, 0, 1);}
357    } {
358      Fl_Scroll kitlist {
359        tooltip {Editor for all learned controllers.
360CTRL-Right click on any knob/slider/button to learn.
361Note: Adding/deleting entries or changing CC/Chan will renumber the lines.} xywh {0 15 818 245} type VERTICAL box DOWN_FRAME
362      } {}
363      Fl_Box none {
364        label {No Entries}
365        xywh {290 131 206 44} labelsize 32
366      }
367      Fl_Box mutebox {
368        label Mute
369        xywh {18 0 41 15} labelfont 1 labelsize 11 align 18
370      }
371      Fl_Box ccbox {
372        label CC
373        xywh {80 0 40 15} labelfont 1 labelsize 11 align 18
374      }
375      Fl_Box chanbox {
376        label Chan
377        xywh {139 0 40 15} labelfont 1 labelsize 11 align 18
378      }
379      Fl_Box blockbox {
380        label Block
381        xywh {355 0 50 15} labelfont 1 labelsize 11 align 18
382      }
383      Fl_Box limitbox {
384        label Limit
385        xywh {310 0 48 15} labelfont 1 labelsize 11 align 18
386      }
387      Fl_Box controlbox {
388        label {Control Function}
389        xywh {530 0 130 15} labelfont 1 labelsize 11 align 18
390      }
391      Fl_Box minbox {
392        label {Min %}
393        xywh {200 0 40 15} labelfont 1 labelsize 11 align 18
394      }
395      Fl_Box maxbox {
396        label {Max %}
397        xywh {263 0 40 15} labelfont 1 labelsize 11 align 18
398      }
399      Fl_Button close {
400        label Close
401        callback {//
402    saveWin(synth, midilearnwindow->w(), midilearnwindow->h(), midilearnwindow->x(), midilearnwindow->y(), false, "Midi-learn");
403    midilearnwindow->hide();
404    learnSeen = false;}
405        xywh {730 262 63 20} box THIN_UP_BOX
406      }
407      Fl_Button load {
408        label Load
409        callback {//
410        string filename = setfiler(synth,"", "", false, TOPLEVEL::XML::MLearn);
411        if (filename.empty())
412            return;
413        loadMidi(filename);}
414        tooltip {Load complete learned list} xywh {30 264 70 18} down_box DOWN_BOX labelfont 1 labelsize 12
415      }
416      Fl_Button save {
417        label Save
418        callback {//
419        string filename = setfiler(synth,"", "", true, TOPLEVEL::XML::MLearn);
420        if (filename.empty())
421            return;
422        send_data(0, MIDILEARN::control::saveList, 0, 0, 0, 0, 0, 0, textMsgBuffer.push((string) filename));
423        recent->activate();
424        setWindowTitle(findLeafName(filename));}
425        tooltip {Save complete learned list} xywh {130 264 70 18} down_box DOWN_BOX labelfont 1 labelsize 12 deactivate
426      }
427      Fl_Button clear {
428        label Clear
429        callback {//
430        if (choice(synth, "", "Yes", "No", "Remove all entries") < 2)
431            return;
432
433        send_data(0, MIDILEARN::control::clearAll,0,0);
434        o->deactivate();
435        setWindowTitle();}
436        tooltip {Remove all entries} xywh {330 264 70 18} down_box DOWN_BOX labelfont 1 labelsize 12 deactivate
437      }
438      Fl_Button recent {
439        label Recent
440        callback {//
441        synth->getGuiMaster()->paramsui->Recent->position(midilearnwindow->x() + recent->x() - 80, midilearnwindow->y() + recent->y() - 187);
442        synth->getGuiMaster()->paramsui->Show(TOPLEVEL::XML::MLearn);}
443        tooltip {Load from recently seen list} xywh {230 264 70 18} down_box DOWN_BOX labelfont 1 labelsize 12
444        code0 {vector<string> &listType = *synth->getHistory(TOPLEVEL::XML::MLearn);}
445        code1 {if (listType.size() == 0) o->deactivate(); else o->activate();}
446      }
447    }
448  }
449  Function {showLearn()} {} {
450    code {//
451    int fetchW, fetchH, fetchX, fetchY, fetchO;
452    loadWin(synth, fetchW, fetchH, fetchX, fetchY, fetchO, "Midi-learn");
453    if (fetchW < learnDW || fetchH < learnDH)
454    {
455        fetchW = learnDW;
456        fetchH = learnDH;
457    }
458    checkSane(fetchX, fetchY, fetchW, fetchH, learnDW, learnDH);
459
460    midilearnwindow->resize(fetchX, fetchY, fetchW, fetchH);
461    midilearnwindow->show();
462    learnW = 0;
463    learnSeen = true;} {}
464  }
465  Function {send_data(int action, int control, float value, int type, int kititem = UNUSED, int engine = UNUSED, int insert = UNUSED, int parameter = UNUSED, int miscmsg = UNUSED)} {} {
466    code {//
467    collect_data(synth, value, action, type, control, TOPLEVEL::section::midiLearn, kititem, engine, insert, parameter, UNUSED, miscmsg);} {}
468  }
469  Function {returns_update(CommandBlock *getData)} {} {
470    code {//
471    int value = lrint(getData->data.value);
472    unsigned char type = getData->data.type;
473    unsigned char control = getData->data.control;
474    unsigned char kititem = getData->data.kit;
475    unsigned char engine = getData->data.engine;
476    unsigned char insert = getData->data.insert;
477    unsigned char parameter = getData->data.parameter;
478    unsigned char miscmsg = getData->data.miscmsg;
479    string hex;
480    int nrpnTot;
481    unsigned int IDold;
482    unsigned int IDnew;
483    switch(control)
484    {
485        case MIDILEARN::control::block:
486            break;
487        case MIDILEARN::control::ignoreMove:
488            if (type != UNUSED) // edit line in place
489            {
490                midilearnkititem[value]->blockcheck->value((type & 1) != 0);
491                midilearnkititem[value]->compresscheck->value((type & 2) != 0);
492                midilearnkititem[value]->mutecheck->value((type & 4) != 0);
493                midilearnkititem[value]->sevenbit->value((type & 16) != 0);
494                if (type & 4) // it's muted
495                    midilearnkititem[value]->midilearnkititemgroup->deactivate();
496                else
497                    midilearnkititem[value]->midilearnkititemgroup->activate();
498            }
499            if (kititem != UNUSED)
500                midilearnkititem[value]->CCcounter->value(kititem);
501            if (engine != UNUSED)
502                midilearnkititem[value]->channelchoice->value(engine);
503            if (insert != UNUSED)
504                midilearnkititem[value]->minval->value(insert / 2.0f);
505            if (parameter != UNUSED)
506                midilearnkititem[value]->maxval->value(parameter / 2.0f);
507            break;
508        case MIDILEARN::control::nrpnDetected: // set NRPN fixed value in place
509            nrpnTot = (int(engine) << 8) + (int(kititem));
510            /* These were stored 8 bit values so must be joined then
511             * split as two 7 bit values to give NRPN msb and lsb
512             */
513            hex = (asHexString(nrpnTot >> 7)) + " " + (asHexString(nrpnTot & 0x7f));
514            midilearnkititem[value]->stat |= 0x10;
515            midilearnkititem[value]->nrpn->copy_label(hex.c_str());
516            midilearnkititem[value]->CCcounter->hide();
517            midilearnkititem[value]->nrpn->show();
518            midilearnkititem[value]->sevenbit->show();
519            break;
520        case MIDILEARN::control::CCorChannel:
521            addLine(getData);
522            break;
523        case MIDILEARN::control::findSize: // not using this yet
524            break;
525        case MIDILEARN::control::sendLearnMessage:
526            synth->getGuiMaster()->setmessage(UNUSED, false, textMsgBuffer.fetch(miscmsg), "Close", "Cancel");
527            break;
528        case MIDILEARN::control::sendRefreshRequest:
529            //midilearnwindow->show();
530            showLearn();
531            break;
532        case MIDILEARN::control::reportActivity: // flash LED
533            IDold = kititem | (engine << 8);
534            for (int i = 0; i < MIDI_LEARN_BLOCK; ++ i)
535            {
536                if (midilearnkititem[i] != NULL && midilearnkititem[i]->mutecheck->value() == 0)
537                {
538                    unsigned char newchan = midilearnkititem[i]->channelchoice->value();
539                    if (newchan == NUM_MIDI_CHANNELS) // all of them
540                        newchan = engine; // force it to match
541                    IDnew = (unsigned int)midilearnkititem[i]->CCcounter->value() | (newchan << 8);
542                    if (IDold == IDnew && (type & 0x10) == (midilearnkititem[i]->stat & 0x10))
543                    {
544                        midilearnkititem[i]->activity->do_callback();
545                        if (midilearnkititem[i]->blockcheck->value() != 0)
546                            IDold = 0xffffff; // block following lines
547                    }
548                }
549            }
550            break;
551        case MIDILEARN::control::clearAll:
552            clearAll(value == 0);
553            break;
554        case MIDILEARN::control::cancelLearn:
555            synth->getGuiMaster()->setmessage(UNUSED, false, "Learn cancelled", "Close");
556            break;
557    }} {}
558  }
559  Function {addLine(CommandBlock *getData)} {} {
560    code {//
561    int lineNo = ((int)getData->data.value);
562    int status = getData->data.type;
563    string name = textMsgBuffer.fetch(getData->data.miscmsg);
564    none->hide();
565    clear->activate();
566    save->activate();
567    midilearnkititem[lineNo] = new MidiLearnKitItem(0, 0,818,20,"");
568    midilearnkititem[lineNo]->init(synth, lineNo);
569    kitlist->add(midilearnkititem[lineNo]);
570
571    midilearnkititem[lineNo]->position(2, 21 + lineNo*20);
572    midilearnkititem[lineNo]->stat = (status & 0x10);
573    midilearnkititem[lineNo]->mutecheck->value(status & 4);
574    midilearnkititem[lineNo]->CCcounter->value(getData->data.kit);
575    midilearnkititem[lineNo]->channelchoice->value(getData->data.engine);
576    midilearnkititem[lineNo]->minval->value(getData->data.insert / 2.0f);
577    midilearnkititem[lineNo]->maxval->value(getData->data.parameter / 2.0f);
578    midilearnkititem[lineNo]->compresscheck->value(status & 2);
579    midilearnkititem[lineNo]->blockcheck->value(status & 1);
580    midilearnkititem[lineNo]->commandName->copy_label(name.c_str());
581    if (status & 4)
582        midilearnkititem[lineNo]->midilearnkititemgroup->deactivate();
583    learnW = 0;
584    midilearnwindow->redraw();} {}
585  }
586  Function {MidiLearnUI(SynthEngine *_synth)} {} {
587    code {//
588    synth = _synth;
589    for (int i = 0; i < MIDI_LEARN_BLOCK; ++i)
590        midilearnkititem[i] = NULL;
591    make_window();
592    setWindowTitle();
593    learnW = 0;
594    learnSeen = false;} {}
595  }
596  Function {~MidiLearnUI()} {} {
597    code {//
598    if (learnSeen)
599        saveWin(synth, midilearnwindow->w(), midilearnwindow->h(), midilearnwindow->x(), midilearnwindow->y(), true, "Midi-learn");
600    midilearnwindow->hide();
601    delete midilearnwindow;} {}
602  }
603  Function {clearAll(bool empty)} {} {
604    code {//
605    kitlist->clear();
606    for (int i = 0; i < MIDI_LEARN_BLOCK; ++i)
607        midilearnkititem[i] = NULL;
608    if (empty)
609    {
610        none->show();
611        clear->deactivate();
612        save->deactivate();
613    }
614    kitlist->redraw();
615    kitlist->show();} {}
616  }
617  Function {loadMidi(string file)} {} {
618    code {//
619    send_data(TOPLEVEL::action::forceUpdate, MIDILEARN::control::loadList, 0, 0, 0, 0, 0, 0, textMsgBuffer.push((string) file));
620    recent->activate();
621    setWindowTitle(findLeafName(file));} {}
622  }
623  Function {setWindowTitle(string name = "")} {} {
624    code {//
625    if (name > "")
626        name = " - " + name;
627    midilearnwindow->copy_label(synth->makeUniqueName("MIDI Learn" + name).c_str());} {}
628  }
629  Function {learnRtext()} {} {
630    code {//
631    if (learnW == midilearnwindow->w())
632        return;
633    learnW = midilearnwindow->w();
634
635    float dScale = midilearnwindow->w() / float(learnDW);
636
637    int size11 = int(11 * dScale);
638    int size12 = int(12 * dScale);
639
640    close->labelsize(size12);
641    load->labelsize(size12);
642    save->labelsize(size12);
643    clear->labelsize(size12);
644    recent->labelsize(size12);
645
646    mutebox->labelsize(size11);
647    ccbox->labelsize(size11);
648    chanbox->labelsize(size11);
649    blockbox->labelsize(size11);
650    limitbox->labelsize(size11);
651    controlbox->labelsize(size11);
652    minbox->labelsize(size11);
653    maxbox->labelsize(size11);
654
655    none->labelsize(int(32 * dScale));
656    for (int i = 0; i < MIDI_LEARN_BLOCK; ++i)
657    {
658        if (midilearnkititem[i] == NULL)
659            continue;
660        midilearnkititem[i]->kitRscale(dScale);
661        midilearnkititem[i]->resize(2 * dScale, (21 + i * 20) * dScale, 818 * dScale, 20 * dScale);
662    }
663    midilearnwindow->redraw();} {}
664  }
665  decl {int lastkititem;} {public local
666  }
667  decl {SynthEngine *synth;} {private local
668  }
669  decl {MidiLearnKitItem *midilearnkititem[MIDI_LEARN_BLOCK];} {private local
670  }
671  decl {int learnDW;} {private local
672  }
673  decl {int learnDH;} {private local
674  }
675  decl {int learnW;} {private local
676  }
677  decl {bool learnSeen;} {private local
678  }
679}
680