Package dtk :: Package ui :: Module dialog

Source Code for Module dtk.ui.dialog

  1  #! /usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  # Copyright (C) 2011 ~ 2012 Deepin, Inc. 
  5  #               2011 ~ 2012 Wang Yong 
  6  #  
  7  # Author:     Wang Yong <lazycat.manatee@gmail.com> 
  8  # Maintainer: Wang Yong <lazycat.manatee@gmail.com> 
  9  #  
 10  # This program is free software: you can redistribute it and/or modify 
 11  # it under the terms of the GNU General Public License as published by 
 12  # the Free Software Foundation, either version 3 of the License, or 
 13  # any later version. 
 14  #  
 15  # This program is distributed in the hope that it will be useful, 
 16  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 17  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 18  # GNU General Public License for more details. 
 19  #  
 20  # You should have received a copy of the GNU General Public License 
 21  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 22   
 23  from button import Button 
 24  from constant import ALIGN_MIDDLE 
 25  from draw import draw_vlinear, draw_blank_mask 
 26  from entry import InputEntry 
 27  from label import Label 
 28  from locales import _ 
 29  from mask import draw_mask 
 30  from skin_config import skin_config 
 31  from theme import ui_theme 
 32  from titlebar import Titlebar 
 33  from utils import container_remove_all 
 34  from window import Window 
 35  import gobject 
 36  import gtk 
 37   
 38  DIALOG_MASK_SINGLE_PAGE = 0 
 39  DIALOG_MASK_GLASS_PAGE = 1 
 40  DIALOG_MASK_MULTIPLE_PAGE = 2 
 41  DIALOG_MASK_TAB_PAGE = 3 
 42   
