OSDN Git Service

first
[psychlops/cpp.git] / psychlops / extension / standard / widgets / psychlops_widgets.cpp
1 /*
2  *  psychlops_figure_prototype.cpp
3  *  Psychlops Standard Library (Universal)
4  *
5  *  Last Modified 2009/02/15 by Kenchi HOSOKAWA
6  *  (C) 2009 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
7  */
8
9 #include "psychlops_widget.h"
10 #include "psychlops_widgets.h"
11 #include "psychlops_widgets_prototype.h"
12 #include "../../../core/ApplicationInterfaces/psychlops_code_snippets.h"
13
14 namespace Psychlops {
15
16
17 namespace Widgets {
18
19
20
21
22
23         // TextBlock
24         void TextBlock::initialize()
25         {
26                 if(!initialized)
27                 {
28                         area.fill = Color::gray;
29                         area.stroke = Stroke::hair_line;
30                         area.set( content.length()*label.font.size, label.font.size + 4 );
31                         area.shift( -area.getWidth()/2, -label.font.size/2 - 2 );
32
33                         label.fill = Color::white;
34                         label.stroke = Stroke::hair_line;
35                         label.shift(0, label.font.size/4 - 1 );
36                         label.align = Letters::TEXT_ALIGN_CENTER;
37
38                         append(&area);
39                         append(&label);
40                 }
41         }
42         TextBlock::TextBlock()
43         {
44                 initialized = false;
45         }
46         TextBlock::TextBlock(std::wstring s, double hei)
47         {
48                 initialized = false;
49                 setText(s);
50                 initialize();
51         }
52
53         Point TextBlock::getHitDatum()
54         {
55                 return getDatum();
56         }
57         TextBlock& TextBlock::set(const std::wstring s, double hei)
58         {
59                 setText(content);
60                 initialize();
61                 return *this;
62         }
63         TextBlock& TextBlock::set(double w, double h)
64         {
65                 initialized = false;
66                 area.set(w,h);
67                 initialize();
68                 return *this;
69         }
70         void TextBlock::setText(const std::wstring &str)
71         {
72                 content = str;
73                 label.setString(content);
74                 initialize();
75         }
76         std::wstring& TextBlock::getText()
77         {
78                 return content;
79         }
80
81
82
83
84         void Button_::evokeP(Events::Evoke &ev)
85         {
86                 if(onClick!=0) (*onClick)();
87         }
88         void Button_::evokeMouse(Events::MouseLeftUp &ev)
89         {
90                 Events::Evoke e;
91                 getSlots().emit(e);
92         }
93         Button_::Button_()
94         {
95                 onClick = 0;
96                 initialized = false;
97                 getSlots().connectEventDelegate(this, &Button_::evokeMouse);
98                 getSlots().connectEventDelegate(this, &Button_::evokeP);
99         }
100         Button_::Button_(std::wstring s, double hei)
101         {
102                 onClick = 0;
103                 initialized = false;
104                 setText(s);
105                 initialize();
106                 getSlots().connectEventDelegate(this, &Button_::evokeMouse);
107                 getSlots().connectEventDelegate(this, &Button_::evokeP);
108         }
109         void Button_::onEvoked(void (*f)())
110         {
111                 getSlots().connectActionFunction<Events::Evoke>(f);
112         }
113         //Button_& Button_::set(double w, double h)
114         //{
115         //      TextBlock::set(w,h);
116         //      return *this;
117         //}
118
119
120
121
122
123         // Deplecated Widgets
124
125
126         void TextBox::setBase()
127         {
128                 cache.fill = Color::white;
129                 area.fill = Color::null_color;
130                 area.stroke = Stroke::hair_line;
131         }
132         TextBox::TextBox()
133         {
134                 setBase();
135         }
136         TextBox::TextBox(std::wstring s)
137         {
138                 setBase();
139         }
140         TextBox& TextBox::set(std::wstring s)
141         {
142                 setBase();
143                 return *this;
144         }
145         TextBox& TextBox::draw(Drawable &target)
146         {
147 //              if(!tabStopRegistered) { TabStopHotKey::tabStopHotKey.set(this); tabStopRegistered=true; }
148                 if(getLeft()<1 && getTop()<1) WidgetRect::__autoAlign(*this);
149
150                 area.draw(target);
151                 cache.setString(content);
152                 cache.draw(target);
153                 return *this;
154         }
155         void TextBox::setText(const std::wstring &str)
156         {
157                 content = str;
158         }
159         std::wstring& TextBox::getText()
160         {
161                 return content;
162         }
163
164
165         namespace Internal
166         {
167                 void doNothing() {}
168                 void doNothingP(void *p) {}
169         }
170
171         Button::Button()
172         {
173                 setBase();
174         }
175         Button::Button(std::wstring s)
176         {
177                 set(s);
178         }
179         Button::Button(std::wstring s, double size)
180         {
181                 set(s, size);
182         }
183         void Button::setBase() {
184                 onClick = 0;
185                 onClickP = 0;
186                 arg = 0;
187         }
188         Button& Button::set(std::wstring s, double size) {
189                 setBase();
190                 WidgetRect::set(s, size);
191                 return *this;
192         }
193         Button& Button::set(double w, double h)
194         {
195                 setBase();
196                 WidgetRect::set(w, h);
197                 return *this;
198         }
199         Button& Button::draw(Drawable &target) {
200 //              if(!tabStopRegistered) { TabStopHotKey::tabStopHotKey.set(this); tabStopRegistered=true; }
201                 if(getLeft()<1 && getTop()<1) WidgetRect::__autoAlign(*this);
202
203                 Point mouse = drawableMouse(target);
204                 if(area.include(mouse)) {
205                         area.fill = theme->over_background[theme_type];
206                         if(mleft.pushed()) {
207                                 pushThis();
208                                 if(onClick!=0) onClick();
209                                 if(onClickP!=0) onClickP(arg);
210                                 label.fill = theme->active_foreground[theme_type];
211                                 area.stroke = theme->active_stroke[theme_type];
212                         }
213                 } else {
214                         label.fill = theme->normal_foreground[theme_type];
215                         area.fill = theme->normal_background[theme_type];
216                         area.stroke = theme->normal_stroke[theme_type];
217                 }
218
219                 area.draw(target);
220                 Canvas* tag = dynamic_cast<Canvas*>(&target);
221                 if(tag!=0) tag->drawImage(*(theme->button_back), area);
222                 //label.align = Letters::TEXT_ALIGN_CENTER;
223                 label.centering(area.getCenter().x, area.getBottom()-2);
224                 label.draw(label.fill, target);
225                 return *this;
226         }
227
228         ToggleButton::ToggleButton()
229         : Button(), checked_(false) {
230         }
231         ToggleButton::ToggleButton(std::wstring s)
232         : Button(s), checked_(false) {
233         }
234         ToggleButton::ToggleButton(std::wstring s, double size)
235         : Button(s, size), checked_(false) {
236         }
237         bool ToggleButton::toggle()
238         {
239                 pushed_ = true;
240                 checked_ = !checked_;
241                 return checked_;
242         }
243         bool ToggleButton::toggle(bool on_off)
244         {
245                 pushed_ = true;
246                 checked_ = on_off;
247                 return checked_;
248         }
249         bool ToggleButton::isChecked()
250         {
251                 return checked_;
252         }
253         ToggleButton& ToggleButton::draw(Drawable &target)
254         {
255 //              if(!tabStopRegistered) { TabStopHotKey::tabStopHotKey.set(this); tabStopRegistered=true; }
256                 if(getLeft()<1 && getTop()<1) WidgetRect::__autoAlign(*this);
257
258                 Point mouse = drawableMouse(target);
259                 if(area.include(mouse)) {
260                         area.fill = isChecked() ? theme->active_background[theme_type] : theme->over_background[theme_type];
261                         if(mleft.pushed()) {
262                                 toggle();
263                                 pushed_ = true;
264                                 if(onClick!=0) onClick();
265                                 if(onClickP!=0) onClickP(arg);
266                                 label.fill = theme->active_foreground[theme_type];
267                                 area.stroke = theme->active_stroke[theme_type];
268                         }
269                 } else {
270                         if(isChecked()){
271                                 label.fill = theme->active_foreground[theme_type];
272                                 area.fill = theme->active_background[theme_type];
273                                 area.stroke = theme->active_stroke[theme_type];
274                         } else {
275                                 label.fill = theme->normal_foreground[theme_type];
276                                 area.fill = theme->normal_background[theme_type];
277                                 area.stroke = theme->normal_stroke[theme_type];
278                         }
279                 }
280
281                 area.draw(target);
282                 Canvas* tag = dynamic_cast<Canvas*>(&target);
283                 if(tag!=0) tag->drawImage(*(theme->button_back), area);
284                 label.centering(area.getCenter().x, area.getBottom()-2);
285                 label.draw(label.fill, target);
286                 return *this;
287         }
288
289
290
291         Image ScreenShotButton::buffer;
292         void ScreenShotButton::shoot(void *ffname)
293         {
294                 Psychlops::Rectangle rect(Display::the_canvas->getWidth(), Display::the_canvas->getHeight());
295                 Display::the_canvas->to(buffer, rect);
296                 std::string fname("psychlops_");
297                 fname += (char*)ffname;
298                 fname += ".png";
299                 buffer.save(fname);
300         }
301         ScreenShotButton::ScreenShotButton(char *name__)
302         : Button(L"Capture")
303         {
304                 name = name__;
305                 arg = (void*)name.c_str();
306                 onClickP = &shoot;
307         }
308
309
310         const Interval Slider::def_itvl(0, Interval::CLOSE, 1, Interval::CLOSE);
311         Slider::~Slider()
312         {
313                 if(isLocal_ && var!=0) delete var;
314         }
315         Slider::Slider()
316         : WidgetRect()
317         {
318                 var = 0;
319                 scale_mode = LINEAR;
320                 setBase();
321                 //StackPanel::default_stack.append(this);
322         }
323         Slider::Slider(ExperimentalMethods::Variable &v)
324         : WidgetRect()
325         {
326                 var = 0;
327                 scale_mode = LINEAR;
328                 setBase();
329                 set(v);
330                 //StackPanel::default_stack.append(this);
331         }
332         Slider::Slider(double wid, double hei)
333         : WidgetRect()
334         {
335                 var = 0;
336                 scale_mode = LINEAR;
337                 WidgetRect::set(wid, hei);
338                 setBase();
339                 Interval rng;
340                 link(local, 0<=rng<=1, 0.125, 10.0);
341                 //StackPanel::default_stack.append(this);
342         }
343         Slider::Slider(std::string s, Interval rng, double d_step, double e_step)
344         : WidgetRect()
345         {
346                 var = 0;
347                 scale_mode = LINEAR;
348                 setBase();
349                 link(local, s, rng, d_step, e_step);
350                 setLabel(s);
351                 //StackPanel::default_stack.append(this);
352         }
353         void Slider::setBase() {
354                 show_value = true;
355                 isLocal_ = false;
356                 changed_ = true;
357                 area.fill = Color(0.3);
358                 internal.fill = Color::blue;
359                 dragged = false;
360                 local = 0;
361                 setSize(150, Font::default_font.size - 4);
362         }
363         Slider& Slider::set(ExperimentalMethods::Variable &v)
364         {
365                 set(v.label);
366                 return linkTo(&v);
367         }
368         Slider& Slider::setSize(double wid, double hei)
369         {
370                 WidgetRect::set(wid, hei);
371                 label.fill = Color::white;
372                 label.align = Letters::TEXT_ALIGN_LEFT;
373                 show_value = label.getString().length()*area.getHeight()*2/3 < area.getWidth();
374                 return *this;
375         }
376         Slider& Slider::set(std::string s, Interval rng, double d_step, double e_step)
377         {
378                 if(var==0) {
379                         link(local, s, rng, d_step, e_step);
380                 } else {
381                         var->setInterval(rng);
382                         //var->set(s, rng, d_step, e_step);
383                 }
384                 return *this;
385         }
386         /*
387         Slider& Slider::set(std::string s, double hei) { return set(StringToWString(s), hei); }
388         Slider& Slider::set(std::wstring s, double hei)
389         {
390                 WidgetRect::set(s, hei);
391                 label.fill = Color::white;
392                 label.align = Letters::TEXT_ALIGN_LEFT;
393                 show_value = label.getString().length()*area.getHeight()*2/3 < area.getWidth();
394                 return *this;
395         }
396         */
397         Slider& Slider::setLabel(std::string s) { return setLabel(StringToWString(s)); }
398         Slider& Slider::setLabel(std::wstring s)
399         {
400                 WidgetRect::setLabel(s);
401                 label.fill = Color::white;
402                 label.align = Letters::TEXT_ALIGN_LEFT;
403                 show_value = label.getString().length()*area.getHeight()*2/3 < area.getWidth();
404                 return *this;
405         }
406         Slider& Slider::draw(Drawable &target)
407         {
408                 if(!tabStopRegistered) { TabStopHotKey::tabStopHotKey.set(this); tabStopRegistered=true; }
409                 if(getLeft()<1 && getTop()<1) WidgetRect::__autoAlign(*this);
410
411                 Point mouse = drawableMouse(target);
412                 bool mouse_over = area.include(mouse), focused = true;
413                 if(Display::the_canvas!=0) focused = Display::the_canvas->eventroot.isFocused__(this);
414                 Canvas* cnvs = dynamic_cast<Canvas*>(&target);
415
416                 if(var!=0) {
417                         area.draw(target);
418
419                         if(mleft.pushed() && mouse_over) { dragged = true; pushThis(); }
420                         if(mleft.pressed() && dragged) {
421                                 if(area.getWidth()>area.getHeight()) { var->setByRatioInStep((mouse.x-area.getLeft())/area.getWidth()); changed_=true; }
422                                 else { var->setByRatioInStep((area.getBottom()-mouse.y)/area.getHeight()); changed_=true; }
423                         }
424                         if(focused) {
425                                 if(Keyboard::left.pressed()) { if(pressFrame<=0) { var->decrement(Keyboard::shift.pressed()); changed_=true; pressFrame = pressFrame==0 ? HumanInterfaceDevice::pushRepeatInterval : HumanInterfaceDevice::pushRepeatFrames; } }
426                                 else if(Keyboard::right.pressed()) { if(pressFrame<=0) { var->increment(Keyboard::shift.pressed()); changed_=true; pressFrame = pressFrame==0 ? HumanInterfaceDevice::pushRepeatInterval : HumanInterfaceDevice::pushRepeatFrames; } }
427                                 else { pressFrame = -1; }
428                                 if(pressFrame>0) pressFrame--;
429                         }
430                         if(!mleft.pressed()) dragged = false;
431
432                         if(area.getWidth()>area.getHeight()) {
433                                 internal.set(area.getLeft()+1, area.getTop()+1, area.getLeft()+area.getWidth()*(var->getRatio()), area.getBottom()-1).draw(target);
434                         } else {
435                                 internal.set(area.getLeft()+1, area.getBottom()-area.getHeight()*(var->getRatio()), area.getRight()-1, area.getBottom()-1).draw(target);
436                         }
437                         area.draw(mouse_over ? Stroke::hair_line : Stroke::null_line);
438                         label.locate(area.getLeft()+5, area.getBottom()-2);
439                         if(focused) {
440                                 label.draw(Color::white, target);
441                                 if(cnvs!=0 && show_value) cnvs->msg(var->to_str(), area.getRight()-2, area.getBottom()-5, Color::white, Letters::TEXT_ALIGN_RIGHT);
442                         } else {
443                                 label.draw(Color::gray, target);
444                                 if(cnvs!=0 && show_value) cnvs->msg(var->to_str(), area.getRight()-2, area.getBottom()-5, Color::gray, Letters::TEXT_ALIGN_RIGHT);
445                         }
446                 }
447
448                 return *this;
449         }
450         Slider& Slider::linkTo(ExperimentalMethods::Variable *v)
451         {
452                 var = v;
453                 return *this;
454         }
455         Slider& Slider::operator =(ExperimentalMethods::Variable &v)
456         {
457                 return set(v);
458         }
459         bool Slider::changed()
460         {
461                 bool tmp = changed_;
462                 changed_ = false;
463                 return tmp;
464         }
465         Slider::operator double()
466         {
467                 return local;
468         }
469         double Slider::operator =(double v)
470         {
471                 return local = v;
472         }
473         void Slider::setByRatio(double ratio) { var->setByRatio(ratio); }
474         double Slider::getRatio() const { return var->getRatio(); }
475         Interval Slider::getInterval() const { return var->getInterval(); }
476         Interval Slider::setInterval(const Interval &itvl) { return var->setInterval(itvl); }
477         void Slider::increment(int modulation) { var->increment(modulation); }
478         void Slider::decrement(int modulation) { var->decrement(modulation); }
479
480
481         Dial::Dial() {
482                 set(50);
483                 setBase();
484         }
485         Dial::Dial(double r) {
486                 set(r);
487                 setBase();
488         }
489         void Dial::setBase() {
490                 local = 0;
491                 link(local);
492                 changed_ = true;
493                 current_theta = factor = 0;
494                 pressed = dragged = false;
495                 ext.fill = Color(0.3);
496                 internal.fill = Color::black;
497         }
498         Dial& Dial::set(double r) {
499                 ext.set(r,r);
500                 internal.set(r/5, r/5);
501                 return *this;
502         }
503         Dial& Dial::link(double &item, double fac)
504         {
505                 var = &item;
506                 factor = fac;
507                 let.align = Letters::TEXT_ALIGN_CENTER;
508                 return *this;
509         }
510         Dial& Dial::draw(Drawable &target) {
511                 Point mouse = drawableMouse(target);
512                 ext.centering(getDatum());
513                 bool mouse_over = ext.include(mouse);
514                 target.ellipse(ext, ext.fill);
515                 if(!pressed && Mouse::left.pressed() && mouse_over) {
516                         dragged = true;
517                         former_theta = atan2(mouse.y-ext.getCenter().y, mouse.x-ext.getCenter().x);
518                 }
519                 if(mouse_over || dragged) {
520                         target.ellipse(ext, Stroke::hair_line);
521                         if(Keyboard::left.pressed()) { current_theta-=2*PI/36; (*var) = *var-factor/36; changed_=true; }
522                         if(Keyboard::right.pressed()) { current_theta+=2*PI/36; (*var) = *var+factor/36; changed_=true; }
523                 }
524                 pressed = Mouse::left.pressed();
525                 if(Mouse::left.pressed() && dragged) {
526                         current_theta = atan2(mouse.y-ext.getCenter().y, mouse.x-ext.getCenter().x);
527                         double delta_theta = Math::mod(current_theta-former_theta, 2*PI);
528                         if(delta_theta>PI) delta_theta-=2*PI;
529                         (*var) = *var+delta_theta/2/PI*factor;
530                         changed_ = true;
531                         former_theta = current_theta;
532                 } else {
533                         dragged = false;
534                 }
535                 internal.centering(ext).shift(ext.getWidth()/2.2*cos(current_theta), ext.getWidth()/2.2*sin(current_theta));
536                 target.ellipse(internal, internal.fill);
537                 //let.centering(ext.getCenter().x, ext.getBottom());
538                 //let.draw(let.fill, target);
539                 return *this;
540         }
541         bool Dial::changed() {
542                 bool tmp = changed_;
543                 changed_ = false;
544                 return tmp;
545         }
546         Dial::operator double() {
547                 return local;
548         }
549         double Dial::operator =(double v) {
550                 return local = v;
551         }
552
553
554         SelectBox::SelectBox()
555         : WidgetRect()
556         {
557                 set(Font::default_font.size);
558         }
559         SelectBox::SelectBox(double size)
560         : WidgetRect()
561         {
562                 set(size);
563         }
564         SelectBox& SelectBox::set(double hei)
565         {
566                 return set(0, hei);
567         }
568         SelectBox& SelectBox::set(double wid, double hei)
569         {
570                 selected_ = 0;
571                 vertical_ = false;
572                 area.resize(wid, hei);
573                 return *this;
574         }
575         void SelectBox::makeVertical()
576         {
577                 area.resize(area.getHeight(), area.getWidth());
578                 vertical_ = true;
579         }
580         void SelectBox::appendL(Letters &let)
581         {
582                 area.resize(Math::max(area.getWidth(), let.getString().length()*Font::default_font.size), area.getHeight());
583                 let.fill = theme->normal_foreground[theme_type];
584                 let.font.size = area.getHeight() - 4;;
585                 item.push_back(let);
586         }
587         int SelectBox::getSelected() { return selected_; }
588         void SelectBox::setSelected(int dd) { selected_ = Math::min( Math::max(dd, 0), item.size() ); }
589         void SelectBox::next() { if(selected_<item.size()-1) { ++selected_; } else { selected_ = 0; }  }
590         void SelectBox::retreat() { if(selected_>0) { --selected_; } else { selected_ = item.size()-1; } }
591         void SelectBox::hid()
592         {
593                 int wheel = Mouse::getWheelDelta().y;
594                 if(wheel<0) {
595                         pushThis();
596                         area.stroke = theme->active_stroke[theme_type];
597                         retreat();
598                 }
599                 if(wheel>0 || mleft.pushed()) {
600                         pushThis();
601                         area.stroke = theme->active_stroke[theme_type];
602                         next();
603                 }
604         }
605         SelectBox& SelectBox::draw(Drawable &target)
606         {
607                 Point mouse = drawableMouse(target);
608                 if(area.include(mouse)) {
609                         area.stroke = theme->normal_stroke[theme_type];
610                         hid();
611                         area.fill = theme->over_background[theme_type];
612                 } else {
613                         area.stroke = theme->normal_stroke[theme_type];
614                         area.fill = theme->normal_background[theme_type];
615                 }
616
617                 area.draw(target);
618                 Canvas* tag = dynamic_cast<Canvas*>(&target);
619                 if(tag!=0) tag->drawImage(*(theme->button_back), area);
620                 if(!vertical_) {
621                         if(!item.empty()) {
622                                 item[selected_].locate(area.getLeft()+5, area.getBottom()-2);
623                                 item[selected_].draw(item[selected_].fill, target);
624                         }
625                 } else {
626                         holder_.contents.clear();
627                         if(!item.empty()) {
628                                 holder_.setDatum(Point(area.getLeft()+2, area.getTop()-5));
629                                 holder_.append(item[selected_]);
630                                 item[selected_].setDatum(Point(0,0)).shift(5, item[selected_].getFont().size);
631                                 holder_.rotation = PI/2;
632                                 holder_.draw(target);
633                         }
634                 }
635                 return *this;
636         }
637
638
639         TitleBar *TitleBar::default_titlebar;
640
641
642
643
644
645 }       /*      <- namespace Widgets    */
646 }       /*      <- namespace Psycholops         */
647
648