BankView.cpp (9666B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 BankView.cpp - View Of Bank Fields 5 Copyright (C) 2016 Mark McCurry 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License 9 as published by the Free Software Foundation; either version 2 10 of the License, or (at your option) any later version. 11 */ 12 #include "BankView.h" 13 #include "../Misc/Util.h" 14 #include <FL/Fl.H> 15 #include <FL/Fl_Check_Button.H> 16 #include <FL/fl_ask.H> 17 #include <rtosc/rtosc.h> 18 #include <cstdio> 19 #include <cstring> 20 #include <cassert> 21 22 using namespace zyn; 23 24 BankList::BankList(int x,int y, int w, int h, const char *label) 25 :Fl_Osc_Choice(x,y,w,h,label) 26 {} 27 28 void BankList::init(std::string path) 29 { 30 ext = path; 31 oscRegister("bank/bank_select"); 32 oscRegister(path.c_str()); 33 oscWrite("bank/banks", ""); 34 } 35 36 void BankList::OSC_raw(const char *msg) 37 { 38 if(!strcmp(msg, "/bank/bank_select") && !strcmp(rtosc_argument_string(msg),"iss")) { 39 40 const int pos = rtosc_argument(msg, 0).i; 41 const char *path = rtosc_argument(msg, 1).s; 42 43 value(0); 44 if(pos == 0) 45 this->clear(); 46 47 if(pos <= this->size()-2) { 48 return; 49 } 50 this->add(path); 51 } 52 if(!strcmp(msg, "/bank/bank_select")&& !strcmp(rtosc_argument_string(msg),"i")) { 53 int val = rtosc_argument(msg, 0).i; 54 if(value() != val) { 55 value(val); 56 for(int i=0; i<160; ++i) 57 osc->write("/bank/slot"+to_s(i), ""); 58 } 59 } 60 } 61 62 BankSlot::BankSlot(int x,int y, int w, int h, const char *label) 63 :Fl_Button(x,y,w,h,label), nslot(-1) 64 { 65 memset(labelstr, 0, sizeof(labelstr)); 66 box(FL_THIN_UP_BOX); 67 labelfont(0); 68 labelsize(13); 69 align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP); 70 } 71 72 int BankSlot::handle(int event) 73 { 74 int what = 0; 75 if (Fl::event_inside(this)) 76 { 77 what=0; 78 if ((event==FL_RELEASE)&&(Fl::event_button()==1)) 79 what=1; 80 if ((event==FL_RELEASE)&&(Fl::event_button()==3)) 81 what=2; 82 } 83 84 int tmp=Fl_Button::handle(event); 85 86 if (what && Fl::event_inside(this)) 87 bv->react(what, nslot); 88 89 return tmp; 90 } 91 92 void BankSlot::init(int nslot_, BankView *bv_) 93 { 94 nslot = nslot_; 95 bv = bv_; 96 97 snprintf(labelstr, 127, "%d.", nslot_); 98 label(labelstr); 99 } 100 101 void BankSlot::update(const char *name__, const char *fname__) 102 { 103 name_ = name__; 104 filename_ = fname__; 105 snprintf(labelstr, 127, "%d. %s", nslot, name_.c_str()); 106 label(labelstr); 107 108 if(name_.empty()) 109 label(""); 110 111 color(empty() ? 46 : 51); 112 #ifdef NTK_GUI 113 redraw(); 114 #endif 115 } 116 117 bool BankSlot::empty(void) const 118 { 119 return filename_.empty(); 120 } 121 122 const char *BankSlot::name(void) const 123 { 124 return name_.c_str(); 125 } 126 127 const char *BankSlot::filename(void) const 128 { 129 return filename_.c_str(); 130 } 131 132 /* 133 void BankSlot::init(int nslot_, int *what_, int *whatslot_,void (BankProcess_:: *fnc_)(void),BankProcess_ *bp_,Bank *bank_,int *nselected_) { 134 nslot=nslot_; 135 what=what_; 136 whatslot=whatslot_; 137 fnc=fnc_; 138 bp=bp_; 139 //bank=bank_; 140 nselected=nselected_; 141 box(FL_THIN_UP_BOX); 142 labelfont(0); 143 labelsize(13); 144 align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP); 145 146 highlight=0; 147 //refresh(); 148 } 149 */ 150 151 /* 152 void BankSlot::refresh() { 153 if (bank->emptyslot(nslot)) 154 color(46); 155 else if (bank->isPADsynth_used(nslot)) 156 color(26); 157 else 158 color(51); 159 160 161 if (*nselected==nslot) 162 color(6); 163 164 165 copy_label(bank->getnamenumbered(nslot).c_str()); 166 } 167 */ 168 static int modeCb(const char *label) 169 { 170 if(!strcmp("Read", label)) 171 return 1; 172 else if(!strcmp("Write", label)) 173 return 2; 174 else if(!strcmp("Clear", label)) 175 return 3; 176 else if(!strcmp("Swap", label)) 177 return 4; 178 return -1; 179 } 180 181 static void modeButtonCb(Fl_Widget *w, void *v) 182 { 183 BankViewControls *bvc = (BankViewControls*)v; 184 bvc->mode(modeCb(w->label())); 185 } 186 187 BankViewControls::BankViewControls(int x, int y, int w, int h, const char *label) 188 :Fl_Group(x,y,w,h,label) 189 { 190 //Margin 191 const int m = 10; 192 //Width per elm 193 const float W = w/4; 194 195 read = new Fl_Check_Button(x+m+0*W, y+m, W-2*m, h-2*m, "Read"); 196 write = new Fl_Check_Button(x+m+1*W, y+m, W-2*m, h-2*m, "Write"); 197 clear = new Fl_Check_Button(x+m+2*W, y+m, W-2*m, h-2*m, "Clear"); 198 swap = new Fl_Check_Button(x+m+3*W, y+m, W-2*m, h-2*m, "Swap"); 199 read->box(FL_BORDER_BOX); 200 write->box(FL_BORDER_BOX); 201 clear->box(FL_BORDER_BOX); 202 swap->box(FL_BORDER_BOX); 203 read->callback(modeButtonCb, this); 204 write->callback(modeButtonCb, this); 205 clear->callback(modeButtonCb, this); 206 swap->callback(modeButtonCb, this); 207 mode(1); 208 } 209 210 int BankViewControls::mode(void) const 211 { 212 return mode_; 213 } 214 215 void BankViewControls::mode(int m) 216 { 217 mode_ = m; 218 int M = m-1; 219 assert(0 <= M && M <= 3); 220 Fl_Button *buttons[4]{read, write, clear, swap}; 221 222 for(int i=0; i<4; ++i) 223 buttons[i]->value(i==M); 224 } 225 226 227 BankView::BankView(int x,int y, int w, int h, const char *label) 228 :Fl_Group(x,y,w,h,label), Fl_Osc_Widget(), 229 bvc(NULL), slots{0}, nselected(-1), npart(0), cbwig_(0) 230 {} 231 232 233 BankView::~BankView(void) 234 { 235 if(osc) { 236 osc->removeLink("/bankview", this); 237 osc->removeLink("/bank/search_results", this); 238 } 239 } 240 241 void BankView::init(Fl_Osc_Interface *osc_, BankViewControls *bvc_, int *npart_) 242 { 243 assert(osc_); 244 245 osc = osc_; 246 bvc = bvc_; 247 npart = npart_; 248 249 osc->createLink("/bankview", this); 250 osc->createLink("/bank/search_results", this); 251 252 //Element Size 253 const float width = w()/5.0; 254 const float height = h()/32.0; 255 256 //Offsets 257 const int X = x(); 258 const int Y = y(); 259 260 begin(); 261 //Place All Slots 262 for(int i=0; i<5; ++i) 263 for(int j=0; j<32; ++j) 264 slots[i*32 + j] = 265 new BankSlot(X + i*width, Y + j*height, width, height); 266 267 end(); 268 269 //Initialize callbacks 270 for(int i=0; i<160; ++i) 271 slots[i]->init(i, this); 272 273 //Create Slot Listeners 274 for(int i=0; i<160; ++i) 275 osc->createLink("/bank/slot"+to_s(i), this); 276 //Request Values 277 for(int i=0; i<160; ++i) 278 osc->write("/bank/slot"+to_s(i), ""); 279 } 280 281 /* 282 * React to user input. 283 * This consists of the events: 284 * - Rename Slot (right click) 285 * - Read From Slot 286 * - Write To Slot 287 * - Swap Slot First Selection 288 * - Swap Slot Second Selection 289 * 290 * TODO restore autoclose functionality 291 */ 292 void BankView::react(int event, int nslot) 293 { 294 BankSlot &slot = *slots[nslot]; 295 const bool isempty = slot.empty(); 296 const int mode = bvc->mode(); 297 298 //Rename slot 299 if (event==2 && !isempty && mode!=4) { 300 if(const char *name=fl_input("Slot (instrument) name:", slot.name())) { 301 osc->write("/bank/rename_slot", "is", nslot, name); 302 osc->write("/bank/slot"+to_s(nslot), ""); 303 } 304 } 305 306 //Reads from slot 307 if ((event==1)&&(mode==1) && !isempty){ 308 printf("Loading a part #%d with file '%s'\n", nslot, slot.filename()); 309 osc->write("/load-part", "iss", *npart, slot.filename(), 310 slot.name()); 311 osc->writeValue("/part"+to_s(*npart)+"/Pname", slot.name()); 312 if(cbwig_) 313 cbwig_->do_callback(); 314 } 315 316 //save(write) to slot 317 if(event==1 && mode==2){ 318 if(isempty || 319 fl_choice("Overwrite the slot no. %d ?","No","Yes",NULL,nslot+1)) { 320 osc->write("/bank/save_to_slot", "ii", *npart, nslot); 321 osc->write("/bank/slot"+to_s(nslot), ""); 322 } 323 bvc->mode(1); 324 } 325 326 327 //Clears the slot 328 if(event==1 && mode==3) { 329 if (!isempty && 330 fl_choice("Clear the slot no. %d ?","No","Yes",NULL, nslot+1)) { 331 osc->write("/bank/clear_slot", "i", nslot); 332 osc->write("/bank/slot"+to_s(nslot), ""); 333 } 334 bvc->mode(1); 335 } 336 337 //Swap 338 if(mode==4) { 339 if(event==1 && nselected>=0){ 340 osc->write("/bank/swap_slots", "ii", nselected, nslot); 341 osc->write("/bank/slot"+to_s(nslot), ""); 342 osc->write("/bank/slot"+to_s(nselected), ""); 343 nselected=-1; 344 } else if(nselected<0 || event==2) { 345 nselected=nslot; 346 }; 347 }; 348 } 349 350 void BankView::OSC_raw(const char *msg) 351 { 352 if(!strcmp(msg, "/bank/search_results")) { 353 const char *ptr = rtosc_argument_string(msg); 354 int slot = 0; 355 356 while (ptr[0] == 's' && ptr[1] == 's') { 357 const char *bank = rtosc_argument(msg, 2*slot).s; 358 const char *fname = rtosc_argument(msg, 2*slot + 1).s; 359 360 /* store search results directly into slot */ 361 slots[slot]->update(bank, fname); 362 if (++slot == 160) 363 break; 364 ptr += 2; 365 } 366 while (slot < 160) 367 slots[slot++]->update("", ""); 368 } else if(!strcmp(rtosc_argument_string(msg), "iss")) { 369 int nslot = rtosc_argument(msg,0).i; 370 const char *name = rtosc_argument(msg,1).s; 371 const char *fname = rtosc_argument(msg,2).s; 372 373 if(0 <= nslot && nslot < 160) 374 slots[nslot]->update(name, fname); 375 } else if(!strcmp(rtosc_argument_string(msg), "ss")) { 376 while(*msg && !isdigit(*msg)) msg++; 377 int nslot = atoi(msg); 378 const char *name = rtosc_argument(msg,0).s; 379 const char *fname = rtosc_argument(msg,1).s; 380 381 if(0 <= nslot && nslot < 160) 382 slots[nslot]->update(name, fname); 383 } 384 } 385 386 void BankView::cbwig(Fl_Widget *w) 387 { 388 cbwig_ = w; 389 } 390 391 void BankView::refresh(void) 392 { 393 assert(osc); 394 //Odd case during initialization 395 if(!osc) 396 return; 397 398 for(int i=0; i<160; ++i) 399 osc->write("/bank/slot"+to_s(i), ""); 400 } 401