43 -class DialogLeftButtonBox(gtk.HBox):
44 ''' 45 HBox to handle left side buttons in DialogBox. 46 ''' 47
48 - def __init__(self):
49 ''' 50 Initialize DialogLeftButtonBox class. 51 ''' 52 gtk.HBox.__init__(self) 53 self.button_align = gtk.Alignment() 54 self.button_align.set(0.0, 0.5, 0, 0) 55 self.button_align.set_padding(5, 9, 7, 0) 56 self.button_box = gtk.HBox() 57 58 self.button_align.add(self.button_box) 59 self.pack_start(self.button_align, True, True)
60
61 - def set_buttons(self, buttons):
62 ''' 63 Set buttons in box. 64 65 @note: This functin will use new buttons B{instead} old buttons in button box. 66 67 @param buttons: A list of Gtk.Widget instance. 68 ''' 69 container_remove_all(self.button_box) 70 for button in buttons: 71 self.button_box.pack_start(button, False, False, 4)
72 73 gobject.type_register(DialogLeftButtonBox) 74
75 -class DialogRightButtonBox(gtk.HBox):
76 ''' 77 HBox to handle right side buttons in DialogBox. 78 ''' 79
80 - def __init__(self):
81 ''' 82 Initialize DialogRightButtonBox class. 83 ''' 84 gtk.HBox.__init__(self) 85 self.button_align = gtk.Alignment() 86 self.button_align.set(1.0, 0.5, 0, 0) 87 self.button_align.set_padding(5, 9, 0, 7) 88 self.button_box = gtk.HBox() 89 90 self.button_align.add(self.button_box) 91 self.pack_start(self.button_align, True, True)
92
93 - def set_buttons(self, buttons):
94 ''' 95 Set buttons in box. 96 97 @note: This functin will use new buttons B{instead} old buttons in button box. 98 99 @param buttons: A list of Gtk.Widget instance. 100 ''' 101 container_remove_all(self.button_box) 102 for button in buttons: 103 self.button_box.pack_start(button, False, False, 4)
104 105 gobject.type_register(DialogRightButtonBox) 106
107 -class DialogBox(Window):
108 ''' 109 Dialog box to standard dialog layout and ui detail. 110 111 If you want build a dialog, you should use this standard. 112 113 @undocumented: draw_mask_single_page 114 @undocumented: draw_mask_glass_page 115 @undocumented: draw_mask_multiple_page 116 @undocumented: draw_mask_tab_page 117 ''' 118
119 - def __init__(self, 120 title, 121 default_width=None, 122 default_height=None, 123 mask_type=None, 124 close_callback=None, 125 modal=True, 126 window_hint=gtk.gdk.WINDOW_TYPE_HINT_DIALOG, 127 window_pos=None, 128 skip_taskbar_hint=True, 129 resizable=False):
130 ''' 131 Initialize DialogBox class. 132 133 @param title: Dialog title. 134 @param default_width: Width of dialog, default is None. 135 @param default_height: Height of dialog, default is None. 136 @param mask_type: Background mask type, it allow use below type: 137 - DIALOG_MASK_SINGLE_PAGE single mask style, use in single page that background mask include dialog button area. 138 - DIALOG_MASK_GLASS_PAGE glass mask style, similar DIALOG_MASK_SINGLE_PAGE but with different color. 139 - DIALOG_MASK_MULTIPLE_PAGE multiple mask style, use in multiple page that background mask not include dialog button area. 140 - DIALOG_MASK_TAB_PAGE tab mask style, use in preference page that background mask not include button area. 141 ''' 142 Window.__init__(self, resizable) 143 self.default_width = default_width 144 self.default_height = default_height 145 self.mask_type = mask_type 146 147 if window_pos: 148 self.set_position(window_pos) 149 self.set_modal(modal) # grab focus to avoid build too many skin window 150 if window_hint: 151 self.set_type_hint(window_hint) 152 self.set_skip_taskbar_hint(skip_taskbar_hint) # skip taskbar 153 if self.default_width != None and self.default_height != None: 154 self.set_default_size(self.default_width, self.default_height) 155 156 if not resizable: 157 self.set_geometry_hints(None, self.default_width, self.default_height, -1, -1, -1, -1, -1, -1, -1, -1) 158 159 self.padding_left = 2 160 self.padding_right = 2 161 162 self.titlebar = Titlebar( 163 ["close"], 164 None, 165 title) 166 self.add_move_event(self.titlebar) 167 self.body_box = gtk.VBox() 168 self.body_align = gtk.Alignment() 169 self.body_align.set(0.5, 0.5, 1, 1) 170 self.body_align.set_padding(0, 0, self.padding_left, self.padding_right) 171 self.body_align.add(self.body_box) 172 self.button_box = gtk.HBox() 173 self.left_button_box = DialogLeftButtonBox() 174 self.right_button_box = DialogRightButtonBox() 175 176 self.button_box.pack_start(self.left_button_box, True, True) 177 self.button_box.pack_start(self.right_button_box, True, True) 178 179 self.window_frame.pack_start(self.titlebar, False, False) 180 self.window_frame.pack_start(self.body_align, True, True) 181 self.window_frame.pack_start(self.button_box, False, False) 182 183 if close_callback: 184 self.titlebar.close_button.connect("clicked", lambda w: close_callback()) 185 self.connect("destroy", lambda w: close_callback()) 186 else: 187 self.titlebar.close_button.connect("clicked", lambda w: self.destroy()) 188 self.connect("destroy", lambda w: self.destroy()) 189 190 self.draw_mask = self.get_mask_func(self, 1, 1, 0, 1)
191
192 - def get_mask_func(self, widget, padding_left=0, padding_right=0, padding_top=0, padding_bottom=0):
193 ''' 194 Get mask function to render background, you can use this function to return \"render function\" to draw your ui to keep same style. 195 196 @param widget: DialogBox widget. 197 @param padding_left: Padding at left side. 198 @param padding_right: Padding at right side. 199 @param padding_top: Padding at top side. 200 @param padding_bottom: Padding at bottom side. 201 ''' 202 if self.mask_type == DIALOG_MASK_SINGLE_PAGE: 203 return lambda cr, x, y, w, h: draw_mask( 204 widget, x + padding_left, 205 y + padding_top, 206 w - padding_left - padding_right, 207 h - padding_top - padding_bottom, 208 self.draw_mask_single_page) 209 elif self.mask_type == DIALOG_MASK_GLASS_PAGE: 210 return lambda cr, x, y, w, h: draw_mask( 211 widget, x + padding_left, 212 y + padding_top, 213 w - padding_left - padding_right, 214 h - padding_top - padding_bottom, 215 self.draw_mask_glass_page) 216 elif self.mask_type == DIALOG_MASK_MULTIPLE_PAGE: 217 return lambda cr, x, y, w, h: draw_mask( 218 widget, x + padding_left, 219 y + padding_top, 220 w - padding_left - padding_right, 221 h - padding_top - padding_bottom, 222 self.draw_mask_multiple_page) 223 elif self.mask_type == DIALOG_MASK_TAB_PAGE: 224 return lambda cr, x, y, w, h: draw_mask( 225 widget, x + padding_left, 226 y + padding_top, 227 w - padding_left - padding_right, 228 h - padding_top - padding_bottom, 229 self.draw_mask_tab_page) 230 else: 231 return lambda cr, x, y, w, h: draw_mask( 232 widget, x + padding_left, 233 y + padding_top, 234 w - padding_left - padding_right, 235 h - padding_top - padding_bottom, 236 draw_blank_mask)
237
238 - def draw_mask_single_page(self, cr, x, y, w, h):
239 ''' 240 Internal render function for DIALOG_MASK_SINGLE_PAGE type. 241 242 @param cr: Cairo context. 243 @param x: X coordiante of draw area. 244 @param y: Y coordiante of draw area. 245 @param w: Width of draw area. 246 @param h: Height of draw area. 247 ''' 248 top_height = 70 249 250 draw_vlinear( 251 cr, x, y, w, top_height, 252 ui_theme.get_shadow_color("mask_single_page_top").get_color_info(), 253 ) 254 255 draw_vlinear( 256 cr, x, y + top_height, w, h - top_height, 257 ui_theme.get_shadow_color("mask_single_page_bottom").get_color_info(), 258 )
259
260 - def draw_mask_glass_page(self, cr, x, y, w, h):
261 ''' 262 Internal render function for DIALOG_MASK_GLASS_PAGE type. 263 264 @param cr: Cairo context. 265 @param x: X coordiante of draw area. 266 @param y: Y coordiante of draw area. 267 @param w: Width of draw area. 268 @param h: Height of draw area. 269 ''' 270 top_height = 70 271 272 draw_vlinear( 273 cr, x, y, w, top_height, 274 ui_theme.get_shadow_color("mask_glass_page_top").get_color_info(), 275 ) 276 277 draw_vlinear( 278 cr, x, y + top_height, w, h - top_height, 279 ui_theme.get_shadow_color("mask_glass_page_bottom").get_color_info(), 280 )
281
282 - def draw_mask_multiple_page(self, cr, x, y, w, h):
283 ''' 284 Internal render function for DIALOG_MASK_MULTIPLE_PAGE type. 285 286 @param cr: Cairo context. 287 @param x: X coordiante of draw area. 288 @param y: Y coordiante of draw area. 289 @param w: Width of draw area. 290 @param h: Height of draw area. 291 ''' 292 titlebar_height = self.titlebar.get_allocation().height 293 button_box_height = self.right_button_box.get_allocation().height 294 dominant_color = skin_config.dominant_color 295 296 draw_vlinear( 297 cr, x, y + titlebar_height, w, h - titlebar_height, 298 ui_theme.get_shadow_color("mask_single_page_bottom").get_color_info(), 299 ) 300 301 draw_vlinear( 302 cr, x, y + h - button_box_height, w, button_box_height, 303 [(0, (dominant_color, 1.0)), 304 (1, (dominant_color, 1.0))]) 305 306 draw_vlinear( 307 cr, x, y + h - button_box_height, w, button_box_height, 308 ui_theme.get_shadow_color("mask_multiple_page").get_color_info(), 309 )
310
311 - def draw_mask_tab_page(self, cr, x, y, w, h):
312 ''' 313 Internal render function for DIALOG_MASK_TAB_PAGE type. 314 315 @param cr: Cairo context. 316 @param x: X coordiante of draw area. 317 @param y: Y coordiante of draw area. 318 @param w: Width of draw area. 319 @param h: Height of draw area. 320 ''' 321 button_box_height = self.right_button_box.get_allocation().height 322 dominant_color = skin_config.dominant_color 323 324 draw_vlinear( 325 cr, x, y + h - button_box_height, w, button_box_height, 326 [(0, (dominant_color, 1.0)), 327 (1, (dominant_color, 1.0))]) 328 329 draw_vlinear( 330 cr, x, y + h - button_box_height, w, button_box_height, 331 ui_theme.get_shadow_color("mask_multiple_page").get_color_info(), 332 )
333 334 gobject.type_register(DialogBox) 335
336 -class ConfirmDialog(DialogBox):
337 ''' 338 Simple message confirm dialog. 339 340 @undocumented: click_confirm_button 341 @undocumented: click_cancel_button 342 ''' 343
344 - def __init__(self, 345 title, 346 message, 347 default_width=330, 348 default_height=145, 349 confirm_callback=None, 350 cancel_callback=None):
351 ''' 352 Initialize ConfirmDialog class. 353 354 @param title: Title for confirm dialog. 355 @param message: Confirm message. 356 @param default_width: Dialog width, default is 330 pixel. 357 @param default_height: Dialog height, default is 145 pixel. 358 @param confirm_callback: Callback when user click confirm button. 359 @param cancel_callback: Callback when user click cancel button. 360 ''' 361 # Init. 362 DialogBox.__init__(self, title, default_width, default_height, DIALOG_MASK_SINGLE_PAGE) 363 self.confirm_callback = confirm_callback 364 self.cancel_callback = cancel_callback 365 366 self.label_align = gtk.Alignment() 367 self.label_align.set(0.5, 0.5, 0, 0) 368 self.label_align.set_padding(0, 0, 8, 8) 369 self.label = Label(message, text_x_align=ALIGN_MIDDLE, text_size=11) 370 371 self.confirm_button = Button(_("OK")) 372 self.cancel_button = Button(_("Cancel")) 373 374 self.confirm_button.connect("clicked", lambda w: self.click_confirm_button()) 375 self.cancel_button.connect("clicked", lambda w: self.click_cancel_button()) 376 377 # Connect widgets. 378 self.body_box.pack_start(self.label_align, True, True) 379 self.label_align.add(self.label) 380 381 self.right_button_box.set_buttons([self.confirm_button, self.cancel_button])
382
383 - def click_confirm_button(self):
384 ''' 385 Internal function to handle click confirm button. 386 ''' 387 if self.confirm_callback != None: 388 self.confirm_callback() 389 390 self.destroy()
391
392 - def click_cancel_button(self):
393 ''' 394 Internal function to handle click cancel button. 395 ''' 396 if self.cancel_callback != None: 397 self.cancel_callback() 398 399 self.destroy()
400 401 gobject.type_register(ConfirmDialog) 402
403 -class InputDialog(DialogBox):
404 ''' 405 Simple input dialog. 406 407 @undocumented: click_confirm_button 408 @undocumented: click_cancel_button 409 ''' 410
411 - def __init__(self, 412 title, 413 init_text, 414 default_width=330, 415 default_height=145, 416 confirm_callback=None, 417 cancel_callback=None):
418 ''' 419 Initialize InputDialog class. 420 421 @param title: Input dialog title. 422 @param init_text: Initialize input text. 423 @param default_width: Width of dialog, default is 330 pixel. 424 @param default_height: Height of dialog, default is 330 pixel. 425 @param confirm_callback: Callback when user click confirm button, this callback accept one argument that return by user input text. 426 @param cancel_callback: Callback when user click cancel button, this callback not need argument. 427 ''' 428 # Init. 429 DialogBox.__init__(self, title, default_width, default_height, DIALOG_MASK_SINGLE_PAGE) 430 self.confirm_callback = confirm_callback 431 self.cancel_callback = cancel_callback 432 433 self.entry_align = gtk.Alignment() 434 self.entry_align.set(0.5, 0.5, 0, 0) 435 self.entry_align.set_padding(0, 0, 8, 8) 436 self.entry = InputEntry(init_text) 437 self.entry.set_size(default_width - 20, 25) 438 439 self.confirm_button = Button(_("OK")) 440 self.cancel_button = Button(_("Cancel")) 441 442 self.confirm_button.connect("clicked", lambda w: self.click_confirm_button()) 443 self.cancel_button.connect("clicked", lambda w: self.click_cancel_button()) 444 445 self.entry_align.add(self.entry) 446 self.body_box.pack_start(self.entry_align, True, True) 447 448 self.right_button_box.set_buttons([self.confirm_button, self.cancel_button]) 449 450 self.connect("show", self.focus_input)
451
452 - def focus_input(self, widget):
453 ''' 454 Grab focus on input entry. 455 456 @param widget: InputDialog widget. 457 ''' 458 self.entry.entry.grab_focus()
459
460 - def click_confirm_button(self):
461 ''' 462 Inernal fucntion to handle click confirm button. 463 ''' 464 if self.confirm_callback != None: 465 self.confirm_callback(self.entry.get_text()) 466 467 self.destroy()
468
469 - def click_cancel_button(self):
470 ''' 471 Inernal fucntion to handle click cancel button. 472 ''' 473 if self.cancel_callback != None: 474 self.cancel_callback() 475 476 self.destroy()
477 478 gobject.type_register(InputDialog) 479
480 -class OpenFileDialog(gtk.FileChooserDialog):
481 ''' 482 Simple dialog to open file. 483 ''' 484
485 - def __init__(self, title, parent, ok_callback=None, cancel_callback=None):
486 ''' 487 Initialize OpenFileDialog class. 488 489 @param title: Dialog title. 490 @param parent: Parent widget to call open file dialog. 491 @param ok_callback: Callback when user click ok button, this function accept one argument: filename. 492 @param cancel_callback: Callback when user click cancel button, this function accept one argument: filename. 493 ''' 494 gtk.FileChooserDialog.__init__( 495 self, 496 title, 497 parent, 498 gtk.FILE_CHOOSER_ACTION_OPEN, 499 (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, 500 gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT)) 501 self.set_default_response(gtk.RESPONSE_ACCEPT) 502 self.set_position(gtk.WIN_POS_CENTER) 503 self.set_local_only(True) 504 response = self.run() 505 filename = self.get_filename() 506 if response == gtk.RESPONSE_ACCEPT: 507 if ok_callback != None: 508 ok_callback(filename) 509 elif response == gtk.RESPONSE_REJECT: 510 if cancel_callback != None: 511 cancel_callback(filename) 512 self.destroy()
513 514 gobject.type_register(OpenFileDialog) 515
516 -class SaveFileDialog(gtk.FileChooserDialog):
517 ''' 518 Simple dialog to save file. 519 ''' 520
521 - def __init__(self, title, parent, ok_callback=None, cancel_callback=None):
522 ''' 523 Initialize SaveFileDialog class. 524 525 @param title: Dialog title. 526 @param parent: Parent widget to call open file dialog. 527 @param ok_callback: Callback when user click ok button, this function accept one argument: filename. 528 @param cancel_callback: Callback when user click cancel button, this function accept one argument: filename. 529 ''' 530 gtk.FileChooserDialog.__init__( 531 self, 532 title, 533 parent, 534 gtk.FILE_CHOOSER_ACTION_SAVE, 535 (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, 536 gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) 537 self.set_default_response(gtk.RESPONSE_ACCEPT) 538 self.set_position(gtk.WIN_POS_CENTER) 539 self.set_local_only(True) 540 response = self.run() 541 filename = self.get_filename() 542 if response == gtk.RESPONSE_ACCEPT: 543 if ok_callback != None: 544 ok_callback(filename) 545 elif response == gtk.RESPONSE_REJECT: 546 if cancel_callback != None: 547 cancel_callback(filename) 548 self.destroy()
549 550 gobject.type_register(SaveFileDialog) 551 552 553 if __name__ == '__main__': 554 dialog = ConfirmDialog("确认对话框", "你确定吗?", 200, 100) 555 dialog.show_all() 556 557 gtk.main() 558