1 /**
2  * Widget module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.widget.panedwindow;
8 
9 /**
10  * Imports.
11  */
12 import std.array;
13 import tkd.element.uielement;
14 import tkd.widget.common.height;
15 import tkd.widget.common.width;
16 import tkd.widget.orientation;
17 import tkd.widget.widget;
18 
19 /**
20  * A paned window widget displays a number of subwindows, stacked either 
21  * vertically or horizontally. The user may adjust the relative sizes of the 
22  * subwindows by dragging the sash between panes.
23  *
24  * Example:
25  * ---
26  * // The paned window must be created first.
27  * // See the constructor notes in the documentation.
28  * auto panedWindow = new PanedWindow();
29  *
30  * // The pane's widgets are contained within the frames.
31  * auto left = new Frame(panedWindow);
32  * auto right = new Frame(panedWindow);
33  *
34  * panedwindow.addPane(left)
35  * 	.addPane(right)
36  * 	.pack();
37  * ---
38  *
39  * Common_Commands:
40  *     These are injected common commands that can also be used with this widget.
41  *     $(P
42  *         $(LINK2 ./common/height.html, Height) $(BR)
43  *         $(LINK2 ./common/width.html, Width) $(BR)
44  *     )
45  *
46  * Additional_Events:
47  *     Additional events that can also be bound to using the $(LINK2 ../element/uielement.html#UiElement.bind, bind) method.
48  *     $(P
49  *         <<EnteredChild>>,
50  *         <<PrevWindow>>,
51  *         <Alt-Key>,
52  *         <B1-Motion>,
53  *         <Button-1>,
54  *         <ButtonRelease-1>,
55  *         <Enter>,
56  *         <Key-F10>,
57  *         <Key-Tab>,
58  *         <Leave>,
59  *         <Motion>,
60  *     )
61  *
62  * See_Also:
63  *     $(LINK2 ./widget.html, tkd.widget.widget)
64  */
65 class PanedWindow : Widget
66 {
67 	/**
68 	 * Construct the widget.
69 	 *
70 	 * Params:
71 	 *     parent = The parent of this widget.
72 	 *     orientation = The orientation of the widget.
73 	 *
74 	 * Bugs:
75 	 *     Because this widget contains and handles other widget's geometry, it 
76 	 *     must be created before the child panes and not chained with methods 
77 	 *     that add new tabs. If it is chained, tabs will not be handled 
78 	 *     correctly and might not show at all. This seems to be a limitation 
79 	 *     with Tcl/Tk.
80 	 *
81 	 * See_Also:
82 	 *     $(LINK2 ../element/uielement.html, tkd.element.UiElement) $(BR)
83 	 *     $(LINK2 ./orientation.html, tkd.widget.orientation) for orientations.
84 	 */
85 	public this(UiElement parent, string orientation = Orientation.vertical)
86 	{
87 		super(parent);
88 		this._elementId = "panedwindow";
89 
90 		this._tk.eval("ttk::panedwindow %s -orient %s", this.id, orientation);
91 	}
92 
93 	/**
94 	 * Construct the widget.
95 	 *
96 	 * Params:
97 	 *     orientation = The orientation of the widget.
98 	 *
99 	 * Bugs:
100 	 *     Because this widget contains and handles other widget's geometry, it 
101 	 *     must be created before the child panes and not chained with methods 
102 	 *     that add new tabs. If it is chained, tabs will not be handled 
103 	 *     correctly and might not show at all. This seems to be a limitation 
104 	 *     with Tcl/Tk.
105 	 *
106 	 * See_Also:
107 	 *     $(LINK2 ./orientation.html, tkd.widget.orientation) for orientations.
108 	 */
109 	public this(string orientation = Orientation.vertical)
110 	{
111 		this(null, orientation);
112 	}
113 
114 	/**
115 	 * Add a pane to the paned window. When adding a pane to the paned window 
116 	 * the pane gains an id that is equal to the passed widget's id and can be 
117 	 * used later to refer to the new pane.
118 	 *
119 	 * Params:
120 	 *     widget = The widget to add as the pane.
121 	 *
122 	 * Returns:
123 	 *     This widget to aid method chaining.
124 	 */
125 	public auto addPane(this T)(Widget widget)
126 	{
127 		this.insertPane("end", widget);
128 
129 		return cast(T) this;
130 	}
131 
132 	/**
133 	 * Insert a pane into the paned window at a specified zero based index or 
134 	 * before another pane id. When adding a pane to the paned window for the 
135 	 * first time the pane gains an id that is equal to the passed widget's id 
136 	 * and can be used later to refer to the new pane. If the id of the widget 
137 	 * passed is already used as a pane id then that existing one will be moved 
138 	 * to the new position.
139 	 *
140 	 * Params:
141 	 *     paneIdentifier = The zero based index or string id of the pane.
142 	 *     widget = The widget to add as the pane.
143 	 *
144 	 * Returns:
145 	 *     This widget to aid method chaining.
146 	 */
147 	public auto insertPane(this T, I)(I paneIdentifier, Widget widget) if (is(I == int) || is(I == string))
148 	{
149 		this._tk.eval("%s insert %s %s", this.id, paneIdentifier, widget.id);
150 
151 		return cast(T) this;
152 	}
153 
154 	/**
155 	 * Remove a pane from the paned window.
156 	 *
157 	 * Params:
158 	 *     paneIdentifier = The zero based index or string id of the pane.
159 	 *
160 	 * Returns:
161 	 *     This widget to aid method chaining.
162 	 */
163 	public auto removePane(this T, I)(I paneIdentifier) if (is(I == int) || is(I == string))
164 	{
165 		this._tk.eval("%s forget %s", this.id, paneIdentifier);
166 
167 		return cast(T) this;
168 	}
169 
170 	/**
171 	 * Set the pane weight. Weight is an integer specifying the relative 
172 	 * stretchability of the pane. When the paned window is resized, the extra 
173 	 * space is added or subtracted to each pane proportionally to its weight.
174 	 *
175 	 * Params:
176 	 *     paneIdentifier = The zero based index or string id of the pane.
177 	 *     weight = The new weight of the pane.
178 	 *
179 	 * Returns:
180 	 *     This widget to aid method chaining.
181 	 */
182 	public auto setPaneWeight(this T, I)(I paneIdentifier, int weight)
183 	{
184 		this._tk.eval("%s pane %s -weight %s", this.id, paneIdentifier, weight);
185 
186 		return cast(T) this;
187 	}
188 
189 	/**
190 	 * Get an array of all the current pane id's.
191 	 *
192 	 * Returns:
193 	 *     An array containing all the pane id's.
194 	 */
195 	public string[] getPaneIds()
196 	{
197 		this._tk.eval("%s panes", this.id);
198 		return this._tk.getResult!(string).split();
199 	}
200 
201 	/**
202 	 * Sets the position of a sash. May adjust the positions of adjacent sashes 
203 	 * to ensure that positions are monotonically increasing.  Sash positions 
204 	 * are further constrained to be between 0 and the total size of the 
205 	 * widget. Must be called after the UI has been drawn.
206 	 *
207 	 * Params:
208 	 *     sashIndex = The index of the sash.
209 	 *     position = The new position of the sash.
210 	 */
211 	public auto setSashPosition(this T)(int sashIndex, int position)
212 	{
213 		this._tk.eval("%s sashpos %s %s", this.id, sashIndex, position);
214 
215 		return cast(T) this;
216 	}
217 
218 	/**
219 	 * Get the position of a sash. Must be called after the UI has been drawn.
220 	 *
221 	 * Params:
222 	 *     sashIndex = The index of the sash.
223 	 */
224 	public int getSashPosition(this T)(int sashIndex)
225 	{
226 		this._tk.eval("%s sashpos %s", this.id, sashIndex);
227 		return this._tk.getResult!(int);
228 	}
229 
230 	/**
231 	 * Mixin common commands.
232 	 */
233 	mixin Height;
234 	mixin Width;
235 }