1 /** 2 Copyright: Copyright (c) 2014 Andrey Penechko. 3 License: a$(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module anchovy.gui.behaviors.scrollbarbehavior; 8 9 import anchovy.core.math; 10 import anchovy.gui; 11 import anchovy.gui.interfaces.iwidgetbehavior; 12 13 alias ScrollbarBehaviorVert = ScrollbarBehavior!true; 14 alias ScrollbarBehaviorHori = ScrollbarBehavior!false; 15 16 class ScrollbarBehavior(bool vertical) : IWidgetBehavior 17 { 18 protected: 19 Widget _slider; 20 Widget _body; 21 Widget _widget; 22 23 public: 24 25 override void attachPropertiesTo(Widget widget) 26 { 27 widget["sliderSize"] = new ValueProperty(_widget, 0.5); 28 widget["sliderPos"] = new ValueProperty(_widget, 0.0); 29 } 30 31 override void attachTo(Widget widget) 32 { 33 _body = widget["subwidgets"].get!(Widget[string]).get("body", null); 34 _slider = widget["subwidgets"].get!(Widget[string]).get("slider", null); 35 _widget = widget; 36 37 if (_slider && _body) 38 { 39 _body.size.valueChanged.connect((FlexibleObject obj, Variant value){updateSize();}); 40 41 _slider.addEventHandler(&handleSliderDrag); 42 _slider.position.valueChanging.connect(&handleSliderMoving); 43 44 _widget.property("sliderPos").valueChanging.connect(&handleSliderPositionChanging); 45 _widget.property("sliderSize").valueChanging.connect(&handleSliderSizeChanging); 46 _widget.property("sliderSize").valueChanged.connect(&handleSliderSizeChanged); 47 48 updateSize(); 49 } 50 } 51 52 void updateSize() 53 { 54 ivec2 minSize = _slider.getPropertyAs!("minSize", ivec2); 55 ivec2 bodySize = _body.size.value.get!ivec2; 56 57 static if (vertical) 58 { 59 int size = cast(int)(bodySize.y * _widget["sliderSize"].get!double); 60 _slider.setProperty!"size"(ivec2(bodySize.x, max(size, minSize.y))); 61 62 int position = cast(int)((clamp(bodySize.y - _slider["size"].get!ivec2.y, 0, int.max)) * 63 _widget["sliderPos"].get!double); 64 _slider.setProperty!"position"(ivec2(0, position)); 65 } 66 else 67 { 68 int size = cast(int)(bodySize.x * _widget["sliderSize"].get!double); 69 _slider.setProperty!"size"(ivec2(max(size, minSize.x), bodySize.y)); 70 71 int position = cast(int)((clamp(bodySize.x - _slider["size"].get!ivec2.x, 0, int.max)) * 72 _widget["sliderPos"].get!double); 73 _slider.setProperty!"position"(ivec2(position, 0)); 74 } 75 } 76 77 double clampToNormal(double num) 78 { 79 return num < 0 ? 0 : (num > 1.0 ? 1.0 : num); 80 } 81 82 // clamps value to [0.0..1.0] 83 void handleSliderPositionChanging(FlexibleObject widget, Variant* value) 84 { 85 double* val = (*value).peek!double; 86 if (!val) *val = (*value).coerce!double; 87 88 if (val) 89 { 90 *val = clampToNormal(*val); 91 } 92 93 *value = *val; 94 } 95 96 void handleSliderSizeChanging(FlexibleObject widget, Variant* value) 97 { 98 handleSliderPositionChanging(widget, value); 99 } 100 101 void handleSliderSizeChanged(FlexibleObject obj, Variant value) 102 { 103 updateSize(); 104 } 105 106 bool handleSliderDrag(Widget widget, DragEvent event) 107 { 108 _slider["position"] = _slider.getPropertyAs!("position", ivec2) + event.delta; 109 return true; 110 } 111 112 void handleSliderMoving(FlexibleObject slider, Variant* position) 113 { 114 int newPosition; 115 int bodySize; 116 int sliderSize; 117 118 static if (vertical) 119 { 120 int pos = position.get!ivec2.y; 121 bodySize = _body.size.value.get!ivec2.y; 122 sliderSize = _slider.size.value.get!ivec2.y; 123 newPosition = pos < 0 ? 0 : ((pos + sliderSize) > bodySize ? bodySize - sliderSize : pos); 124 (*position) = ivec2(0, newPosition); 125 } 126 else 127 { 128 int pos = position.get!ivec2.x; 129 bodySize = _body.size.value.get!ivec2.x; 130 sliderSize = _slider.size.value.get!ivec2.x; 131 newPosition = pos < 0 ? 0 : ((pos + sliderSize) > bodySize ? bodySize - sliderSize : pos); 132 (*position) = ivec2(newPosition, 0); 133 } 134 135 double sliderPos = cast(double)newPosition / cast(double)(bodySize - sliderSize); 136 _widget["sliderPos"] = sliderPos is double.nan ? 0 : sliderPos; 137 138 //writeln("slider moved ", sliderPos); 139 } 140 141 }