PageRenderTime 38ms CodeModel.GetById 22ms app.highlight 12ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua

http://calcute-bedb.googlecode.com/
Lua | 687 lines | 532 code | 112 blank | 43 comment | 48 complexity | 5361cbd2713039ac9f0c6f8785418d8a MD5 | raw file
  1--[[ $Id: AceGUIWidget-DropDown.lua 793 2009-04-07 09:26:44Z nevcairiel $ ]]--
  2local min, max, floor = math.min, math.max, math.floor
  3
  4local AceGUI = LibStub("AceGUI-3.0")
  5
  6local function fixlevels(parent,...)
  7	local i = 1
  8	local child = select(i, ...)
  9	while child do
 10		child:SetFrameLevel(parent:GetFrameLevel()+1)
 11		fixlevels(child, child:GetChildren())
 12		i = i + 1
 13		child = select(i, ...)
 14	end
 15end
 16
 17local function fixstrata(strata, parent, ...)
 18	local i = 1
 19	local child = select(i, ...)
 20	parent:SetFrameStrata(strata)
 21	while child do
 22		fixstrata(strata, child, child:GetChildren())
 23		i = i + 1
 24		child = select(i, ...)
 25	end
 26end
 27
 28do
 29	local widgetType = "Dropdown-Pullout"
 30	local widgetVersion = 2
 31	
 32	--[[ Static data ]]--
 33	
 34	local backdrop = {
 35		bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
 36		edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
 37		edgeSize = 32,
 38		tileSize = 32,
 39		tile = true,
 40		insets = { left = 11, right = 12, top = 12, bottom = 11 },
 41	}
 42	local sliderBackdrop  = {
 43		bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
 44		edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
 45		tile = true, tileSize = 8, edgeSize = 8,
 46		insets = { left = 3, right = 3, top = 3, bottom = 3 }
 47	}
 48
 49	local defaultWidth = 200
 50	local defaultMaxHeight = 600
 51	
 52	--[[ UI Event Handlers ]]--
 53	
 54	-- HACK: This should be no part of the pullout, but there
 55	--       is no other 'clean' way to response to any item-OnEnter
 56	--       Used to close Submenus when an other item is entered
 57	local function OnEnter(item)
 58		local self = item.pullout
 59		for k, v in ipairs(self.items) do
 60			if v.CloseMenu and v ~= item then
 61				v:CloseMenu()
 62			end
 63		end
 64	end
 65	
 66	-- See the note in Constructor() for each scroll related function
 67	local function OnMouseWheel(this, value)
 68		this.obj:MoveScroll(value)
 69	end
 70	
 71	local function OnScrollValueChanged(this, value)
 72		this.obj:SetScroll(value)
 73	end
 74	
 75	local function OnSizeChanged(this)
 76		this.obj:FixScroll()
 77	end
 78	
 79	--[[ Exported methods ]]--
 80	
 81	-- exported
 82	local function SetScroll(self, value)
 83		local status = self.scrollStatus
 84		local frame, child = self.scrollFrame, self.itemFrame
 85		local height, viewheight = frame:GetHeight(), child:GetHeight()
 86
 87		local offset
 88		if height > viewheight then
 89			offset = 0
 90		else
 91			offset = floor((viewheight - height) / 1000 * value)
 92		end
 93		child:ClearAllPoints()
 94		child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
 95		child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", self.slider:IsShown() and -12 or 0, offset)
 96		status.offset = offset
 97		status.scrollvalue = value		
 98	end
 99	
