62c74406ed92860cc95a07ad06aae11489d91cae
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / dialog.qc
1 // Note: this class is called Dialog, but it can also handle a tab under the following conditions:
2 // - isTabRoot is 0
3 // - backgroundImage is the tab's background
4 // - closable is 0
5 // - rootDialog is 0
6 // - title is ""
7 // - marginTop is
8 // - intendedHeight ends up to be the tab's actual height, or at least close
9 // - titleFontSize is 0
10 // - marginTop cancels out as much of titleHeight as needed (that is, it should be actualMarginTop - titleHeight)
11 // To ensure the latter, you best create all tabs FIRST and insert the tabbed
12 // control to your dialog THEN - with the right height
13 //
14 // a subclass may help with using this as a tab
15
16 #ifdef INTERFACE
17 CLASS(Dialog) EXTENDS(InputContainer)
18         METHOD(Dialog, configureDialog, void(entity)) // no runtime configuration, all parameters are given in the code!
19         METHOD(Dialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
20         METHOD(Dialog, keyDown, float(entity, float, float, float))
21         METHOD(Dialog, close, void(entity))
22         METHOD(Dialog, addItemSimple, void(entity, float, float, float, float, entity, vector))
23
24         METHOD(Dialog, TD, void(entity, float, float, entity))
25         METHOD(Dialog, TDNoMargin, void(entity, float, float, entity, vector))
26         METHOD(Dialog, TDempty, void(entity, float))
27         METHOD(Dialog, setFirstColumn, void(entity, float))
28         METHOD(Dialog, TR, void(entity))
29         METHOD(Dialog, gotoRC, void(entity, float, float))
30
31         ATTRIB(Dialog, isTabRoot, float, 1)
32         ATTRIB(Dialog, closeButton, entity, NULL)
33         ATTRIB(Dialog, intendedHeight, float, 0)
34         ATTRIB(Dialog, itemOrigin, vector, '0 0 0')
35         ATTRIB(Dialog, itemSize, vector, '0 0 0')
36         ATTRIB(Dialog, itemSpacing, vector, '0 0 0')
37         ATTRIB(Dialog, currentRow, float, 0)
38         ATTRIB(Dialog, currentColumn, float, 0)
39         ATTRIB(Dialog, firstColumn, float, 0)
40
41         // to be customized
42         ATTRIB(Dialog, closable, float, 1)
43         ATTRIB(Dialog, title, string, "Form1") // ;)
44         ATTRIB(Dialog, color, vector, '1 0.5 1')
45         ATTRIB(Dialog, intendedWidth, float, 0)
46         ATTRIB(Dialog, rows, float, 3)
47         ATTRIB(Dialog, columns, float, 2)
48
49         ATTRIB(Dialog, marginTop, float, 0) // pixels
50         ATTRIB(Dialog, marginBottom, float, 0) // pixels
51         ATTRIB(Dialog, marginLeft, float, 0) // pixels
52         ATTRIB(Dialog, marginRight, float, 0) // pixels
53         ATTRIB(Dialog, columnSpacing, float, 0) // pixels
54         ATTRIB(Dialog, rowSpacing, float, 0) // pixels
55         ATTRIB(Dialog, rowHeight, float, 0) // pixels
56         ATTRIB(Dialog, titleHeight, float, 0) // pixels
57         ATTRIB(Dialog, titleFontSize, float, 0) // pixels; if 0, title causes no margin
58         ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0)
59         ATTRIB(Dialog, zoomedOutTitleBar, float, 0)
60
61         ATTRIB(Dialog, requiresConnection, float, 0) // set to true if the dialog requires a connection to be opened
62
63         ATTRIB(Dialog, backgroundImage, string, string_null)
64         ATTRIB(Dialog, borderLines, float, 1)
65         ATTRIB(Dialog, closeButtonImage, string, string_null)
66
67         ATTRIB(Dialog, frame, entity, NULL)
68 ENDCLASS(Dialog)
69 #endif
70
71 #ifdef IMPLEMENTATION
72 void Dialog_Close(entity button, entity me)
73 {
74         me.close(me);
75 }
76
77 void Dialog_fill(entity me)
78 {
79 }
80
81 void Dialog_addItemSimple(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
82 {
83         vector o, s;
84         o = me.itemOrigin + eX * ( col          * me.itemSpacing.x) + eY * ( row          * me.itemSpacing.y);
85         s = me.itemSize   + eX * ((colspan - 1) * me.itemSpacing.x) + eY * ((rowspan - 1) * me.itemSpacing.y);
86         o.x -= 0.5 * (me.itemSpacing.x - me.itemSize.x) * v.x;
87         s.x +=       (me.itemSpacing.x - me.itemSize.x) * v.x;
88         o.y -= 0.5 * (me.itemSpacing.y - me.itemSize.y) * v.y;
89         s.y +=       (me.itemSpacing.y - me.itemSize.y) * v.y;
90         me.addItem(me, e, o, s, 1);
91 }
92
93 void Dialog_gotoRC(entity me, float row, float col)
94 {
95         me.currentRow = row;
96         me.currentColumn = col;
97 }
98
99 void Dialog_TR(entity me)
100 {
101         me.currentRow += 1;
102         me.currentColumn = me.firstColumn;
103 }
104
105 void Dialog_TD(entity me, float rowspan, float colspan, entity e)
106 {
107         me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, '0 0 0');
108         me.currentColumn += colspan;
109 }
110
111 void Dialog_TDNoMargin(entity me, float rowspan, float colspan, entity e, vector v)
112 {
113         me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, v);
114         me.currentColumn += colspan;
115 }
116
117 void Dialog_setFirstColumn(entity me, float col)
118 {
119         me.firstColumn = col;
120 }
121
122 void Dialog_TDempty(entity me, float colspan)
123 {
124         me.currentColumn += colspan;
125 }
126
127 void Dialog_configureDialog(entity me)
128 {
129         float absWidth, absHeight;
130
131         me.frame = spawnBorderImage();
132         me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * me.titleHeight);
133         me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
134         me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
135         me.frame.alpha = me.alpha;
136         me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
137
138         if (!me.titleFontSize)
139                 me.titleHeight = 0; // no title bar
140
141         absWidth = me.intendedWidth * conwidth;
142         absHeight = me.borderLines * me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
143         me.itemOrigin  = eX * (me.marginLeft / absWidth)
144                        + eY * ((me.borderLines * me.titleHeight + me.marginTop) / absHeight);
145         me.itemSize    = eX * ((1 - (me.marginLeft + me.marginRight + me.columnSpacing * (me.columns - 1)) / absWidth) / me.columns)
146                        + eY * (me.rowHeight / absHeight);
147         me.itemSpacing = me.itemSize
148                        + eX * (me.columnSpacing / absWidth)
149                        + eY * (me.rowSpacing / absHeight);
150         me.intendedHeight = absHeight / conheight;
151         me.currentRow = -1;
152         me.currentColumn = -1;
153
154         me.fill(me);
155
156         if(me.closable && me.borderLines > 0)
157         {
158                 entity closebutton;
159                 closebutton = me.closeButton = me.frame.closeButton = spawnButton();
160                 closebutton.configureButton(closebutton, "", 0, me.closeButtonImage);
161                 closebutton.onClick = Dialog_Close; closebutton.onClickEntity = me;
162                 closebutton.srcMulti = 0;
163                 me.addItem(me, closebutton, '0 0 0', '1 1 0', 1); // put it as LAST
164         }
165 }
166
167 void Dialog_close(entity me)
168 {
169         if(me.parent.instanceOfNexposee)
170         {
171                 ExposeeCloseButton_Click(me, me.parent);
172         }
173         else if(me.parent.instanceOfModalController)
174         {
175                 DialogCloseButton_Click(me, me);
176         }
177 }
178
179 float Dialog_keyDown(entity me, float key, float ascii, float shift)
180 {
181         if(me.closable)
182         {
183                 if(key == K_ESCAPE)
184                 {
185                         me.close(me);
186                         return 1;
187                 }
188         }
189         return SUPER(Dialog).keyDown(me, key, ascii, shift);
190 }
191 #endif