Merge branch 'terencehill/menu_remove_tab_title' into 'master'
[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 #ifndef ITEM_DIALOG_H
17 #define ITEM_DIALOG_H
18 #include "inputcontainer.qc"
19 CLASS(Dialog, InputContainer)
20         METHOD(Dialog, configureDialog, void(entity)) // no runtime configuration, all parameters are given in the code!
21         METHOD(Dialog, fill, void(entity)) // to be overridden by user to fill the dialog with controls
22         METHOD(Dialog, keyDown, float(entity, float, float, float))
23         METHOD(Dialog, close, void(entity))
24         METHOD(Dialog, addItemSimple, void(entity, float, float, float, float, entity, vector))
25
26         METHOD(Dialog, TD, void(entity, float, float, entity))
27         METHOD(Dialog, TDNoMargin, void(entity, float, float, entity, vector))
28         METHOD(Dialog, TDempty, void(entity, float))
29         METHOD(Dialog, setFirstColumn, void(entity, float))
30         METHOD(Dialog, TR, void(entity))
31         METHOD(Dialog, gotoRC, void(entity, float, float))
32
33         ATTRIB(Dialog, isTabRoot, float, 1)
34         ATTRIB(Dialog, closeButton, entity, NULL)
35         ATTRIB(Dialog, intendedHeight, float, 0)
36         ATTRIB(Dialog, itemOrigin, vector, '0 0 0')
37         ATTRIB(Dialog, itemSize, vector, '0 0 0')
38         ATTRIB(Dialog, itemSpacing, vector, '0 0 0')
39         ATTRIB(Dialog, currentRow, float, 0)
40         ATTRIB(Dialog, currentColumn, float, 0)
41         ATTRIB(Dialog, firstColumn, float, 0)
42
43         // to be customized
44         ATTRIB(Dialog, closable, float, 1)
45         ATTRIB(Dialog, title, string, "Form1") // ;)
46         ATTRIB(Dialog, color, vector, '1 0.5 1')
47         ATTRIB(Dialog, intendedWidth, float, 0)
48         ATTRIB(Dialog, rows, float, 3)
49         ATTRIB(Dialog, columns, float, 2)
50
51         ATTRIB(Dialog, marginTop, float, 0) // pixels
52         ATTRIB(Dialog, marginBottom, float, 0) // pixels
53         ATTRIB(Dialog, marginLeft, float, 0) // pixels
54         ATTRIB(Dialog, marginRight, float, 0) // pixels
55         ATTRIB(Dialog, columnSpacing, float, 0) // pixels
56         ATTRIB(Dialog, rowSpacing, float, 0) // pixels
57         ATTRIB(Dialog, rowHeight, float, 0) // pixels
58         ATTRIB(Dialog, titleHeight, float, 0) // pixels
59         ATTRIB(Dialog, titleFontSize, float, 0) // pixels; if 0, title causes no margin
60         ATTRIB(Dialog, zoomedOutTitleBarPosition, float, 0)
61         ATTRIB(Dialog, zoomedOutTitleBar, float, 0)
62
63         ATTRIB(Dialog, requiresConnection, float, 0) // set to true if the dialog requires a connection to be opened
64
65         ATTRIB(Dialog, backgroundImage, string, string_null)
66         ATTRIB(Dialog, borderLines, float, 1)
67         ATTRIB(Dialog, closeButtonImage, string, string_null)
68
69         ATTRIB(Dialog, frame, entity, NULL)
70 ENDCLASS(Dialog)
71 #endif
72
73 #ifdef IMPLEMENTATION
74 void Dialog_Close(entity button, entity me)
75 {
76         me.close(me);
77 }
78
79 void Dialog_fill(entity me)
80 {
81 }
82
83 void Dialog_addItemSimple(entity me, float row, float col, float rowspan, float colspan, entity e, vector v)
84 {
85         vector o, s;
86         o = me.itemOrigin + eX * ( col          * me.itemSpacing.x) + eY * ( row          * me.itemSpacing.y);
87         s = me.itemSize   + eX * ((colspan - 1) * me.itemSpacing.x) + eY * ((rowspan - 1) * me.itemSpacing.y);
88         o.x -= 0.5 * (me.itemSpacing.x - me.itemSize.x) * v.x;
89         s.x +=       (me.itemSpacing.x - me.itemSize.x) * v.x;
90         o.y -= 0.5 * (me.itemSpacing.y - me.itemSize.y) * v.y;
91         s.y +=       (me.itemSpacing.y - me.itemSize.y) * v.y;
92         me.addItem(me, e, o, s, 1);
93 }
94
95 void Dialog_gotoRC(entity me, float row, float col)
96 {
97         me.currentRow = row;
98         me.currentColumn = col;
99 }
100
101 void Dialog_TR(entity me)
102 {
103         me.currentRow += 1;
104         me.currentColumn = me.firstColumn;
105 }
106
107 void Dialog_TD(entity me, float rowspan, float colspan, entity e)
108 {
109         me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, '0 0 0');
110         me.currentColumn += colspan;
111 }
112
113 void Dialog_TDNoMargin(entity me, float rowspan, float colspan, entity e, vector v)
114 {
115         me.addItemSimple(me, me.currentRow, me.currentColumn, rowspan, colspan, e, v);
116         me.currentColumn += colspan;
117 }
118
119 void Dialog_setFirstColumn(entity me, float col)
120 {
121         me.firstColumn = col;
122 }
123
124 void Dialog_TDempty(entity me, float colspan)
125 {
126         me.currentColumn += colspan;
127 }
128
129 void Dialog_configureDialog(entity me)
130 {
131         float absWidth, absHeight;
132
133         if(me.isTabRoot)
134         {
135                 me.frame = NEW(BorderImage);
136                 me.frame.configureBorderImage(me.frame, me.title, me.titleFontSize, me.color, me.backgroundImage, me.borderLines * me.titleHeight);
137                 me.frame.zoomedOutTitleBarPosition = me.zoomedOutTitleBarPosition;
138                 me.frame.zoomedOutTitleBar = me.zoomedOutTitleBar;
139                 me.frame.alpha = me.alpha;
140                 me.addItem(me, me.frame, '0 0 0', '1 1 0', 1);
141         }
142
143         if (!me.titleFontSize)
144                 me.titleHeight = 0; // no title bar
145
146         absWidth = me.intendedWidth * conwidth;
147         absHeight = me.borderLines * me.titleHeight + me.marginTop + me.rows * me.rowHeight + (me.rows - 1) * me.rowSpacing + me.marginBottom;
148         me.itemOrigin  = eX * (me.marginLeft / absWidth)
149                        + eY * ((me.borderLines * me.titleHeight + me.marginTop) / absHeight);
150         me.itemSize    = eX * ((1 - (me.marginLeft + me.marginRight + me.columnSpacing * (me.columns - 1)) / absWidth) / me.columns)
151                        + eY * (me.rowHeight / absHeight);
152         me.itemSpacing = me.itemSize
153                        + eX * (me.columnSpacing / absWidth)
154                        + eY * (me.rowSpacing / absHeight);
155         me.intendedHeight = absHeight / conheight;
156         me.currentRow = -1;
157         me.currentColumn = -1;
158
159         me.fill(me);
160
161         if(me.isTabRoot && me.closable && me.borderLines > 0)
162         {
163                 entity closebutton;
164                 closebutton = me.closeButton = me.frame.closeButton = NEW(Button);
165                 closebutton.configureButton(closebutton, "", 0, me.closeButtonImage);
166                 closebutton.onClick = Dialog_Close; closebutton.onClickEntity = me;
167                 closebutton.srcMulti = 0;
168                 me.addItem(me, closebutton, '0 0 0', '1 1 0', 1); // put it as LAST
169         }
170 }
171
172 void Dialog_close(entity me)
173 {
174         if(me.parent.instanceOfNexposee)
175         {
176                 ExposeeCloseButton_Click(me, me.parent);
177         }
178         else if(me.parent.instanceOfModalController)
179         {
180                 DialogCloseButton_Click(me, me);
181         }
182 }
183
184 float Dialog_keyDown(entity me, float key, float ascii, float shift)
185 {
186         if(me.closable)
187         {
188                 if(key == K_ESCAPE)
189                 {
190                         m_play_click_sound(MENU_SOUND_CLOSE);
191                         me.close(me);
192                         return 1;
193                 }
194         }
195         return SUPER(Dialog).keyDown(me, key, ascii, shift);
196 }
197 #endif