1#-*-python-*-
2#GemRB - Infinity Engine Emulator
3#Copyright (C) 2009 The GemRB Project
4#
5#This program is free software; you can redistribute it and/or
6#modify it under the terms of the GNU General Public License
7#as published by the Free Software Foundation; either version 2
8#of the License, or (at your option) any later version.
9#
10#This program is distributed in the hope that it will be useful,
11#but WITHOUT ANY WARRANTY; without even the implied warranty of
12#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13#GNU General Public License for more details.
14#
15#You should have received a copy of the GNU General Public License
16#along with this program; if not, write to the Free Software
17#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19
20import _GemRB
21import GameCheck
22
23from GUIDefines import *
24from MetaClasses import metaIDWrapper, add_metaclass
25from GemRB import GetView, CreateView, RemoveView, RemoveScriptingRef
26
27def CreateScrollbarARGs(bam = None):
28	bamframes = list(range(6))
29
30	if GameCheck.IsBG2():
31		bam = bam if bam else 'GUISCRCW'
32		bamframes = [0,1,2,3,5,4]
33	elif GameCheck.IsPST():
34		bam = bam if bam else 'CGSCRL1'
35	elif GameCheck.IsIWD2():
36		bam = bam if bam else 'GBTNSCRL'
37	elif GameCheck.IsBG1():
38		bam = bam if bam else 'GUIWSBR'
39		bamframes = [0,1,2,3,6,7]
40	elif GameCheck.IsIWD1():
41		bam = bam if bam else 'GUISBR'
42	else: # demo
43		bam = bam if bam else 'scrlbar1'
44		bamframes = [0,1,2,3,5,4]
45
46	return (bam, bamframes)
47
48@add_metaclass(metaIDWrapper)
49class GTable:
50	methods = {
51		'GetValue': _GemRB.Table_GetValue,
52		'FindValue': _GemRB.Table_FindValue,
53		'GetRowIndex': _GemRB.Table_GetRowIndex,
54		'GetRowName': _GemRB.Table_GetRowName,
55		'GetColumnIndex': _GemRB.Table_GetColumnIndex,
56		'GetColumnName': _GemRB.Table_GetColumnName,
57		'GetRowCount': _GemRB.Table_GetRowCount,
58		'GetColumnCount': _GemRB.Table_GetColumnCount
59	}
60
61	def __bool__(self):
62		return self.ID != -1
63
64@add_metaclass(metaIDWrapper)
65class GSymbol:
66	methods = {
67		'GetValue': _GemRB.Symbol_GetValue,
68		'Unload': _GemRB.Symbol_Unload
69	}
70
71class Scrollable(object):
72	def Scroll(self, x, y, relative = True):
73		_GemRB.Scrollable_Scroll(self, x, y, relative)
74
75	def ScrollTo(self, x, y):
76		self.Scroll(x, y, False)
77
78	def ScrollDelta(self, x, y):
79		self.Scroll(x, y, True)
80
81@add_metaclass(metaIDWrapper)
82class GView:
83	methods = {
84	'AddAlias': _GemRB.View_AddAlias,
85	'AddSubview': _GemRB.View_AddSubview,
86	'SetEventProxy': _GemRB.View_SetEventProxy,
87	'GetFrame': _GemRB.View_GetFrame,
88	'SetFrame': _GemRB.View_SetFrame,
89	'SetBackground': _GemRB.View_SetBackground,
90	'SetFlags': _GemRB.View_SetFlags,
91	'SetResizeFlags': _GemRB.View_SetResizeFlags,
92	'SetTooltip': _GemRB.View_SetTooltip,
93	'Focus': _GemRB.View_Focus
94	}
95
96	__slots__ = ['SCRIPT_GROUP', 'Flags']
97
98	def __eq__(self, rhs):
99		if rhs == None:
100			return self.ID == -1
101		return self.ID == rhs.ID and self.SCRIPT_GROUP == rhs.SCRIPT_GROUP
102
103	def __hash__(self):
104		return self.SCRIPT_GROUP + str(self.ID)
105
106	def __bool__(self):
107		return self.ID != -1
108
109	def GetSize(self):
110		frame = self.GetFrame()
111		return (frame['w'], frame['h'])
112
113	def GetPos(self):
114		frame = self.GetFrame()
115		return (frame['x'], frame['y'])
116
117	def SetSize(self, w, h):
118		r = self.GetFrame()
119		r['w'] = w
120		r['h'] = h
121		self.SetFrame(r);
122
123	def SetPos(self, x, y):
124		r = self.GetFrame()
125		r['x'] = x
126		r['y'] = y
127		self.SetFrame(r);
128
129	def GetInsetFrame(self, l = 0, r = None, t = None, b = None):
130		r = r if r is not None else l
131		t = t if t is not None else l
132		b = b if b is not None else t
133
134		frame = self.GetFrame()
135		frame['x'] = l
136		frame['y'] = b
137		frame['w'] -= (l + r)
138		frame['h'] -= (b + t)
139		return frame
140
141	def SetVisible(self, visible):
142		self.SetFlags(IE_GUI_VIEW_INVISIBLE, OP_NAND if visible else OP_OR)
143
144	def IsVisible(self):
145		return not (self.Flags & IE_GUI_VIEW_INVISIBLE)
146
147	def SetDisabled(self, disable):
148		self.SetFlags(IE_GUI_VIEW_DISABLED, OP_OR if disable else OP_NAND)
149
150	def CreateControl(self, newID, ctype, x, y, w, h, *args): # backwards compatibility
151		frame = {"x" : x, "y" : y, "w" : w, "h" : h}
152		return self.CreateSubview(newID, ctype, frame, *args)
153
154	def ReplaceSubview(self, subview, ctype, *args):
155		if isinstance(subview, int):
156			subview = self.GetControl (subview)
157		newID = subview.ID & 0x00000000ffffffff
158		frame = subview.GetFrame()
159		RemoveView(subview, True)
160
161		return self.CreateSubview(newID, ctype, frame, args)
162
163	def CreateSubview(self, newID, ctype, frame, *args):
164		view = CreateView(newID, ctype, frame, *args) # this will create an entry in the generic 'control' group
165		created = self.AddSubview(view) # this will move the reference into the our window's group
166		RemoveScriptingRef(view) # destroy the old reference just in case something tries to recycle the id while 'created' is still valid
167		return created
168
169	def RemoveSubview(self, view, delete=False):
170		return RemoveView(view, delete)
171
172	def CreateWorldMapControl(self, control, *args):
173		return self.CreateControl(control, IE_GUI_WORLDMAP, args[0], args[1], args[2], args[3], args[4:])
174
175	def CreateMapControl(self, control, *args):
176		return self.CreateControl(control, IE_GUI_MAP, args[0], args[1], args[2], args[3], args[4:])
177
178	def CreateLabel(self, control, *args):
179		return self.CreateControl(control, IE_GUI_LABEL, args[0], args[1], args[2], args[3], args[4:])
180
181	def CreateButton(self, control, *args):
182		return self.CreateControl(control, IE_GUI_BUTTON, args[0], args[1], args[2], args[3], args[4:])
183
184	def CreateScrollBar(self, control, frame, bam=None):
185		view = CreateView (control, IE_GUI_SCROLLBAR, frame, CreateScrollbarARGs(bam))
186		return self.AddSubview (view)
187
188	def CreateTextArea(self, control, *args):
189		return self.CreateControl(control, IE_GUI_TEXTAREA, args[0], args[1], args[2], args[3], args[4:])
190
191	def CreateTextEdit(self, control, *args):
192		return self.CreateControl(control, IE_GUI_EDIT, args[0], args[1], args[2], args[3], args[4:])
193
194class GWindow(GView, Scrollable):
195	methods = {
196		'SetupEquipmentIcons': _GemRB.Window_SetupEquipmentIcons,
197		'SetupControls': _GemRB.Window_SetupControls,
198		'Focus': _GemRB.Window_Focus,
199		'ShowModal': _GemRB.Window_ShowModal,
200		'SetAction': _GemRB.Window_SetAction
201	}
202
203	__slots__ = ['HasFocus']
204
205	def DeleteControl(self, view): # backwards compatibility
206		if type(view) == int:
207			view = self.GetControl (view)
208		RemoveView (view, True)
209
210	def GetControl(self, newID): # backwards compatibility
211		return GetView(self, newID)
212
213	def AliasControls (self, map):
214		for alias, cid in map.items():
215			control = self.GetControl(cid)
216			if control:
217				control.AddAlias(alias, self.ID)
218			else:
219				print("no control with id=" + str(cid))
220
221	def GetControlAlias(self, alias): # see AliasControls()
222		return GetView(alias, self.ID)
223
224	def ReparentSubview(self, view, newparent):
225		# reparenting assumes within the same window
226		newID = view.ID & 0x00000000ffffffff
227		view = self.RemoveSubview(view)
228
229		parentFrame = newparent.GetFrame()
230		frame = view.GetFrame()
231		frame['x'] -= parentFrame['x']
232		frame['y'] -= parentFrame['y']
233		view.SetFrame(frame)
234		return newparent.AddSubview(view, None, newID)
235
236	def Unload(self): # backwards compatibility
237		self.Close()
238
239	def Close(self):
240		RemoveView(self, False)
241
242class GControl(GView):
243	methods = {
244		'HasAnimation': _GemRB.Control_HasAnimation,
245		'SetVarAssoc': _GemRB.Control_SetVarAssoc,
246		'SetAnimationPalette': _GemRB.Control_SetAnimationPalette,
247		'SetAnimation': _GemRB.Control_SetAnimation,
248		'QueryText': _GemRB.Control_QueryText,
249		'SetText': _GemRB.Control_SetText,
250		'SetAction': _GemRB.Control_SetAction,
251		'SetActionInterval': _GemRB.Control_SetActionInterval,
252		'SetStatus': _GemRB.Control_SetStatus
253	}
254
255	__slots__ = ['ControlID', 'VarName', 'Value']
256
257	# backwards compatibility
258	# map old event identifiers to new action system
259	EventMap = {
260		IE_GUI_BUTTON_ON_PRESS: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_PRESS, GEM_MB_ACTION, 0, 1),
261		IE_GUI_MOUSE_ENTER_BUTTON: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_ENTER),
262		IE_GUI_MOUSE_LEAVE_BUTTON: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_LEAVE),
263		IE_GUI_BUTTON_ON_SHIFT_PRESS: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_PRESS, GEM_MB_ACTION, 1, 1),
264		IE_GUI_BUTTON_ON_RIGHT_PRESS: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_PRESS, GEM_MB_MENU, 0, 1),
265		IE_GUI_BUTTON_ON_DOUBLE_PRESS: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_PRESS, GEM_MB_ACTION, 0, 2),
266		IE_GUI_PROGRESS_END_REACHED: lambda control, handler: control.SetAction(handler, IE_GUI_PROGRESS_END_REACHED),
267		IE_GUI_SLIDER_ON_CHANGE: lambda control, handler: control.SetAction(handler, IE_ACT_VALUE_CHANGE),
268		IE_GUI_EDIT_ON_CHANGE: lambda control, handler: control.SetAction(handler, IE_ACT_VALUE_CHANGE),
269		IE_GUI_EDIT_ON_DONE: lambda control, handler: control.SetAction(handler, IE_ACT_CUSTOM),
270		IE_GUI_EDIT_ON_CANCEL: lambda control, handler: control.SetAction(handler, IE_ACT_CUSTOM+1),
271		IE_GUI_TEXTAREA_ON_CHANGE: lambda control, handler: control.SetAction(handler, IE_ACT_VALUE_CHANGE),
272		IE_GUI_TEXTAREA_ON_SELECT: lambda control, handler: control.SetAction(handler, IE_GUI_TEXTAREA_ON_SELECT),
273		IE_GUI_LABEL_ON_PRESS: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_PRESS, GEM_MB_ACTION, 0, 1),
274		IE_GUI_SCROLLBAR_ON_CHANGE: lambda control, handler: control.SetAction(handler, IE_ACT_VALUE_CHANGE),
275		IE_GUI_WORLDMAP_ON_PRESS: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_PRESS, GEM_MB_ACTION, 0, 1),
276		IE_GUI_MAP_ON_PRESS: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_PRESS, GEM_MB_ACTION, 0, 1),
277		IE_GUI_MAP_ON_RIGHT_PRESS: lambda control, handler: control.SetAction(handler, IE_ACT_MOUSE_PRESS, GEM_MB_MENU, 0, 1)
278	}
279
280	def SetEvent(self, event, handler):
281		GControl.EventMap[event](self, handler)
282
283	def QueryInteger(self):
284		return int("0"+self.QueryText())
285
286class GLabel(GControl):
287	methods = {
288		'SetFont': _GemRB.Label_SetFont,
289		'SetTextColor': _GemRB.Label_SetTextColor
290	}
291
292class GTextArea(GControl, Scrollable):
293	methods = {
294		'ChapterText': _GemRB.TextArea_SetChapterText,
295		'Append': _GemRB.TextArea_Append,
296		'SetColor': _GemRB.TextArea_SetColor
297	}
298	__slots__ = ['DefaultText']
299
300	def ListResources(self, what, opts=0):
301		_GemRB.TextArea_SetColor(self, ColorWhitish, TA_COLOR_OPTIONS)
302		return _GemRB.TextArea_ListResources(self, what, opts)
303
304	def Clear(self):
305		self.SetText("")
306
307	def SetOptions(self, optList, varname=None, val=0):
308		_GemRB.TextArea_SetOptions(self, optList)
309		if varname:
310			self.SetVarAssoc(varname, val)
311
312class GTextEdit(GControl):
313	methods = {
314		'SetBufferLength': _GemRB.TextEdit_SetBufferLength,
315	}
316
317class GScrollBar(GControl, Scrollable):
318	def SetVarAssoc(self, varname, val, rangeMin = 0, rangeMax = None):
319		rangeMax = val if rangeMax is None else rangeMax
320		super(GScrollBar, self).SetVarAssoc(varname, val, rangeMin, rangeMax)
321
322class GButton(GControl):
323	methods = {
324		'SetSprites': _GemRB.Button_SetSprites,
325		'SetOverlay': _GemRB.Button_SetOverlay,
326		'SetBorder': _GemRB.Button_SetBorder,
327		'EnableBorder': _GemRB.Button_EnableBorder,
328		'SetFont': _GemRB.Button_SetFont,
329		'SetHotKey': _GemRB.Button_SetHotKey,
330		'SetAnchor': _GemRB.Button_SetAnchor,
331		'SetPushOffset': _GemRB.Button_SetPushOffset,
332		'SetTextColor': _GemRB.Button_SetTextColor,
333		'SetState': _GemRB.Button_SetState,
334		'SetPictureClipping': _GemRB.Button_SetPictureClipping,
335		'SetPicture': _GemRB.Button_SetPicture,
336		'SetPLT': _GemRB.Button_SetPLT,
337		'SetBAM': _GemRB.Button_SetBAM,
338		'SetSpellIcon': _GemRB.Button_SetSpellIcon,
339		'SetItemIcon': _GemRB.Button_SetItemIcon,
340		'SetActionIcon': _GemRB.Button_SetActionIcon
341	}
342
343	def MakeDefault(self, glob=False):
344		# return key
345		return self.SetHotKey(chr(0x86), 0, glob)
346
347	def MakeEscape(self, glob=False):
348		# escape key
349		return self.SetHotKey(chr(0x8c), 0, glob)
350
351	def SetMOS(self, mos):
352		self.SetPicture(mos) # backwards compatibility
353
354	def SetSprite2D(self, spr):
355		self.SetPicture(spr) # backwards compatibility
356
357	def CreateLabel(self, labelid, *args):
358		frame = self.GetFrame()
359		return self.CreateControl(labelid, IE_GUI_LABEL, 0, 0, frame['w'], frame['h'], args)
360
361class GWorldMap(GControl, Scrollable):
362	methods = {
363		'GetDestinationArea': _GemRB.WorldMap_GetDestinationArea
364	}
365
366@add_metaclass(metaIDWrapper)
367class GSaveGame:
368	methods = {
369		'GetDate': _GemRB.SaveGame_GetDate,
370		'GetGameDate': _GemRB.SaveGame_GetGameDate,
371		'GetName': _GemRB.SaveGame_GetName,
372		'GetPortrait': _GemRB.SaveGame_GetPortrait,
373		'GetPreview': _GemRB.SaveGame_GetPreview,
374		'GetSaveID': _GemRB.SaveGame_GetSaveID,
375	}
376
377@add_metaclass(metaIDWrapper)
378class GSprite2D:
379	methods = {}
380