From 9a498a0c7dd90af62c7e769cf9e397f034d5d4d3 Mon Sep 17 00:00:00 2001 From: Gonzalo Odiard Date: Fri, 18 Jan 2013 16:04:31 +0000 Subject: Partial port of TamTamMini With this commit, the activity starts, but not all the functionality is working. A massive amount of unneded or overcomplicated code was removed. More work is needed in the ThemeWidgets classes. Signed-off-by: Gonzalo Odiard --- diff --git a/Mini/InstrumentPanel.py b/Mini/InstrumentPanel.py index 9d33e63..ecabe2d 100644 --- a/Mini/InstrumentPanel.py +++ b/Mini/InstrumentPanel.py @@ -7,6 +7,7 @@ from common.Util.ThemeWidgets import * from common.Util import InstrumentDB from common.port.scrolledbox import HScrolledBox import sugar3.graphics.style as style + import logging @@ -33,13 +34,11 @@ class InstrumentPanel( Gtk.EventBox ): self.loaded = False self.loadData = {} - self.loadStage = [0,0,0] def grab_focus(self): if not self.instDic: return - for widget in self.instDic.values(): - button = widget.get_children()[0] + for button in self.instDic.values(): if button.props.active: button.grab_focus() break @@ -61,63 +60,28 @@ class InstrumentPanel( Gtk.EventBox ): if self.loaded: self.prepareInstrumentTable(self.category) - def load( self, timeout = -1 ): - if self.loaded: return True - if Config.DEBUG > 4: print "InstrumentPanel load", self.loadStage - - if self.loadStage[0] == 0: - color = Gdk.color_parse(Config.PANEL_BCK_COLOR) - self.modify_bg(Gtk.StateType.NORMAL, color) - self.loadStage[0] = 1 - if timeout >= 0 and time.time() > timeout: return False - - if self.loadStage[0] == 1: - self.loadStage[0] = 2 - if timeout >= 0 and time.time() > timeout: return False - - if self.loadStage[0] == 2: - self.instTable = None - self.recstate = False - self.lastInstrumentWidget = None - - self.mainVBox = Gtk.VBox() - self.loadStage[0] = 3 - if timeout >= 0 and time.time() > timeout: return False - - if self.loadStage[0] == 3: - if not self.loadInstrumentList( timeout, self.loadStage ): - return False - self.loadStage[0] = 4 - if timeout >= 0 and time.time() > timeout: return False - - if self.loadStage[0] == 4: - if not self.loadToolbar( timeout, self.loadStage ): - return False - self.loadStage[0] = 5 - if timeout >= 0 and time.time() > timeout: return False - - if self.loadStage[0] == 5: - if self.instDic == None: - self.instDic = {} - self.loadStage[0] = 5.1 - else: - self.loadStage[0] = 6 + def load(self): + if self.loaded: + return True + + color = Gdk.color_parse(Config.PANEL_BCK_COLOR) + self.modify_bg(Gtk.StateType.NORMAL, color) + self.instTable = None + self.recstate = False - if self.loadStage[0] == 5.1: - if not self.loadInstDic( self.instDic, timeout, self.loadStage ): - return False - self.loadStage[0] = 6 - if timeout >= 0 and time.time() > timeout: return False + self.mainVBox = Gtk.VBox() - if self.loadStage[0] == 6: - self.loadInstrumentViewport() - self.loadStage[0] = 7 - if timeout >= 0 and time.time() > timeout: return False + self.loadInstrumentList() + self.loadToolbar() - if self.loadStage[0] == 7: - self.prepareInstrumentTable() - self.loadStage[0] = 8 - if timeout >= 0 and time.time() > timeout: return False + if self.instDic == None: + self.instDic = {} + + self.loadInstDic(self.instDic) + + self.loadInstrumentViewport() + + self.prepareInstrumentTable() self.add(self.mainVBox) self.show_all() @@ -125,140 +89,76 @@ class InstrumentPanel( Gtk.EventBox ): self.loaded = True return True - def loadInstrumentList( self, timeout = -1, loadStage = [0,0,0] ): - - if loadStage[1] == 0: - self.instrumentList = { "all": [], "all.enterMode": [], "percussions.enterMode": [], "mysounds": [] } - for category in Config.CATEGORIES: - self.instrumentList[category] = [] - loadStage[1] = 1 - if timeout >= 0 and time.time() > timeout: return False - - if loadStage[1] == 1: - keys = self.instrumentDB.instNamed.keys() - for i in range(loadStage[2], len(keys)): - key = keys[i] - - instrument = self.instrumentDB.instNamed[key] - if not instrument.kitStage and not instrument.kit: - if not key.startswith('mic') and not key.startswith('lab'): - self.instrumentList["all"].append( key ) - self.instrumentList["all.enterMode"].append( key ) - self.instrumentList[instrument.category].append( key ) - if instrument.category == "percussions": - self.instrumentList["percussions.enterMode"].append( key ) - loadStage[2] += 1 - if timeout >= 0 and time.time() > timeout: return False - - loadStage[1] = 2 - loadStage[2] = 0 + def loadInstrumentList(self): + + self.instrumentList = { "all": [], "all.enterMode": [], "percussions.enterMode": [], "mysounds": [] } + for category in Config.CATEGORIES: + self.instrumentList[category] = [] + + keys = self.instrumentDB.instNamed.keys() + for i in range(len(keys)): + key = keys[i] + + instrument = self.instrumentDB.instNamed[key] + if not instrument.kitStage and not instrument.kit: + if not key.startswith('mic') and not key.startswith('lab'): + self.instrumentList["all"].append( key ) + self.instrumentList["all.enterMode"].append( key ) + self.instrumentList[instrument.category].append( key ) + if instrument.category == "percussions": + self.instrumentList["percussions.enterMode"].append( key ) self.instrumentList["mysounds"].sort() self.instrumentList["all"] += self.instrumentList["mysounds"] self.instrumentList["all.enterMode"] += self.instrumentList["mysounds"] - loadStage[1] = 0 - return True - - def loadToolbar( self, timeout = -1, loadStage = [0,0,0] ): - if loadStage[1] == 0: - self.toolbarBox = Gtk.HBox() + def loadToolbar(self): + self.toolbarBox = Gtk.HBox() - scrollbox = HScrolledBox(scroll_policy=Gtk.PolicyType.NEVER) - scrollbox.set_viewport(self.toolbarBox) - scrollbox.modify_bg(Gtk.StateType.NORMAL, - style.Color(Config.PANEL_BCK_COLOR).get_gdk_color()) - self.mainVBox.pack_start(scrollbox, False, False, 0) + scrollbox = HScrolledBox(scroll_policy=Gtk.PolicyType.NEVER) + scrollbox.set_viewport(self.toolbarBox) + scrollbox.modify_bg(Gtk.StateType.NORMAL, + style.Color(Config.PANEL_BCK_COLOR).get_gdk_color()) + self.mainVBox.pack_start(scrollbox, False, False, 0) - self.firstTbBtn = None - self.loadStage[1] = 1 - if timeout >= 0 and time.time() > timeout: return False + self.firstTbBtn = None - for i in range(loadStage[1]-1, len(Config.CATEGORIES)): + for i in range(len(Config.CATEGORIES)): category = Config.CATEGORIES[i] - if loadStage[2] == 0: - self.loadData["btnBox"] = RoundVBox(fillcolor = Config.CATEGORY_BCK_COLOR, bordercolor = Config.PANEL_BCK_COLOR, radius = Config.PANEL_RADIUS) - self.loadData["btnBox"].set_border_width(Config.PANEL_SPACING) - loadStage[2] = 1 - if timeout >= 0 and time.time() > timeout: return False - - if loadStage[2] == 1: - self.loadData["btn"] = ImageRadioButton(self.firstTbBtn, - category + '.png', category + 'sel.png', - category + 'sel.png') - loadStage[2] = 2 - if timeout >= 0 and time.time() > timeout: return False - if self.firstTbBtn == None: - self.firstTbBtn = self.loadData["btn"] - self.loadData["btn"].connect('clicked',self.handleToolbarBtnPress,category) - self.loadData["btn"].set_tooltip_text(str(category)) - self.loadData["btnBox"].add(self.loadData["btn"]) - self.toolbarBox.pack_start(self.loadData["btnBox"], True, True, 0) - - loadStage[2] = 0 - loadStage[1] += 1 - if timeout >= 0 and time.time() > timeout: return False - - self.loadData.pop("btn") - self.loadData.pop("btnBox") - loadStage[1] = 0 - return True + btn = ImageRadioButton(self.firstTbBtn, + category + '.png', category + 'sel.png', + category + 'sel.png') - def loadInstDic( self, instDic, timeout = -1, loadStage = [0,0,0] ): - - if loadStage[1] == 0: - self.firstInstButton = None - self.loadData["len"] = len(self.instrumentList['all']) - loadStage[1] = 1 - if timeout >= 0 and time.time() > timeout: return False - - - for i in range( loadStage[1]-1, self.loadData["len"] ): - instrument = self.instrumentList["all"][i] - if loadStage[2] == 0: - self.loadData["instBox"] = RoundVBox(fillcolor = Config.INST_BCK_COLOR, bordercolor = Config.INSTRUMENT_GRID_COLOR, radius = Config.PANEL_RADIUS) - self.loadData["instBox"].set_border_width(Config.PANEL_SPACING) - loadStage[2] = 1 - if timeout >= 0 and time.time() > timeout: return False - - if loadStage[2] == 1: - try: - self.loadData['instButton'] = ImageRadioButton( - self.firstInstButton, instrument + '.png', - instrument + 'sel.png', instrument + 'sel.png') - except: - self.loadData["instButton"] = ImageRadioButton( - self.firstInstButton, 'generic.png', - 'genericsel.png', 'genericsel.png') - loadStage[2] = 2 - if timeout >= 0 and time.time() > timeout: return False - - if loadStage[2] == 2: - self.loadData["instButton"].clickedHandler = self.loadData["instButton"].connect('clicked',self.handleInstrumentButtonClick, instrument) - self.loadData["instButton"].connect('enter',self.handleInstrumentButtonEnter, instrument) - self.loadData["instButton"].connect('focus-in-event', self.handleInstrumentButtonFocus, instrument) - loadStage[2] = 3 - if timeout >= 0 and time.time() > timeout: return False - - self.loadData["instBox"].set_tooltip_text(str(self.instrumentDB.instNamed[instrument].nameTooltip)) - - self.loadData["instBox"].pack_start(self.loadData["instButton"], - False, False, 0) - instDic[instrument] = self.loadData["instBox"] + if self.firstTbBtn == None: + self.firstTbBtn = btn + btn.connect('clicked',self.handleToolbarBtnPress,category) + btn.set_tooltip_text(str(category)) + self.toolbarBox.pack_start(btn, False, False, 0) + + def loadInstDic( self, instDic): + + self.firstInstButton = None + + for instrument in self.instrumentList['all']: + try: + btn = ImageRadioButton( + self.firstInstButton, instrument + '.png', + instrument + 'sel.png', instrument + 'sel.png') + except: + btn = ImageRadioButton( + self.firstInstButton, 'generic.png', + 'genericsel.png', 'genericsel.png') + + btn.clickedHandler = btn.connect('clicked',self.handleInstrumentButtonClick, instrument) + btn.connect('enter',self.handleInstrumentButtonEnter, instrument) + btn.connect('focus-in-event', self.handleInstrumentButtonFocus, instrument) + + btn.set_tooltip_text(str(self.instrumentDB.instNamed[instrument].nameTooltip)) + instDic[instrument] = btn if self.firstInstButton == None: - self.firstInstButton = self.loadData["instButton"] - loadStage[2] = 0 - if timeout >= 0 and time.time() > timeout: return False - - loadStage[1] += 1 - - self.loadData.pop("instBox") - self.loadData.pop("instButton") - self.loadData.pop("len") - loadStage[1] = 0 - return True + self.firstInstButton = btn def loadInstrumentViewport( self ): self.instBox = Gtk.Alignment.new(0.5, 0, 0, 1) @@ -271,6 +171,7 @@ class InstrumentPanel( Gtk.EventBox ): scrollwin = Gtk.ScrolledWindow() scrollwin.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scrollwin.add_with_viewport(box) + box.get_parent().set_shadow_type(Gtk.ShadowType.NONE) self.mainVBox.pack_end(scrollwin, True, True, 0) @@ -284,7 +185,7 @@ class InstrumentPanel( Gtk.EventBox ): elif category == "percussions": category = "percussions.enterMode" if self.instTable != None: - for child in self.instTable.get_children()[:]: + for child in self.instTable.get_children(): self.instTable.remove(child) self.instBox.remove(self.instTable) self.instTable.destroy() @@ -313,7 +214,6 @@ class InstrumentPanel( Gtk.EventBox ): self.instTable.attach(self.instDic[inst], col, col + 1, row, row + 1, Gtk.AttachOptions.SHRINK, Gtk.AttachOptions.SHRINK, 0, 0) - self.instBox.add(self.instTable) self.instTable.show_all() @@ -327,7 +227,7 @@ class InstrumentPanel( Gtk.EventBox ): def handleInstrumentButtonClick(self,widget,instrument): if widget.get_active() is True and self.recstate == False: if self.setInstrument: - widget.event( Gdk.Event( Gdk.LEAVE_NOTIFY ) ) # fake the leave event + #widget.event( Gdk.Event( Gdk.LEAVE_NOTIFY ) ) # fake the leave event self.setInstrument(instrument) time.sleep(0.05) if self.playInstrument: self.playInstrument(instrument) @@ -340,12 +240,12 @@ class InstrumentPanel( Gtk.EventBox ): def handleInstrumentButtonFocus(self, widget, event, instrument): if self._scrolled_window is None: - parent = widget.parent + parent = widget.get_parent() while parent is not None: if isinstance(parent, Gtk.ScrolledWindow): self._scrolled_window = parent break - parent = parent.parent + parent = parent.get_parent() else: return top = self._scrolled_window @@ -399,8 +299,7 @@ class DrumPanel( Gtk.EventBox ): btnBox.set_border_width(Config.PANEL_SPACING) self.drums = {} for drumkit in self.instrumentList: - instBox = RoundVBox(fillcolor = Config.INST_BCK_COLOR, bordercolor = Config.PANEL_COLOR, radius = Config.PANEL_RADIUS) - instBox.set_border_width(Config.PANEL_SPACING) + instBox = Gtk.VBox() self.drums[drumkit] = ImageRadioButton(firstBtn, drumkit + '.png', drumkit + 'sel.png', drumkit + 'sel.png') self.drums[drumkit].clickedHandler = self.drums[drumkit].connect('clicked',self.setDrums,drumkit) @@ -423,11 +322,3 @@ class DrumPanel( Gtk.EventBox ): btn.handler_block(btn.clickedHandler) btn.set_active(state) btn.handler_unblock(btn.clickedHandler) - -if __name__ == "__main__": - win = Gtk.Window() - wc = DrumPanel(None) - win.add(wc) - win.show() - #start the Gtk event loop - Gtk.main() diff --git a/Mini/miniTamTamMain.py b/Mini/miniTamTamMain.py index 2bfec3d..cf50cae 100644 --- a/Mini/miniTamTamMain.py +++ b/Mini/miniTamTamMain.py @@ -1,7 +1,6 @@ from gi.repository import Gtk from gi.repository import GObject import os -import random import time import xdrlib import commands @@ -41,17 +40,14 @@ from gettext import gettext as _ Tooltips = Config.Tooltips -class miniTamTamMain(Gtk.EventBox): +class miniTamTamMain(Gtk.HBox): def __init__(self, activity): - Gtk.EventBox.__init__(self) + Gtk.HBox.__init__(self) self.instrumentPanel = None self.activity = activity - #self.set_border_width(Config.MAIN_WINDOW_PADDING) - #self.set_border_width(0) - self.instrumentDB = InstrumentDB.getRef() self.firstTime = False self.playing = False @@ -88,12 +84,11 @@ class miniTamTamMain(Gtk.EventBox): self.sequencer.beat = self.beat self.loop.beat = self.beat - self.mainWindowBox = Gtk.HBox() self.leftBox = Gtk.VBox() self.rightBox = Gtk.VBox() - self.mainWindowBox.pack_start(self.rightBox, False, True, 0) - self.mainWindowBox.pack_start(self.leftBox, True, True, 0) - self.add(self.mainWindowBox) + # TODO: right is at left, and left is at right? + self.pack_start(self.rightBox, False, False, 0) + self.pack_start(self.leftBox, False, False, 0) self.enableKeyboard() self.setInstrument(self.instrument) @@ -177,7 +172,6 @@ class miniTamTamMain(Gtk.EventBox): self.activity.connect( "shared", self.shared ) if os.path.isfile("FORCE_SHARE"): # HOST - r = random.random() #print "::::: Sharing as TTDBG%f :::::" % r #self.activity.set_title(_("TTDBG%f" % r)) print "::::: Sharing as TamTam :::::" @@ -192,9 +186,7 @@ class miniTamTamMain(Gtk.EventBox): def drawGeneration( self ): - slidersBox = RoundVBox(fillcolor = Config.PANEL_COLOR, bordercolor = Config.PANEL_BCK_COLOR, radius = Config.PANEL_RADIUS) - slidersBox.set_border_width(Config.PANEL_SPACING) - + slidersBox = Gtk.VBox() geneSliderBox = Gtk.VBox() self.geneSliderBoxImgTop = Gtk.Image() self.geneSliderBoxImgTop.set_from_file(imagefile('complex6.png')) @@ -259,20 +251,12 @@ class miniTamTamMain(Gtk.EventBox): slidersBoxSub.pack_start(volumeSliderBox, True, True, 0) slidersBox.pack_start(slidersBoxSub, True, True, 0) - generateBtnSub = RoundHBox( - fillcolor=Config.PANEL_COLOR, - bordercolor=Config.PANEL_BCK_COLOR, - radius=Config.PANEL_RADIUS) - generateBtnSub.set_border_width(Config.PANEL_SPACING) + generateBtnSub = Gtk.HBox() - #playImg = Gtk.Image() - #playImg.set_from_icon_name('media-playback-start', Gtk.ICON_SIZE_LARGE_TOOLBAR) self.playButton = ImageToggleButton('miniplay.png', 'stop.png') - #self.playButton.set_relief(Gtk.RELIEF_NONE) - #self.playButton.set_image(playImg) self.playButton.connect('clicked',self.handlePlayButton) generateBtnSub.pack_start(self.playButton, True, True, 0) - #self.playButton.set_tooltip(_('Play / Stop')) + self.playButton.set_tooltip_text(_('Play / Stop')) generateBtn = ImageButton('dice.png', clickImg_path='diceblur.png') generateBtn.connect('button-press-event', self.handleGenerateBtn) @@ -281,10 +265,7 @@ class miniTamTamMain(Gtk.EventBox): # drums - drum_box = RoundVBox( - fillcolor=Config.PANEL_COLOR, - bordercolor=Config.PANEL_BCK_COLOR, - radius=Config.PANEL_RADIUS) + drum_box = Gtk.VBox() drum_scroll = VScrolledBox(scroll_policy=Gtk.PolicyType.NEVER) drum_scroll.set_viewport(drum_box) @@ -346,13 +327,13 @@ class miniTamTamMain(Gtk.EventBox): def updateInstrumentPanel(self): if self.instrumentPanel is None: self.instrumentPanel = InstrumentPanel() - self.leftBox.pack_start(self.instrumentPanel, True, True, 0) width = Gdk.Screen.width() - self.rightBox.get_size_request()[0] self.instrumentPanel.configure(self.setInstrument, self.playInstrumentNote, False, self.micRec, width=width) self.instrumentPanel.load() + self.leftBox.pack_start(self.instrumentPanel, True, True, 0) def micRec(self, widget, mic): self.csnd.inputMessage("i5600 0 4") @@ -413,12 +394,12 @@ class miniTamTamMain(Gtk.EventBox): self.activity.close() def handleGenerationSlider(self, adj): - img = int(adj.value * 7)+1 + img = int(adj.get_value() * 7)+1 self.geneSliderBoxImgTop.set_from_file( imagefile('complex' + str(img) + '.png')) def handleGenerationSliderRelease(self, widget, event): - self.regularity = widget.get_adjustment().value + self.regularity = widget.get_adjustment().get_value() self.beatPickup = False self.regenerate() self.beatPickup = True @@ -441,7 +422,7 @@ class miniTamTamMain(Gtk.EventBox): self.drumFillin.setBeats( self.beat ) def handleBeatSlider(self, adj): - img = self.scale(int(adj.value),2,12,1,11) + img = self.scale(int(adj.get_value()),2,12,1,11) self.beatSliderBoxImgTop.set_from_file( imagefile('beat' + str(img) + '.png')) self.sequencer.beat = self.beat @@ -449,7 +430,7 @@ class miniTamTamMain(Gtk.EventBox): self.drumFillin.setBeats( self.beat ) def handleBeatSliderRelease(self, widget, event): - self.beat = int(widget.get_adjustment().value) + self.beat = int(widget.get_adjustment().get_value()) self.sequencer.beat = self.beat self.loop.beat = self.beat self.drumFillin.setBeats( self.beat ) @@ -473,9 +454,9 @@ class miniTamTamMain(Gtk.EventBox): def handleTempoSliderChange(self,adj): if self.network.isPeer(): - self.requestTempoChange(int(adj.value)) + self.requestTempoChange(int(adj.get_value())) else: - self._updateTempo( int(adj.value) ) + self._updateTempo(int(adj.get_value())) def _updateTempo( self, val ): @@ -502,7 +483,7 @@ class miniTamTamMain(Gtk.EventBox): imagefile('tempo' + str(img) + '.png')) def handleBalanceSlider(self, adj): - self.instVolume = int(adj.value) + self.instVolume = int(adj.get_value()) self.drumVolume = sqrt( (100-self.instVolume)*0.01 ) self.adjustDrumVolume() self.drumFillin.setVolume(self.drumVolume) @@ -517,7 +498,7 @@ class miniTamTamMain(Gtk.EventBox): imagefile('instr' + str(img2) + '.png')) def handleReverbSlider(self, adj): - self.reverb = adj.value + self.reverb = adj.get_value() self.drumFillin.setReverb( self.reverb ) img = int(self.scale(self.reverb,0,1,0,4)) self._playToolbar.reverbSliderImgRight.set_from_file( @@ -525,7 +506,7 @@ class miniTamTamMain(Gtk.EventBox): self.keyboardStandAlone.setReverb(self.reverb) def handleVolumeSlider(self, adj): - self.volume = adj.value + self.volume = adj.get_value() self.csnd.setMasterVolume(self.volume) img = int(self.scale(self.volume,0,200,0,3.9)) self.volumeSliderBoxImgTop.set_from_file( diff --git a/TamTamMini.py b/TamTamMini.py index 55b63f7..03af715 100644 --- a/TamTamMini.py +++ b/TamTamMini.py @@ -20,33 +20,25 @@ import locale locale.setlocale(locale.LC_NUMERIC, 'C') -import signal -import time -import sys import os -import shutil import logging from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GObject -import time -import common.Util.Instruments import common.Config as Config from common.Util.CSoundClient import new_csound_client -from common.Util.Profiler import TP from Mini.miniTamTamMain import miniTamTamMain from common.Util.Trackpad import Trackpad from gettext import gettext as _ -import commands from sugar3.activity import activity -if Config.HAVE_TOOLBOX: - from sugar3.graphics.toolbarbox import ToolbarBox - from sugar3.activity import widgets +from sugar3.graphics.toolbarbox import ToolbarBox +from sugar3.activity import widgets +from sugar3.activity.widgets import DescriptionItem class TamTamMini(activity.Activity): @@ -58,8 +50,8 @@ class TamTamMini(activity.Activity): activity.Activity.__init__(self, handle) - color = Gdk.color_parse(Config.WS_BCK_COLOR) - self.modify_bg(Gtk.StateType.NORMAL, color) + #color = Gdk.color_parse(Config.WS_BCK_COLOR) + #self.modify_bg(Gtk.StateType.NORMAL, color) self.set_title('TamTam Mini') self.set_resizable(False) @@ -71,49 +63,43 @@ class TamTamMini(activity.Activity): self.connect('destroy', self.onDestroy) #load the sugar toolbar - if Config.HAVE_TOOLBOX: - self.toolbox = ToolbarBox() - self.toolbox.toolbar.insert(widgets.ActivityButton(self), -1) - self.toolbox.toolbar.insert(widgets.TitleEntry(self), -1) + toolbox = ToolbarBox() + toolbox.toolbar.insert(widgets.ActivityButton(self), -1) + toolbox.toolbar.insert(widgets.TitleEntry(self), -1) - try: - from sugar3.activity.widgets import DescriptionItem - except ImportError: - logging.debug('DescriptionItem button is not available,' + - 'toolkit version < 0.96') - else: - description_item = DescriptionItem(self) - self.toolbox.toolbar.insert(description_item, -1) - description_item.show() - - self.toolbox.toolbar.insert(widgets.ShareButton(self), -1) - else: - self.toolbox = activity.ActivityToolbox(self) - self.set_toolbox(self.toolbox) + description_item = DescriptionItem(self) + toolbox.toolbar.insert(description_item, -1) + description_item.show() + + toolbox.toolbar.insert(widgets.ShareButton(self), -1) + + separator = Gtk.SeparatorToolItem() + separator.props.draw = False + separator.set_expand(True) + toolbox.toolbar.insert(separator, -1) - self.toolbox.show() + toolbox.toolbar.insert(widgets.StopButton(self), -1) + toolbox.toolbar.show_all() + + toolbox.show() + self.set_toolbar_box(toolbox) self.mini = miniTamTamMain(self) self.mini.onActivate(arg=None) self.mini.updateInstrumentPanel() + #self.modeList[mode].regenerate() self.set_canvas(self.mini) self.mini.instrumentPanel.grab_focus() - - if Config.HAVE_TOOLBOX: - separator = Gtk.SeparatorToolItem() - separator.props.draw = False - separator.set_expand(True) - self.toolbox.toolbar.insert(separator, -1) - self.toolbox.toolbar.insert(widgets.StopButton(self), -1) - self.toolbox.toolbar.show_all() - + self.set_size_request(Gdk.Screen.width(), Gdk.Screen.height()) self.show() + logging.error('Activity startup end') def do_size_allocate(self, allocation): activity.Activity.do_size_allocate(self, allocation) if self.mini is not None: + logging.error('TamTamMini size alloc %s', (allocation.x, allocation.y, allocation.width, allocation.height)) self.mini.updateInstrumentPanel() def onActive(self, widget=None, event=None): diff --git a/common/Util/ThemeWidgets.py b/common/Util/ThemeWidgets.py index 8bc00ce..cec83e6 100644 --- a/common/Util/ThemeWidgets.py +++ b/common/Util/ThemeWidgets.py @@ -11,103 +11,6 @@ from sugar3.graphics.palette import Palette, WidgetInvoker def gdk_color_to_cairo(color): return (color.red/65536.0, color.green/65536.0, color.blue/65536.0) -class ITYPE: - PIXBUF = 0 - PIXMAP = 1 - -class ImageHScale( Gtk.HScale ): - def __init__( self, image_name, adjustment = None, slider_border = 0, insensitive_name = None, trough_color = "#3D403A", snap = False ): - Gtk.HScale.__init__( self, adjustment ) - - if snap: self.snap = 1/snap - else: self.snap = False - - colormap = self.get_colormap() - self.troughcolor = colormap.alloc_color( trough_color, True, True ) - - img = Gtk.Image() - img.set_from_file( image_name ) - self.sliderPixbuf = img.get_pixbuf() - - if insensitive_name == None: - self.insensitivePixbuf = None - else: - img = Gtk.Image() - img.set_from_file( insensitive_name ) - self.insensitivePixbuf = img.get_pixbuf() - - name = image_name + "ImageHScale" - self.set_name(name) - - # TODO: replace by new gtk3 styles - rc_str = """ -style "scale_style" { - GtkRange::slider_width = %d - GtkScale::slider_length = %d -} -widget "*%s*" style "scale_style" - """ % ( self.sliderPixbuf.get_width(), self.sliderPixbuf.get_height(), name) - #gtk.rc_parse_string( rc_str ) - - self.pixbufWidth = self.sliderPixbuf.get_width() - self.pixbufHeight = self.sliderPixbuf.get_height() - self.sliderBorder = slider_border - self.sliderBorderMUL2 = self.sliderBorder*2 - - self.set_draw_value(False) - - self.connect( "draw", self.expose ) - self.connect( "size-allocate", self.size_allocate ) - self.connect( "button-release-event", self.button_release ) - adjustment.connect( "changed", self.value_changed ) - adjustment.connect( "value-changed", self.value_changed ) - - def size_allocate( self, widget, allocation ): - self.alloc = allocation - self.sliderY = self.alloc.height//2 - self.pixbufHeight//2 - return False - - def set_snap( self, snap ): - if snap: self.snap = 1/snap - else: self.snap = False - self.queue_draw() - - def value_changed( self, adjustment ): - if self.snap: - val = round(self.snap*self.get_value())/self.snap - if val != self.get_value(): - self.set_value( val ) - return True - - def expose( self, widget, event ): - - style = self.get_style() - gc = style.fg_gc[Gtk.StateType.NORMAL] - - gc.foreground = self.troughcolor - - self.window.draw_rectangle( gc, True, self.alloc.x + self.sliderBorder, self.alloc.y + self.alloc.height//2 - 1, self.alloc.width - self.sliderBorderMUL2, 3 ) - - val = self.get_value() - if self.snap: - val = round(self.snap*val)/self.snap - adj = self.get_adjustment() - if self.get_inverted(): - sliderX = int((self.alloc.width - self.pixbufWidth)*(adj.upper-val)/(adj.upper - adj.lower)) - else: - sliderX = int((self.alloc.width - self.pixbufWidth)*(val-adj.lower)/(adj.upper - adj.lower)) - - if self.insensitivePixbuf != None and self.state == Gtk.StateType.INSENSITIVE: - self.window.draw_pixbuf( gc, self.insensitivePixbuf, 0, 0, self.alloc.x + sliderX, self.alloc.y + self.sliderY, self.pixbufWidth, self.pixbufHeight, gtk.gdk.RGB_DITHER_NORMAL, 0, 0 ) - else: - self.window.draw_pixbuf( gc, self.sliderPixbuf, 0, 0, self.alloc.x + sliderX, self.alloc.y + self.sliderY, self.pixbufWidth, self.pixbufHeight, gtk.gdk.RGB_DITHER_NORMAL, 0, 0 ) - - return True - - def button_release( self, widget, event ): - - if self.snap: - self.set_value( round(self.snap*self.get_value())/self.snap ) class ImageVScale( Gtk.VScale ): def __init__(self, image_name, adjustment=None, slider_border=0, @@ -116,7 +19,6 @@ class ImageVScale( Gtk.VScale ): Gtk.VScale.__init__(self) self.set_adjustment(adjustment) - #Gtk.VScale.__init__( self, adjustment ) if snap: self.snap = 1/snap else: self.snap = False @@ -179,26 +81,36 @@ widget "*%s*" style "scale_style" def __draw_cb( self, widget, ctx): - style = self.get_style() - gc = style.fg_gc[Gtk.StateType.NORMAL] - - gc.foreground = self.troughcolor - - self.window.draw_rectangle( gc, True, self.alloc.x + self.alloc.width//2 - 1, self.alloc.y + self.sliderBorder, 3, self.alloc.height - self.sliderBorderMUL2 ) + ctx.save() + ctx.set_source_rgb(0, 0, 0) + ctx.rectangle(self.alloc.x + self.alloc.width // 2 - 1, + self.alloc.y + self.sliderBorder, 3, + self.alloc.height - self.sliderBorderMUL2 ) + ctx.fill() + ctx.restore() val = self.get_value() if self.snap: val = round(self.snap*val)/self.snap adj = self.get_adjustment() + if self.get_inverted(): - sliderY = int((self.alloc.height - self.pixbufHeight)*(adj.upper-val)/(adj.upper - adj.lower)) + sliderY = int((self.alloc.height - self.pixbufHeight) * \ + (adj.get_upper() - val) / (adj.get_upper() - adj.get_lower())) else: - sliderY = int((self.alloc.height - self.pixbufHeight)*(val-adj.lower)/(adj.upper - adj.lower)) + sliderY = int((self.alloc.height - self.pixbufHeight)* \ + (val - adj.get_lower()) / (adj.get_upper() - adj.get_lower())) + + if self.insensitivePixbuf != None and \ + self.state == Gtk.StateType.INSENSITIVE: + Gdk.cairo_set_source_pixbuf(ctx, self.insensitivePixbuf, 0, 0) + ctx.paint() - if self.insensitivePixbuf != None and self.state == gtk.STATE_INSENSITIVE: - self.window.draw_pixbuf( gc, self.insensitivePixbuf, 0, 0, self.alloc.x + self.sliderX, self.alloc.y + sliderY, self.pixbufWidth, self.pixbufHeight, gtk.gdk.RGB_DITHER_NORMAL, 0, 0 ) + #self.window.draw_pixbuf( gc, self.insensitivePixbuf, 0, 0, self.alloc.x + self.sliderX, self.alloc.y + sliderY, self.pixbufWidth, self.pixbufHeight, gtk.gdk.RGB_DITHER_NORMAL, 0, 0 ) else: - self.window.draw_pixbuf( gc, self.sliderPixbuf, 0, 0, self.alloc.x + self.sliderX, self.alloc.y + sliderY, self.pixbufWidth, self.pixbufHeight, gtk.gdk.RGB_DITHER_NORMAL, 0, 0 ) + Gdk.cairo_set_source_pixbuf(ctx, self.sliderPixbuf, 0, 0) + ctx.paint() + #self.window.draw_pixbuf( gc, self.sliderPixbuf, 0, 0, self.alloc.x + self.sliderX, self.alloc.y + sliderY, self.pixbufWidth, self.pixbufHeight, gtk.gdk.RGB_DITHER_NORMAL, 0, 0 ) return True @@ -381,6 +293,9 @@ class RoundHBox( Gtk.HBox ): def draw( self, widget, cr): if self.alloc == None: return + # TODO + Gtk.HBox.do_draw( self, cr ) + return True #TP.ProfileBegin( "Round*Box::expose" ) @@ -546,6 +461,8 @@ class RoundVBox( Gtk.VBox ): if self.get_allocation() is None: return + Gtk.VBox.do_draw( self, ctx) + return True #TP.ProfileBegin( "Round*Box::expose" ) @@ -685,7 +602,6 @@ class RoundFixed( Gtk.Fixed ): if self.alloc == None: return - #TP.ProfileBegin( "Round*Box::expose" ) area = widget.get_allocation() startX = area.x - self.alloc.x startY = area.y - self.alloc.y @@ -751,21 +667,15 @@ class RoundFixed( Gtk.Fixed ): gc.foreground = saveForeground - #TP.ProfileEnd( "Round*Box::expose" ) - return False class ImageButton(Gtk.Button): def __init__(self, mainImg_path, clickImg_path=None, enterImg_path=None, backgroundFill=None ): - #mainImg_path = imagefile(mainImg_path) - #clickImg_path = imagefile(clickImg_path) - #enterImg_path = imagefile(enterImg_path) Gtk.Button.__init__(self) self.alloc = None self.image = {} - self.itype = {} self.iwidth = {} self.iwidthDIV2 = {} self.iheight = {} @@ -785,7 +695,6 @@ class ImageButton(Gtk.Button): self.is_png = False self.image[name] = pix - self.itype[name] = ITYPE.PIXBUF self.iwidth[name] = pix.get_width() self.iwidthDIV2[name] = self.iwidth[name]//2 @@ -804,7 +713,6 @@ class ImageButton(Gtk.Button): self.connect('released',self.on_btn_release, None) if enterImg_path == None: self.image["enter"] = self.image["main"] - self.itype["enter"] = self.itype["main"] self.iwidth["enter"] = self.iwidth["main"] self.iwidthDIV2["enter"] = self.iwidthDIV2["main"] self.iheight["enter"] = self.iheight["main"] @@ -818,7 +726,6 @@ class ImageButton(Gtk.Button): self.connect('draw', self.draw) self.connect('size-allocate', self.size_allocate) - self.set_size_request(self.iwidth["main"],self.iheight["main"]) def size_allocate(self, widget, allocation): self.alloc = allocation @@ -836,14 +743,7 @@ class ImageButton(Gtk.Button): cr.paint() return True - #TODO Gtk3: verify draw is similar and remove expose - def expose(self, widget, event): - if self.itype[self.curImage] == ITYPE.PIXBUF: - self.window.draw_pixbuf( self.gc, self.image[self.curImage], 0, 0, self.drawX - self.iwidthDIV2[self.curImage], self.drawY - self.iheightDIV2[self.curImage], self.iwidth[self.curImage], self.iheight[self.curImage], gtk.gdk.RGB_DITHER_NONE) - else: - self.window.draw_drawable( self.gc, self.image[self.curImage], 0, 0, self.drawX - self.iwidthDIV2[self.curImage], self.drawY - self.iheightDIV2[self.curImage], self.iwidth[self.curImage], self.iheight[self.curImage] ) - return True - + """ def setImage(self, name, pix): print "setImage ", name, pix if name == "main" and self.image["main"] == self.image["enter"]: @@ -854,18 +754,15 @@ class ImageButton(Gtk.Button): if pix.get_has_alpha(): if self.backgroundFill == None: self.image[name] = pix - self.itype[name] = ITYPE.PIXBUF else: self.image[name] = gtk.gdk.Pixmap( win, pix.get_width(), pix.get_height() ) colormap = self.get_colormap() self.gc.foreground = colormap.alloc_color( self.backgroundFill, True, True ) self.image[name].draw_rectangle( self.gc, True, 0, 0, pix.get_width(), pix.get_height() ) self.image[name].draw_pixbuf( self.gc, pix, 0, 0, 0, 0, pix.get_width(), pix.get_height(), gtk.gdk.RGB_DITHER_NONE ) - self.itype[name] = ITYPE.PIXMAP else: self.image[name] = gtk.gdk.Pixmap( win, pix.get_width(), pix.get_height() ) self.image[name].draw_pixbuf( self.gc, pix, 0, 0, 0, 0, pix.get_width(), pix.get_height(), gtk.gdk.RGB_DITHER_NONE ) - self.itype[name] = ITYPE.PIXMAP self.iwidth[name] = pix.get_width() self.iwidthDIV2[name] = self.iwidth[name]//2 self.iheight[name] = pix.get_height() @@ -873,7 +770,6 @@ class ImageButton(Gtk.Button): if updateEnter: self.image["enter"] = self.image["main"] - self.itype["enter"] = self.itype["main"] self.iwidth["enter"] = self.iwidth["main"] self.iwidthDIV2["enter"] = self.iwidthDIV2["main"] self.iheight["enter"] = self.iheight["main"] @@ -882,6 +778,7 @@ class ImageButton(Gtk.Button): self.connect('leave-notify-event',self.on_btn_leave) self.queue_draw() + """ def on_btn_press(self, widget, event): self.curImage = "click" @@ -889,14 +786,14 @@ class ImageButton(Gtk.Button): self.queue_draw() def on_btn_enter(self, widget, event): - if event.mode == gtk.gdk.CROSSING_NORMAL: + if event.mode == Gdk.CrossingMode.NORMAL : self.upImage = "enter" if self.down: self.curImage = "click" else: self.curImage = "enter" self.queue_draw() def on_btn_leave(self, widget, event): - if event.mode == gtk.gdk.CROSSING_NORMAL: + if event.mode == Gdk.CrossingMode.NORMAL : self.curImage = self.upImage = "main" self.queue_draw() @@ -924,7 +821,6 @@ class ImageToggleButton(Gtk.ToggleButton): self.is_png = True self.image = {} - self.itype = {} self.iwidth = {} self.iwidthDIV2 = {} self.iheight = {} @@ -942,7 +838,6 @@ class ImageToggleButton(Gtk.ToggleButton): self.is_png = False self.image[name] = pix - self.itype[name] = ITYPE.PIXBUF self.iwidth[name] = pix.get_width() self.iwidthDIV2[name] = self.iwidth[name]//2 @@ -956,7 +851,6 @@ class ImageToggleButton(Gtk.ToggleButton): prepareImage( "enter", enterImg_path ) else: self.image["enter"] = self.image["main"] - self.itype["enter"] = self.itype["main"] self.iwidth["enter"] = self.iwidth["main"] self.iwidthDIV2["enter"] = self.iwidthDIV2["main"] self.iheight["enter"] = self.iheight["main"] @@ -969,8 +863,6 @@ class ImageToggleButton(Gtk.ToggleButton): self.connect('pressed',self.pressed ) self.connect('released',self.released ) self.connect('draw', self.draw) - self.connect('size-allocate', self.size_allocate) - self.set_size_request(self.iwidth["main"],self.iheight["main"]) self.toggleImage( self ) @@ -989,18 +881,6 @@ class ImageToggleButton(Gtk.ToggleButton): cr.paint() return True - #TODO Gtk3: verify draw is similar and remove expose - def expose(self, widget, cr): - if self.itype[self.curImage] == ITYPE.PIXBUF: - cr.set_source_surface(self.image[self.curImage], 0, 0) - cr.paint() - #self.window.draw_pixbuf( self.gc, self.image[self.curImage], 0, 0, self.drawX - self.iwidthDIV2[self.curImage], self.drawY - self.iheightDIV2[self.curImage], self.iwidth[self.curImage], self.iheight[self.curImage], gtk.gdk.RGB_DITHER_NONE) - else: - cr.set_source_surface(self.image[self.curImage], 0, 0) - cr.paint() - #self.window.draw_drawable( self.gc, self.image[self.curImage], 0, 0, self.drawX - self.iwidthDIV2[self.curImage], self.drawY - self.iheightDIV2[self.curImage], self.iwidth[self.curImage], self.iheight[self.curImage] ) - return True - def setImage(self, name, pix): if name == "main" and self.image["main"] == self.image["enter"]: updateEnter = True @@ -1010,7 +890,6 @@ class ImageToggleButton(Gtk.ToggleButton): if True: if self.backgroundFill == None: self.image[name] = pix - self.itype[name] = ITYPE.PIXBUF else: self.image[name] = cairo.ImageSurface(cairo.FORMAT_RGB24, pix.get_width(), pix.get_height() ) cxt = cairo.Context(self.image[name]) @@ -1019,12 +898,10 @@ class ImageToggleButton(Gtk.ToggleButton): cxt.rectangle(0, 0, pix.get_width(), pix.get_height() ) cxt.fill() cxt.set_source_pixbuf(pix, 0, 0) - self.itype[name] = ITYPE.PIXMAP else: self.image[name] = cairo.ImageSurface(cairo.FORMAT_RGB24, pix.get_width(), pix.get_height() ) cxt = cairo.Context(self.image[name]) cxt.set_source_pixbuf( pix, 0, 0) - self.itype[name] = ITYPE.PIXMAP self.iwidth[name] = pix.get_width() self.iwidthDIV2[name] = self.iwidth[name]//2 self.iheight[name] = pix.get_height() @@ -1032,7 +909,6 @@ class ImageToggleButton(Gtk.ToggleButton): if updateEnter: self.image["enter"] = self.image["main"] - self.itype["enter"] = self.itype["main"] self.iwidth["enter"] = self.iwidth["main"] self.iwidthDIV2["enter"] = self.iwidthDIV2["main"] self.iheight["enter"] = self.iheight["main"] @@ -1092,14 +968,13 @@ class ImageRadioButton(Gtk.RadioButton): altImg_path = imagefile(altImg_path) enterImg_path = imagefile(enterImg_path) - Gtk.RadioButton.__init__(self, group) - self.alloc = None + Gtk.RadioButton.__init__(self) + if group is not None: + self.join_group(group) self.within = False self.clicked = False - - win = Gdk.get_default_root_window() + self.set_label('') self.image = {} - self.itype = {} self.iwidth = {} self.iwidthDIV2 = {} self.iheight = {} @@ -1117,7 +992,6 @@ class ImageRadioButton(Gtk.RadioButton): self.is_png = False self.image[name] = pix - self.itype[name] = ITYPE.PIXBUF self.iwidth[name] = pix.get_width() self.iwidthDIV2[name] = self.iwidth[name]//2 @@ -1131,7 +1005,6 @@ class ImageRadioButton(Gtk.RadioButton): prepareImage( "enter", enterImg_path ) else: self.image["enter"] = self.image["main"] - self.itype["enter"] = self.itype["main"] self.iwidth["enter"] = self.iwidth["main"] self.iwidthDIV2["enter"] = self.iwidthDIV2["main"] self.iheight["enter"] = self.iheight["main"] @@ -1140,22 +1013,18 @@ class ImageRadioButton(Gtk.RadioButton): self.connect('enter-notify-event',self.on_btn_enter) self.connect('leave-notify-event',self.on_btn_leave) - self.connect("toggled", self.toggleImage ) + self.connect("toggled", self.toggleImage) self.connect('pressed',self.pressed ) self.connect('released',self.released ) - self.connect('size-allocate', self.size_allocate) self.connect('draw', self.draw) self.set_size_request(self.iwidth["main"],self.iheight["main"]) - self.toggleImage( self ) - - def size_allocate(self, widget, allocation): - self.alloc = allocation - self.drawX = allocation.x + allocation.width//2 - self.drawY = allocation.y + allocation.height//2 + self.curImage = "main" + self.queue_draw() def draw(self, widget, cr): + logging.error('on_draw %s %s', self.get_active(), self.curImage) if self.is_png: cr.set_source_surface(self.image[self.curImage], 0, 0) cr.paint() @@ -1164,52 +1033,6 @@ class ImageRadioButton(Gtk.RadioButton): cr.paint() return True - #TODO Gtk3: verify draw is similar and remove expose - def expose(self, widget, event): - if self.itype[self.curImage] == ITYPE.PIXBUF: - self.window.draw_pixbuf( self.gc, self.image[self.curImage], 0, 0, self.drawX - self.iwidthDIV2[self.curImage], self.drawY - self.iheightDIV2[self.curImage], self.iwidth[self.curImage], self.iheight[self.curImage], gtk.gdk.RGB_DITHER_NONE) - else: - self.window.draw_drawable( self.gc, self.image[self.curImage], 0, 0, self.drawX - self.iwidthDIV2[self.curImage], self.drawY - self.iheightDIV2[self.curImage], self.iwidth[self.curImage], self.iheight[self.curImage] ) - return True - - def setImage(self, name, pix): - if name == "main" and self.image["main"] == self.image["enter"]: - updateEnter = True - else: - updateEnter = False - - if pix.get_has_alpha(): - if self.backgroundFill == None: - self.image[name] = pix - self.itype[name] = ITYPE.PIXBUF - else: - self.image[name] = gtk.gdk.Pixmap( win, pix.get_width(), pix.get_height() ) - colormap = self.get_colormap() - self.gc.foreground = colormap.alloc_color( self.backgroundFill, True, True ) - self.image[name].draw_rectangle( self.gc, True, 0, 0, pix.get_width(), pix.get_height() ) - self.image[name].draw_pixbuf( self.gc, pix, 0, 0, 0, 0, pix.get_width(), pix.get_height(), gtk.gdk.RGB_DITHER_NONE ) - self.itype[name] = ITYPE.PIXMAP - else: - self.image[name] = gtk.gdk.Pixmap( win, pix.get_width(), pix.get_height() ) - self.image[name].draw_pixbuf( self.gc, pix, 0, 0, 0, 0, pix.get_width(), pix.get_height(), gtk.gdk.RGB_DITHER_NONE ) - self.itype[name] = ITYPE.PIXMAP - self.iwidth[name] = pix.get_width() - self.iwidthDIV2[name] = self.iwidth[name]//2 - self.iheight[name] = pix.get_height() - self.iheightDIV2[name] = self.iheight[name]//2 - - if updateEnter: - self.image["enter"] = self.image["main"] - self.itype["enter"] = self.itype["main"] - self.iwidth["enter"] = self.iwidth["main"] - self.iwidthDIV2["enter"] = self.iwidthDIV2["main"] - self.iheight["enter"] = self.iheight["main"] - self.iheightDIV2["enter"] = self.iheightDIV2["main"] - self.connect('enter-notify-event',self.on_btn_enter) - self.connect('leave-notify-event',self.on_btn_leave) - - self.queue_draw() - def toggleImage( self, widget ): if not self.get_active(): if self.within and self.image.has_key("enter"): @@ -1226,22 +1049,22 @@ class ImageRadioButton(Gtk.RadioButton): self.queue_draw() def released( self, widget ): - self.clicked = False - self.toggleImage( self ) + self.curImage = "main" + self.queue_draw() def on_btn_enter(self, widget, event): - if event.mode == gtk.gdk.CROSSING_NORMAL: + if event.mode == Gdk.CrossingMode.NORMAL: self.within = True - if not self.get_active() and not self.clicked: + if not self.clicked: self.curImage = "enter" else: self.curImage = "alt" self.queue_draw() def on_btn_leave(self, widget, event): - if event.mode == gtk.gdk.CROSSING_NORMAL: + if event.mode == Gdk.CrossingMode.NORMAL: self.within = False - if not self.get_active(): + if not self.clicked: self.curImage = "main" else: self.curImage = "alt" @@ -1253,7 +1076,7 @@ class ImageRadioButton(Gtk.RadioButton): self._palette.props.invoker._position_hint = WidgetInvoker.AT_CURSOR class keyButton(Gtk.Button): - import cairo + def __init__(self, width, height, fillcolor, strokecolor): Gtk.Button.__init__(self) self.alloc = None -- cgit v0.9.1