class MessageBox(object): def __init__(self, pos=[0,0], font=None, area=[50,50], align=["left","top"], visible=True, image=None, image_mode=None, messages=[], max_lines=None, wrap=False, text_padding=[0,0]): self.kind="MessageBox" self.pos=pos self.font=font if not self.font:self.font=Font() self.text_padding=text_padding self.area=area self.align=align self.visible=visible self.image=image self.image_mode=image_mode if self.image: if isinstance(self.image, pygame.Surface): pass else: self.image=self.image.resize(self.area, self.image_mode) self.area=[self.image.get_width(), self.image.get_height()] self.messages=[] self.max_lines=max_lines self.max_width=0 self.wrap=wrap for i in messages: self.add_message(i) self.vscroll=0 self.hscroll=0 def add_message(self, mess): if self.wrap: for x in gui_util.wrap_text(self.font, mess, self.wrap)[0]: self.messages.append(x) else: self.messages.append(mess) if self.max_lines: while len(self.messages)>self.max_lines: del self.messages[0] self.max_width=0 for i in self.messages: w=self.font.size(i)[0] if w>self.max_width: self.max_width=w def update(self, event): pass def scroll(self, v=0, h=0): self.vscroll+=v if self.vscroll<0: self.vscroll=0 if (len(self.messages)+1)*(self.font.fsize-(self.font.fsize/3))>self.area[1]: max=(self.font.fsize-(self.font.fsize/3))*(len(self.messages)+1) max-=self.area[1] if self.vscroll>max: self.vscroll=max else: self.vscroll=0 self.hscroll+=h if self.hscroll<0: self.hscroll=0 if self.max_width > self.area[0]: if self.hscroll>self.max_width-self.area[1]: self.hscroll=self.max_width-self.area[1] else: self.hscroll=0 def render(self, surface): if self.visible: ret_clip=surface.get_clip() new_clip=pygame.Rect((self.pos[0]+self.text_padding[0], self.pos[1]+self.text_padding[1]), (self.area[0]-self.text_padding[0]*2, self.area[1]-self.text_padding[1]*2)) new_clip.clip(ret_clip) if self.image: if isinstance(self.image, pygame.Surface): surface.blit(self.image, self.pos) else: self.image.render(surface, self.pos) surface.set_clip(new_clip) lines=[self.font.render(i) for i in self.messages] fs=self.font.fsize-(self.font.fsize/3) for l in xrange(len(lines)): line=lines[l] r=line.get_rect() y=self.pos[1]+self.text_padding[1]+\ (fs*l)+\ self.vscroll-(fs*(len(self.messages)+1)-self.area[1]) x=self.pos[0]+self.text_padding[0]-self.hscroll if self.align[0]=="left": r.left=x elif self.align[0]=="center": r.centerx=x+self.area[0]/2-self.text_padding[0] else: r.right=x+self.area[0]-self.text_padding[0]*2 if self.align[1]=="top": r.top=y elif self.align[1]=="center": r.centery=y else: r.bottom=y surface.blit(line, r.topleft) surface.set_clip(ret_clip)
class InputBox(object): def __init__(self, pos=[0,0], font=None, prompt="", width=250, start_text="", visible=True, image_normal=None, image_hover=None, image_click=None, image_mode=None, cache_on_KEY=None, ignore_active=False, align=["left","top"], text_padding=[0,0], ignore_events=[]): self.kind="InputBox" #TODO: allow area, istead of width, and allow multiple lines of input self.pos=pos self.image_mode=image_mode self.align=align self.text_padding=text_padding self.ignore_active=ignore_active self.width=width self.ignore_events=ignore_events self.font=font if not self.font: self.font=Font() self.rect=pygame.Rect(self.pos, [width, self.font.fsize]) self.prompt=prompt self.message=start_text self.cached_messages=[] self.text_pos=len(self.message) self.cache_on_KEY=cache_on_KEY self.blink_speed=0.5 self.blink_last=time.time() self.image_normal=image_normal self.image_hover=image_hover self.image_click=image_click if self.image_normal: if isinstance(self.image_normal, pygame.Surface): pass else: self.image_normal=self.image_normal.resize(self.rect.size, self.image_mode) self.rect=self.image_normal.get_rect() self.rect.topleft=self.pos self.width=self.rect.width-self.text_padding[0]*2 if self.image_hover: if isinstance(self.image_hover, pygame.Surface): pass else: self.image_hover=self.image_hover.resize(self.rect.size, self.image_mode) if self.image_click: if isinstance(self.image_click, pygame.Surface): pass else: self.image_click=self.image_click.resize(self.rect.size, self.image_mode) self.hovering=False self.mouse_button_down=False self.am_clicked=False self.active=False self.visible=visible def update(self, event): mouse_pos=pygame.mouse.get_pos() if self.visible: if event.type==MOUSEBUTTONDOWN: if event.button==1: if self.rect.collidepoint(mouse_pos): self.mouse_button_down=True else: self.mouse_button_down=False elif event.type==MOUSEBUTTONUP: self.mouse_button_down=False if event.button==1: if self.rect.collidepoint(mouse_pos): self.was_clicked=True self.active=True self.am_clicked=True else: self.was_clicked=False self.active=False self.am_clicked=False elif event.type==KEYDOWN: if self.active or self.ignore_active: a=gui_util.convert_event_to_key(event) if not a: return if a in self.ignore_events: return if self.cache_on_KEY: if a==self.cache_on_KEY: self.cached_messages.append(self.message) self.message="" self.text_pos=0 return if event.type==KEYDOWN: if event.key==self.cache_on_KEY: self.cached_messages.append(self.message) self.message="" self.text_pos=0 return if a=="BACK": if self.text_pos: self.message=self.message[:len(self.message)-1] self.text_pos-=1 elif a=="DEL": if len(self.message) > self.text_pos: self.message=self.message[:self.text_pos]+\ self.message[self.text_pos+1:] elif a=="HOME": self.text_pos=0 elif a=="END": self.text_pos=len(self.message) elif a=="LEFT": if self.text_pos>0: self.text_pos-=1 elif a=="RIGHT": if self.text_pos<len(self.message): self.text_pos+=1 elif a=="RETURN": b=self.message[:self.text_pos]+"\n"+self.message[self.text_pos+1:] if self.font.size(self.prompt+b)[0]<self.width: self.message=b self.text_pos+=1 elif a=="TAB": b=self.message[:self.text_pos]+" "+self.message[self.text_pos+1:] if self.font.size(self.prompt+b)[0]<self.width: self.message=b self.text_pos+=4 else: b=self.message[:self.text_pos]+a+self.message[self.text_pos+1:] if self.font.size(self.prompt+b)[0]<self.width: self.message=b self.text_pos+=1 if self.rect.collidepoint(mouse_pos): self.hovering=True if self.mouse_button_down: self.am_clicked=True else: self.am_clicked=False else: self.hovering=False def empty_cache(self): a=self.cached_messages[::] self.cached_messages=[] return a def render(self, surface): if self.visible: if self.am_clicked: image=self.image_click elif self.hovering: image=self.image_hover else: image=self.image_normal if image: if isinstance(image, pygame.Surface): surface.blit(image, self.rect.topleft) else: image.render(surface, self.rect.topleft) text=self.font.render(self.prompt+self.message) r=text.get_rect() if self.align[0]=="left": r.left=self.rect.left elif self.align[0]=="center": r.centerx=self.rect.centerx else: r.right=self.rect.right if self.align[1]=="top": r.top=self.rect.top elif self.align[1]=="center": r.centery=self.rect.centery else: r.bottom=self.rect.bottom r.left+=self.text_padding[0] r.top+=self.text_padding[1] surface.blit(text, r.topleft) if time.time()>=self.blink_last+self.blink_speed: r.left=r.right r.left-=self.font.size(self.message[self.text_pos::])[0] r.left-=self.font.fsize/15 if self.active or self.ignore_active: surface.blit(self.font.render("|"), r) if time.time()>=self.blink_last+self.blink_speed*2: self.blink_last=time.time()