100	-- exported
101	local function MoveScroll(self, value)
102		local status = self.scrollStatus
103		local frame, child = self.scrollFrame, self.itemFrame
104		local height, viewheight = frame:GetHeight(), child:GetHeight()
105
106		if height > viewheight then
107			self.slider:Hide()
108		else
109			self.slider:Show()
110			local diff = height - viewheight
111			local delta = 1
112			if value < 0 then
113				delta = -1
114			end
115			self.slider:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
116		end
117	end
118	
119	-- exported
120	local function FixScroll(self)
121		local status = self.scrollStatus
122		local frame, child = self.scrollFrame, self.itemFrame
123		local height, viewheight = frame:GetHeight(), child:GetHeight()
124		local offset = status.offset or 0
125
126		if viewheight < height then
127			self.slider:Hide()
128			child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset)
129			self.slider:SetValue(0)
130		else
131			self.slider:Show()			
132			local value = (offset / (viewheight - height) * 1000)
133			if value > 1000 then value = 1000 end
134			self.slider:SetValue(value)
135			self:SetScroll(value)
136			if value < 1000 then
137				child:ClearAllPoints()
138				child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
139				child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, offset)
140				status.offset = offset
141			end
142		end
143	end
144	
145	-- exported, AceGUI callback
146	local function OnAcquire(self)
147		self.frame:SetParent(UIParent)
148		--self.itemFrame:SetToplevel(true)
149	end
150	
151	-- exported, AceGUI callback
152	local function OnRelease(self)
153		self:Clear()
154		self.frame:ClearAllPoints()
155		self.frame:Hide()
156	end
157	
158	-- exported
159	local function AddItem(self, item)
160		self.items[#self.items + 1] = item
161		
162		local h = #self.items * 16
163		self.itemFrame:SetHeight(h)
164		self.frame:SetHeight(min(h + 34, self.maxHeight)) -- +34: 20 for scrollFrame placement (10 offset) and +14 for item placement
165		
166		item.frame:SetPoint("LEFT", self.itemFrame, "LEFT")
167		item.frame:SetPoint("RIGHT", self.itemFrame, "RIGHT")
168		
169		item:SetPullout(self)
170		item:SetOnEnter(OnEnter)
171	end
172		
173	-- exported
174	local function Open(self, point, relFrame, relPoint, x, y)		
175		local items = self.items
176		local frame = self.frame
177		local itemFrame = self.itemFrame
178		
179		frame:SetPoint(point, relFrame, relPoint, x, y)
180
181				
182		local height = 8
183		for i, item in pairs(items) do
184			if i == 1 then
185				item:SetPoint("TOP", itemFrame, "TOP", 0, -2)
186			else
187				item:SetPoint("TOP", items[i-1].frame, "BOTTOM", 0, 1)
188			end
189			
190			item:Show()
191			
192			height = height + 16
193		end
194		itemFrame:SetHeight(height)
195		fixstrata("TOOLTIP", frame, frame:GetChildren())
196		frame:Show()
197		self:Fire("OnOpen")
198	end	
199	
200	-- exported
201	local function Close(self)
202		self.frame:Hide()
203		self:Fire("OnClose")
204	end	
205	
206	-- exported
207	local function Clear(self)
208		local items = self.items
209		for i, item in pairs(items) do
210			AceGUI:Release(item)
211			items[i] = nil
212		end
213	end	
214	
215	-- exported
216	local function IterateItems(self)
217		return ipairs(self.items)
218	end
219	
220	-- exported
221	local function SetHideOnLeave(self, val)
222		self.hideOnLeave = val
223	end
224	
225	-- exported
226	local function SetMaxHeight(self, height)
227		self.maxHeight = height or defaultMaxHeight
228		if self.frame:GetHeight() > height then
229			self.frame:SetHeight(height)
230		elseif (self.itemFrame:GetHeight() + 34) < height then
231			self.frame:SetHeight(self.itemFrame:GetHeight() + 34) -- see :AddItem
232		end
233	end
234		
235	-- exported
236	local function GetRightBorderWidth(self)
237		return 6 + (self.slider:IsShown() and 12 or 0)
238	end
239	
240	-- exported
241	local function GetLeftBorderWidth(self)
242		return 6
243	end
244	
245	--[[ Constructor ]]--
246	
247	local function Constructor()
248		local count = AceGUI:GetNextWidgetNum(widgetType)
249		local frame = CreateFrame("Frame", "AceGUI30Pullout"..count, UIParent)
250		local self = {}
251		self.count = count
252		self.type = widgetType
253		self.frame = frame
254		frame.obj = self
255		
256		self.OnAcquire = OnAcquire
257		self.OnRelease = OnRelease
258
259		self.AddItem = AddItem
260		self.Open    = Open
261		self.Close   = Close
262		self.Clear   = Clear
263		self.IterateItems = IterateItems
264		self.SetHideOnLeave = SetHideOnLeave
265
266		self.SetScroll  = SetScroll
267		self.MoveScroll = MoveScroll
268		self.FixScroll  = FixScroll
269		
270		self.SetMaxHeight = SetMaxHeight
271		self.GetRightBorderWidth = GetRightBorderWidth
272		self.GetLeftBorderWidth = GetLeftBorderWidth
273		
274		self.items = {}
275		
276		self.scrollStatus = {
277			scrollvalue = 0,
278		}
279		
280		self.maxHeight = defaultMaxHeight
281			
282		frame:SetBackdrop(backdrop)
283		frame:SetBackdropColor(0, 0, 0)
284		frame:SetFrameStrata("FULLSCREEN_DIALOG")
285		frame:SetClampedToScreen(true)
286		frame:SetWidth(defaultWidth)
287		frame:SetHeight(self.maxHeight)	
288		--frame:SetToplevel(true)
289	
290		-- NOTE: The whole scroll frame code is copied from the AceGUI-3.0 widget ScrollFrame
291		local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
292		local itemFrame = CreateFrame("Frame", nil, scrollFrame)
293		
294		self.scrollFrame = scrollFrame
295		self.itemFrame = itemFrame
296		
297		scrollFrame.obj = self
298		itemFrame.obj = self
299		
300		local slider = CreateFrame("Slider", "AceGUI30PulloutScrollbar"..count, scrollFrame)
301		slider:SetOrientation("VERTICAL")
302		slider:SetHitRectInsets(0, 0, -10, 0)
303		slider:SetBackdrop(sliderBackdrop)
304		slider:SetWidth(8)
305		slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
306		slider:SetFrameStrata("FULLSCREEN_DIALOG")
307		self.slider = slider
308		slider.obj = self
309					
310		scrollFrame:SetScrollChild(itemFrame)
311		scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -12)
312		scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -6, 12)
313		scrollFrame:EnableMouseWheel(true)
314		scrollFrame:SetScript("OnMouseWheel", OnMouseWheel)
315		scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
316		scrollFrame:SetToplevel(true)
317		scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
318		
319		itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
320		itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
321		itemFrame:SetHeight(400)
322		itemFrame:SetToplevel(true)
323		itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
324		
325		slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0)
326		slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0)
327		slider:SetScript("OnValueChanged", OnScrollValueChanged)
328		slider:SetMinMaxValues(0, 1000)
329		slider:SetValueStep(1)
330		slider:SetValue(0)
331		
332		scrollFrame:Show()
333		itemFrame:Show()
334		slider:Hide()
335						
336		self:FixScroll()
337		
338		AceGUI:RegisterAsWidget(self)
339		return self
340	end
341	
342	AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
343end
344
345do 
346	local widgetType = "Dropdown"
347	local widgetVersion = 19
348	
349	--[[ Static data ]]--
350	
351	--[[ UI event handler ]]--
352	
353	local function Control_OnEnter(this)
354		this.obj:Fire("OnEnter")
355	end
356	
357	local function Control_OnLeave(this)
358		this.obj:Fire("OnLeave")
359	end
360
361	local function Dropdown_OnHide(this)
362		local self = this.obj
363		if self.open then
364			self.pullout:Close()
365		end
366	end
367	
368	local function Dropdown_TogglePullout(this)
369		local self = this.obj
370		if self.open then
371			self.open = nil
372			self.pullout:Close()
373			AceGUI:ClearFocus()
374		else
375			self.open = true
376			self.pullout:SetWidth(self.frame:GetWidth())
377			self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0)
378			AceGUI:SetFocus(self)
379		end
380	end
381	
382	local function OnPulloutOpen(this)
383		local self = this.userdata.obj
384		local value = self.value
385		
386		if not self.multiselect then
387			for i, item in this:IterateItems() do
388				item:SetValue(item.userdata.value == value)
389			end
390		end
391		
392		self.open = true
393	end
394
395	local function OnPulloutClose(this)
396		local self = this.userdata.obj
397		self.open = nil
398		self:Fire("OnClosed")
399	end
400	
401	local function ShowMultiText(self)
402		local text
403		for i, widget in self.pullout:IterateItems() do
404			if widget.type == "Dropdown-Item-Toggle" then
405				if widget:GetValue() then
406					if text then
407						text = text..", "..widget:GetText()
408					else
409						text = widget:GetText()
410					end
411				end
412			end
413		end
414		self:SetText(text)
415	end
416	
417	local function OnItemValueChanged(this, event, checked)
418		local self = this.userdata.obj
419		
420		if self.multiselect then
421			self:Fire("OnValueChanged", this.userdata.value, checked)
422			ShowMultiText(self)
423		else
424			if checked then
425				self:SetValue(this.userdata.value)
426				self:Fire("OnValueChanged", this.userdata.value)
427			else
428				this:SetValue(true)
429			end
430			if self.open then	
431				self.pullout:Close()
432			end
433		end
434	end
435	
436	--[[ Exported methods ]]--
437	
438	-- exported, AceGUI callback
439	local function OnAcquire(self)
440		local pullout = AceGUI:Create("Dropdown-Pullout")
441		self.pullout = pullout
442		pullout.userdata.obj = self
443		pullout:SetCallback("OnClose", OnPulloutClose)
444		pullout:SetCallback("OnOpen", OnPulloutOpen)
445		self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
446		fixlevels(self.pullout.frame, self.pullout.frame:GetChildren())
447		
448		self:SetHeight(44)
449		self:SetWidth(200)
450	end
451	
452	-- exported, AceGUI callback
453	local function OnRelease(self)
454		if self.open then
455			self.pullout:Close()
456		end
457		AceGUI:Release(self.pullout)
458		
459		self:SetText("")
460		self:SetLabel("")
461		self:SetDisabled(false)
462		self:SetMultiselect(false)
463		
464		self.value = nil
465		self.list = nil		
466		self.open = nil
467		self.hasClose = nil
468		
469		self.frame:ClearAllPoints()
470		self.frame:Hide()		
471	end
472	
473	-- exported
474	local function SetDisabled(self, disabled)
475		self.disabled = disabled
476		if disabled then
477			self.text:SetTextColor(0.5,0.5,0.5)
478			self.button:Disable()
479			self.label:SetTextColor(0.5,0.5,0.5)
480		else
481			self.button:Enable()
482			self.label:SetTextColor(1,.82,0)
483			self.text:SetTextColor(1,1,1)
484		end
485	end
486	
487	-- exported
488	local function ClearFocus(self)
489		if self.open then
490			self.pullout:Close()
491		end
492	end
493	
494	-- exported
495	local function SetText(self, text)
496		self.text:SetText(text or "")
497	end
498	
499	-- exported
500	local function SetLabel(self, text)
501		if text and text ~= "" then
502			self.label:SetText(text)
503			self.label:Show()
504			self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,-18)
505			self.frame:SetHeight(44)
506		else
507			self.label:SetText("")
508			self.label:Hide()
509			self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,0)
510			self.frame:SetHeight(26)
511		end
512	end
513	
514	-- exported
515	local function SetValue(self, value)
516		if self.list then
517			self:SetText(self.list[value] or "")
518		end
519		self.value = value
520	end
521	
522	-- exported
523	local function SetItemValue(self, item, value)
524		if not self.multiselect then return end
525		for i, widget in self.pullout:IterateItems() do
526			if widget.userdata.value == item then
527				if widget.SetValue then
528					widget:SetValue(value)
529				end
530			end
531		end
532		ShowMultiText(self)
533	end
534	
535	-- exported
536	local function SetItemDisabled(self, item, disabled)
537		for i, widget in self.pullout:IterateItems() do
538			if widget.userdata.value == item then
539				widget:SetDisabled(disabled)
540			end
541		end
542	end
543	
544	local function AddListItem(self, value, text)
545		local item = AceGUI:Create("Dropdown-Item-Toggle")
546		item:SetText(text)
547		item.userdata.obj = self
548		item.userdata.value = value
549		item:SetCallback("OnValueChanged", OnItemValueChanged)
550		self.pullout:AddItem(item)
551	end
552	
553	local function AddCloseButton(self)
554		if not self.hasClose then
555			local close = AceGUI:Create("Dropdown-Item-Execute")
556			close:SetText(CLOSE)
557			self.pullout:AddItem(close)
558			self.hasClose = true		
559		end
560	end
561	
562	-- exported
563	local sortlist = {}
564	local function SetList(self, list)
565		self.list = list
566		self.pullout:Clear()
567		self.hasClose = nil
568		if not list then return end
569		
570		for v in pairs(list) do
571			sortlist[#sortlist + 1] = v
572		end
573		table.sort(sortlist)
574		
575		for i, value in pairs(sortlist) do
576			AddListItem(self, value, list[value])
577			sortlist[i] = nil
578		end
579		if self.multiselect then
580			ShowMultiText(self)
581			AddCloseButton(self)
582		end
583	end
584	
585	-- exported
586	local function AddItem(self, value, text)
587		if self.list then
588			self.list[value] = text
589			AddListItem(self, value, text)
590		end
591	end
592	
593	-- exported
594	local function SetMultiselect(self, multi)
595		self.multiselect = multi
596		if multi then
597			ShowMultiText(self)
598			AddCloseButton(self)
599		end
600	end
601	
602	-- exported
603	local function GetMultiselect(self)
604		return self.multiselect
605	end
606	
607	--[[ Constructor ]]--
608	
609	local function Constructor()
610		local count = AceGUI:GetNextWidgetNum(widgetType)
611		local frame = CreateFrame("Frame", nil, UIParent)
612		local dropdown = CreateFrame("Frame", "AceGUI30DropDown"..count, frame, "UIDropDownMenuTemplate")
613		
614		local self = {}
615		self.type = widgetType
616		self.frame = frame
617		self.dropdown = dropdown
618		self.count = count
619		frame.obj = self
620		dropdown.obj = self
621		
622		self.OnRelease   = OnRelease
623		self.OnAcquire   = OnAcquire
624		
625		self.ClearFocus  = ClearFocus
626
627		self.SetText     = SetText
628		self.SetValue    = SetValue
629		self.SetList     = SetList
630		self.SetLabel    = SetLabel
631		self.SetDisabled = SetDisabled
632		self.AddItem     = AddItem
633		self.SetMultiselect = SetMultiselect
634		self.GetMultiselect = GetMultiselect
635		self.SetItemValue = SetItemValue
636		self.SetItemDisabled = SetItemDisabled
637		
638		self.alignoffset = 31
639		
640		frame:SetHeight(44)
641		frame:SetWidth(200)
642		frame:SetScript("OnHide",Dropdown_OnHide)
643
644		dropdown:ClearAllPoints()
645		dropdown:SetPoint("TOPLEFT",frame,"TOPLEFT",-15,0)
646		dropdown:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",17,0)
647		dropdown:SetScript("OnHide", nil)
648
649		local left = _G[dropdown:GetName() .. "Left"]
650		local middle = _G[dropdown:GetName() .. "Middle"]
651		local right = _G[dropdown:GetName() .. "Right"]
652		
653		middle:ClearAllPoints()
654		right:ClearAllPoints()
655		
656		middle:SetPoint("LEFT", left, "RIGHT", 0, 0)
657		middle:SetPoint("RIGHT", right, "LEFT", 0, 0)
658		right:SetPoint("TOPRIGHT", dropdown, "TOPRIGHT", 0, 17)
659
660		local button = _G[dropdown:GetName() .. "Button"]
661		self.button = button
662		button.obj = self
663		button:SetScript("OnEnter",Control_OnEnter)
664		button:SetScript("OnLeave",Control_OnLeave)
665		button:SetScript("OnClick",Dropdown_TogglePullout)
666		
667		local text = _G[dropdown:GetName() .. "Text"]
668		self.text = text
669		text.obj = self
670		text:ClearAllPoints()
671		text:SetPoint("RIGHT", right, "RIGHT" ,-43, 2)
672		text:SetPoint("LEFT", left, "LEFT", 25, 2)
673		
674		local label = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
675		label:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
676		label:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
677		label:SetJustifyH("LEFT")
678		label:SetHeight(18)
679		label:Hide()
680		self.label = label
681
682		AceGUI:RegisterAsWidget(self)
683		return self
684	end
685	
686	AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
687end