summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/crumbs/hobwidget.py
diff options
context:
space:
mode:
authorShane Wang <shane.wang@intel.com>2012-02-27 13:28:26 +0800
committerRichard Purdie <richard.purdie@linuxfoundation.org>2012-03-20 15:21:32 +0000
commit88bbc0ce562aa80d2b98c8b48d79a612b47ca852 (patch)
treed3bbe6d318e96cbbcc46f350d6a730c36320a47c /bitbake/lib/bb/ui/crumbs/hobwidget.py
parent8b206d38c7fb172022e98a0879963e5f44bc2092 (diff)
downloadpoky-88bbc0ce562aa80d2b98c8b48d79a612b47ca852.tar.gz
Hob: implement a self-defined notebook visual component for Hob
In recipe selection page, package selection page, and build details page, etc, there is a notebook component which is not gtk.Notebook in the design video. We implement the visual component with a drawing area, and use it to replace the old notebook in recipe selection page and package selection page. The reasons why we do it are: 1) General speaking, gtk.Notebook doesn't look like the designer worked out. (see https://wiki.yoctoproject.org/wiki/File:Hob1.2-screencast2.mov) 2) And the designer version looks better, for example, there is an indicator to show how many recipes or packages are included, and how many issues happened when building? Very straightforward. But technically, gtk.Notebook can't implement that, as far as we know. 3) Moreover, there is an entry for "search recipes", and "search packages". How to make it horizontal to the tabs is a problem to us. Regarding those, we give up gtk.Notebook and use our own. (From Poky rev: e4ebac226cc5e4589bcecd8bada9fde462e925cc) (Bitbake rev: b0c2ca3f600694c6d37924006de3f9474b2a9a8e) Signed-off-by: Liming An <limingx.l.an@intel.com> Signed-off-by: Shane Wang <shane.wang@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/hobwidget.py')
-rw-r--r--bitbake/lib/bb/ui/crumbs/hobwidget.py468
1 files changed, 383 insertions, 85 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/hobwidget.py b/bitbake/lib/bb/ui/crumbs/hobwidget.py
index f4ff1dc881..8fa663c78a 100644
--- a/bitbake/lib/bb/ui/crumbs/hobwidget.py
+++ b/bitbake/lib/bb/ui/crumbs/hobwidget.py
@@ -17,11 +17,14 @@
17# You should have received a copy of the GNU General Public License along 17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc., 18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21import gtk 20import gtk
22import gobject 21import gobject
23import os 22import os
24import os.path 23import os.path
24import sys
25import pango, pangocairo
26import math
27
25from bb.ui.crumbs.hobcolor import HobColors 28from bb.ui.crumbs.hobcolor import HobColors
26from bb.ui.crumbs.persistenttooltip import PersistentTooltip 29from bb.ui.crumbs.persistenttooltip import PersistentTooltip
27 30
@@ -168,90 +171,6 @@ class HobViewTable (gtk.VBox):
168 if not view_column.get_title() in self.toggle_columns: 171 if not view_column.get_title() in self.toggle_columns:
169 self.emit("row-activated", tree.get_model(), path) 172 self.emit("row-activated", tree.get_model(), path)
170 173
171class HobViewBar (gtk.EventBox):
172 """
173 A EventBox with the specified gray background color is associated with a notebook.
174 And the toolbar to simulate the tabs.
175 """
176
177 def __init__(self, notebook):
178 if not notebook:
179 return
180 self.notebook = notebook
181
182 # setup an event box
183 gtk.EventBox.__init__(self)
184 self.set_border_width(2)
185 style = self.get_style().copy()
186 style.bg[gtk.STATE_NORMAL] = self.get_colormap().alloc_color (HobColors.GRAY, False, False)
187 self.set_style(style)
188
189 hbox = gtk.HBox()
190 self.add(hbox)
191
192 # setup a tool bar in the event box
193 self.toolbar = gtk.Toolbar()
194 self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
195 self.toolbar.set_style(gtk.TOOLBAR_TEXT)
196 self.toolbar.set_border_width(5)
197
198 self.toolbuttons = []
199 for index in range(self.notebook.get_n_pages()):
200 child = self.notebook.get_nth_page(index)
201 label = self.notebook.get_tab_label_text(child)
202 tip_text = 'switch to ' + label + ' page'
203 toolbutton = self.toolbar.append_element(gtk.TOOLBAR_CHILD_RADIOBUTTON, None,
204 label, tip_text, "Private text", None,
205 self.toolbutton_cb, index)
206 toolbutton.set_size_request(200, 100)
207 self.toolbuttons.append(toolbutton)
208
209 # set the default current page
210 self.modify_toolbuttons_bg(0)
211 self.notebook.set_current_page(0)
212
213 self.toolbar.append_space()
214
215 # add the tool bar into the event box
216 hbox.pack_start(self.toolbar, expand=False, fill=False)
217
218 self.search = gtk.Entry()
219 self.align = gtk.Alignment(xalign=0.5, yalign=0.5)
220 self.align.add(self.search)
221 hbox.pack_end(self.align, expand=False, fill=False)
222
223 self.label = gtk.Label(" Search: ")
224 self.label.set_alignment(0.5, 0.5)
225 hbox.pack_end(self.label, expand=False, fill=False)
226
227 def toolbutton_cb(self, widget, index):
228 if index >= self.notebook.get_n_pages():
229 return
230 self.notebook.set_current_page(index)
231 self.modify_toolbuttons_bg(index)
232
233 def modify_toolbuttons_bg(self, index):
234 if index >= len(self.toolbuttons):
235 return
236 for i in range(0, len(self.toolbuttons)):
237 toolbutton = self.toolbuttons[i]
238 if i == index:
239 self.modify_toolbutton_bg(toolbutton, True)
240 else:
241 self.modify_toolbutton_bg(toolbutton)
242
243 def modify_toolbutton_bg(self, toolbutton, active=False):
244 if active:
245 toolbutton.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.WHITE))
246 toolbutton.modify_bg(gtk.STATE_ACTIVE, gtk.gdk.Color(HobColors.WHITE))
247 toolbutton.modify_bg(gtk.STATE_SELECTED, gtk.gdk.Color(HobColors.WHITE))
248 toolbutton.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(HobColors.WHITE))
249 else:
250 toolbutton.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.GRAY))
251 toolbutton.modify_bg(gtk.STATE_ACTIVE, gtk.gdk.Color(HobColors.GRAY))
252 toolbutton.modify_bg(gtk.STATE_SELECTED, gtk.gdk.Color(HobColors.GRAY))
253 toolbutton.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(HobColors.GRAY))
254
255class HobXpmLabelButtonBox(gtk.EventBox): 174class HobXpmLabelButtonBox(gtk.EventBox):
256 """ label: name of buttonbox 175 """ label: name of buttonbox
257 description: the simple description 176 description: the simple description
@@ -360,3 +279,382 @@ class HobInfoButton(gtk.EventBox):
360 """ 279 """
361 def mouse_out_cb(self, widget, event): 280 def mouse_out_cb(self, widget, event):
362 self.image.set_from_file(hic.ICON_INFO_DISPLAY_FILE) 281 self.image.set_from_file(hic.ICON_INFO_DISPLAY_FILE)
282
283class HobTabBar(gtk.DrawingArea):
284 __gsignals__ = {
285 "blank-area-changed" : (gobject.SIGNAL_RUN_LAST,
286 gobject.TYPE_NONE,
287 (gobject.TYPE_INT,
288 gobject.TYPE_INT,
289 gobject.TYPE_INT,
290 gobject.TYPE_INT,)),
291
292 "tab-switched" : (gobject.SIGNAL_RUN_LAST,
293 gobject.TYPE_NONE,
294 (gobject.TYPE_INT,)),
295 }
296
297 def __init__(self):
298 gtk.DrawingArea.__init__(self)
299 self.children = []
300
301 self.tab_width = 140
302 self.tab_height = 52
303 self.tab_x = 10
304 self.tab_y = 0
305
306 self.width = 500
307 self.height = 53
308 self.tab_w_ratio = 140 * 1.0/500
309 self.tab_h_ratio = 52 * 1.0/53
310 self.set_size_request(self.width, self.height)
311
312 self.current_child = 0
313 self.font = self.get_style().font_desc
314 self.font.set_size(pango.SCALE * 13)
315 self.update_children_text_layout_and_bg_color()
316
317 self.blank_rectangle = None
318 self.tab_pressed = False
319
320 self.set_property('can-focus', True)
321 self.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.POINTER_MOTION_MASK |
322 gtk.gdk.BUTTON1_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK |
323 gtk.gdk.BUTTON_RELEASE_MASK)
324
325 self.connect("expose-event", self.on_draw)
326 self.connect("button-press-event", self.button_pressed_cb)
327 self.connect("button-release-event", self.button_released_cb)
328 self.show_all()
329
330 def button_released_cb(self, widget, event):
331 self.tab_pressed = False
332 self.queue_draw()
333
334 def button_pressed_cb(self, widget, event):
335 if event.type == gtk.gdk._2BUTTON_PRESS:
336 return
337
338 result = False
339 if self.is_focus() or event.type == gtk.gdk.BUTTON_PRESS:
340 x, y = event.get_coords()
341 # check which tab be clicked
342 for i, child in enumerate(self.children):
343 if (child["x"] < x) and (x < child["x"] + self.tab_width) \
344 and (child["y"] < y) and (y < child["y"] + self.tab_height):
345 self.current_child = i
346 result = True
347 break
348
349 # check the blank area is focus in or not
350 if (self.blank_rectangle) and (self.blank_rectangle.x > 0) and (self.blank_rectangle.y > 0):
351 if (self.blank_rectangle.x < x) and (x < self.blank_rectangle.x + self.blank_rectangle.width) \
352 and (self.blank_rectangle.y < y) and (y < self.blank_rectangle.y + self.blank_rectangle.height):
353 self.grab_focus()
354
355 if result == True:
356 page = self.children[self.current_child]["toggled_page"]
357 self.emit("tab-switched", page)
358 self.tab_pressed = True
359 self.queue_draw()
360
361 def update_children_size(self):
362 # calculate the size of tabs
363 self.tab_width = int(self.width * self.tab_w_ratio)
364 self.tab_height = int(self.height * self.tab_h_ratio)
365 for i, child in enumerate(self.children):
366 child["x"] = self.tab_x + i * self.tab_width
367 child["y"] = self.tab_y
368
369 if self.blank_rectangle != None:
370 self.resize_blank_rectangle()
371
372 def resize_blank_rectangle(self):
373 width = self.width - self.tab_width * len(self.children) - self.tab_x
374 x = self.tab_x + self.tab_width * len(self.children)
375 hpadding = vpadding = 5
376 self.blank_rectangle = self.set_blank_size(x + hpadding, self.tab_y + vpadding,
377 width - 2 * hpadding, self.tab_height - 2 * vpadding)
378
379 def update_children_text_layout_and_bg_color(self):
380 style = self.get_style().copy()
381 color = style.base[gtk.STATE_NORMAL]
382 for child in self.children:
383 pangolayout = self.create_pango_layout(child["title"])
384 pangolayout.set_font_description(self.font)
385 child["title_layout"] = pangolayout
386 child[i]["r"] = color.red
387 child[i]["g"] = color.green
388 child[i]["b"] = color.blue
389
390 def append_tab_child(self, title, page):
391 num = len(self.children) + 1
392 self.tab_width = self.tab_width * len(self.children) / num
393
394 i = 0
395 for child in self.children:
396 child["x"] = self.tab_x + i * self.tab_width
397 i += 1
398
399 x = self.tab_x + i * self.tab_width
400 y = self.tab_y
401 pangolayout = self.create_pango_layout(title)
402 pangolayout.set_font_description(self.font)
403 color = self.style.base[gtk.STATE_NORMAL]
404 new_one = {
405 "x" : x,
406 "y" : y,
407 "r" : color.red,
408 "g" : color.green,
409 "b" : color.blue,
410 "title_layout" : pangolayout,
411 "toggled_page" : page,
412 "title" : title,
413 "indicator_show" : False,
414 "indicator_number" : 0,
415 }
416 self.children.append(new_one)
417
418 def on_draw(self, widget, event):
419 cr = widget.window.cairo_create()
420
421 self.width = self.allocation.width
422 self.height = self.allocation.height
423
424 self.update_children_size()
425
426 self.draw_background(cr)
427 self.draw_toggled_tab(cr)
428 self.draw_tab_text(cr)
429
430 for i, child in enumerate(self.children):
431 if child["indicator_show"] == True:
432 self.draw_indicator(cr, i)
433
434 def draw_background(self, cr):
435 style = self.get_style()
436
437 if self.is_focus():
438 cr.set_source_color(style.base[gtk.STATE_SELECTED])
439 else:
440 cr.set_source_color(style.base[gtk.STATE_NORMAL])
441
442 y = 6
443 h = self.height - 6 - 1
444 gap = 1
445
446 w = self.children[0]["x"]
447 cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY))
448 cr.rectangle(0, y, w - gap, h) # start rectangle
449 cr.fill()
450
451 cr.set_source_color(style.base[gtk.STATE_NORMAL])
452 cr.rectangle(w - gap, y, w, h) #first gap
453 cr.fill()
454
455 w = self.tab_width
456 for child in self.children:
457 x = child["x"]
458 cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY))
459 cr.rectangle(x, y, w - gap, h) # tab rectangle
460 cr.fill()
461 cr.set_source_color(style.base[gtk.STATE_NORMAL])
462 cr.rectangle(x + w - gap, y, w, h) # gap
463 cr.fill()
464
465 cr.set_source_color(gtk.gdk.color_parse(HobColors.GRAY))
466 cr.rectangle(x + w, y, self.width - x - w, h) # last rectangle
467 cr.fill()
468
469 def draw_tab_text(self, cr):
470 style = self.get_style()
471
472 for child in self.children:
473 pangolayout = child["title_layout"]
474 if pangolayout:
475 fontw, fonth = pangolayout.get_pixel_size()
476 # center pos
477 off_x = (self.tab_width - fontw) / 2
478 off_y = (self.tab_height - fonth) / 2
479 x = child[i]["x"] + off_x
480 y = child[i]["y"] + off_y
481 self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), pangolayout)
482
483 def draw_toggled_tab(self, cr):
484 i = self.current_child
485 x = self.children[i]["x"]
486 y = self.children[i]["y"]
487 width = self.tab_width
488 height = self.tab_height
489 style = self.get_style()
490 color = style.base[gtk.STATE_NORMAL]
491
492 r = height / 10
493 if self.tab_pressed == True:
494 for xoff, yoff in [(1, 0), (2, 0)]:
495 cr.set_source_color(gtk.gdk.color_parse(HobColors.PALE_GREEN))
496 cr.move_to(x + r + xoff, y + yoff)
497 cr.line_to(x + width - r + xoff, y + yoff)
498 cr.arc(x + width - r+ xoff, y + r + yoff, r, 1.5*math.pi, 2*math.pi)
499 cr.move_to(x + width + xoff, r + yoff)
500 cr.line_to(x + width + xoff, y + height + yoff)
501 cr.line_to(x + xoff, y + height + yoff)
502 cr.line_to(x + xoff, r + yoff)
503 cr.arc(x + r + xoff, y + r + yoff, r, math.pi, 1.5*math.pi)
504 cr.stroke()
505 x = x + 2
506 y = y + 2
507 cr.set_source_rgba(color.red, color.green, color.blue, 1)
508 cr.move_to(x + r, y)
509 cr.line_to(x + width - r , y)
510 cr.arc(x + width - r, y + r, r, 1.5*math.pi, 2*math.pi)
511 cr.move_to(x + width, r)
512 cr.line_to(x + width, y + height)
513 cr.line_to(x, y + height)
514 cr.line_to(x, r)
515 cr.arc(x + r, y + r, r, math.pi, 1.5*math.pi)
516 cr.fill()
517
518 def draw_indicator(self, cr, i):
519 style = self.get_style()
520 tab_x = self.children[i]["x"]
521 tab_y = self.children[i]["y"]
522 number = self.children[i]["indicator_number"]
523 dest_w = int(32 * self.tab_w_ratio)
524 dest_h = int(32 * self.tab_h_ratio)
525 if dest_h < self.tab_height:
526 dest_w = dest_h
527
528 # x position is offset(tab_width*3/4 - icon_width/2) + start_pos(tab_x)
529 x = tab_x + self.tab_width * 3/4 - dest_w/2
530 y = tab_y + self.tab_height/2 - dest_h/2
531 cr.move_to(tab_x, tab_y)
532 r = min(dest_w, dest_h)/2
533 color = cr.set_source_color(gtk.gdk.color_parse(HobColors.ORANGE))
534 cr.arc(x + r, y + r, r, 0, 2*math.pi)
535 cr.fill()
536
537 text = ("%d" % number)
538 layout = self.create_pango_layout(text)
539 layout.set_font_description(self.font)
540 textw, texth = layout.get_pixel_size()
541 x = x + (dest_w/2)-(textw/2)
542 y = y + (dest_h/2) - (texth/2)
543 cr.move_to(x, y)
544 self.window.draw_layout(self.style.fg_gc[gtk.STATE_NORMAL], int(x), int(y), layout)
545
546 def show_indicator_icon(self, i, number):
547 self.children[i]["indicator_show"] = True
548 self.children[i]["indicator_number"] = number
549 self.queue_draw()
550
551 def hide_indicator_icon(self, i):
552 self.children[i]["indicator_show"] = False
553 self.queue_draw()
554
555 def set_blank_size(self, x, y, w, h):
556 if self.blank_rectangle == None or self.blank_rectangle.x != x or self.blank_rectangle.width != w:
557 self.emit("blank-area-changed", x, y, w, h)
558
559 return gtk.gdk.Rectangle(x, y, w, h)
560
561class HobNotebook(gtk.VBox):
562
563 def __init__(self):
564 gtk.VBox.__init__(self, False, 0)
565
566 self.notebook = gtk.Notebook()
567 self.notebook.set_property('homogeneous', True)
568 self.notebook.set_property('show-tabs', False)
569
570 self.tabbar = HobTabBar()
571 self.tabbar.connect("tab-switched", self.tab_switched_cb)
572 self.notebook.connect("page-added", self.page_added_cb)
573 self.notebook.connect("page-removed", self.page_removed_cb)
574
575 self.search = None
576 self.search_name = ""
577
578 self.tb = gtk.Table(1, 100, False)
579 self.hbox= gtk.HBox(False, 0)
580 self.hbox.pack_start(self.tabbar, True, True)
581 self.tb.attach(self.hbox, 0, 100, 0, 1)
582
583 self.pack_start(self.tb, False, False)
584 self.pack_start(self.notebook)
585
586 self.show_all()
587
588 def append_page(self, child, tab_label):
589 self.notebook.set_current_page(self.notebook.append_page(child, tab_label))
590
591 def set_entry(self, name="Search:"):
592 for child in self.tb.get_children():
593 if child:
594 self.tb.remove(child)
595
596 hbox_entry = gtk.HBox(False, 0)
597 hbox_entry.show()
598
599 self.search = gtk.Entry()
600 self.search_name = name
601 style = self.search.get_style()
602 style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False)
603 self.search.set_style(style)
604 self.search.set_text(name)
605 self.search.set_editable(False)
606 self.search.show()
607 self.align = gtk.Alignment(xalign=1.0, yalign=0.7)
608 self.align.add(self.search)
609 self.align.show()
610 hbox_entry.pack_end(self.align, False, False)
611 self.tabbar.resize_blank_rectangle()
612
613 self.tb.attach(hbox_entry, 75, 100, 0, 1, xpadding=5)
614 self.tb.attach(self.hbox, 0, 100, 0, 1)
615
616 self.tabbar.connect("blank-area-changed", self.blank_area_resize_cb)
617 self.search.connect("focus-in-event", self.set_search_entry_editable_cb)
618 self.search.connect("focus-out-event", self.set_search_entry_reset_cb)
619
620 self.tb.show()
621
622 def tab_switched_cb(self, widget, page):
623 self.notebook.set_current_page(page)
624
625 def page_added_cb(self, notebook, notebook_child, page):
626 if not notebook:
627 return
628 title = notebook.get_tab_label_text(notebook_child)
629 if title == None:
630 return
631 for child in self.tabbar.children:
632 if child["title"] == title:
633 child["toggled_page"] = page
634 return
635 self.tabbar.append_tab_child(title, page)
636
637 def page_removed_cb(self, notebook, notebook_child, page, title=""):
638 for child in self.tabbar.children:
639 if child["title"] == title:
640 child["toggled_page"] = -1
641
642 def blank_area_resize_cb(self, widget, request_x, request_y, request_width, request_height):
643 self.search.set_size_request(request_width, request_height)
644 widget.modify_bg(gtk.STATE_SELECTED, gtk.gdk.color_parse(HobColors.YELLOW))
645
646 def set_search_entry_editable_cb(self, widget, event):
647 if self.search:
648 self.search.set_editable(True)
649 self.search.set_text("")
650 style = self.search.get_style()
651 style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.BLACK, False, False)
652 self.search.set_style(style)
653
654 def set_search_entry_reset_cb(self, widget, event):
655 if self.search:
656 style = self.search.get_style()
657 style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False)
658 self.search.set_style(style)
659 self.search.set_text(self.search_name)
660 self.search.set_editable(False)