mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 17:45:40 -05:00
Created the VectorIconSetupModal, a quick way to get portraits aligned to a container.
This commit is contained in:
parent
bd969c017e
commit
913dda65aa
8 changed files with 196 additions and 8 deletions
|
@ -40,12 +40,17 @@ module.exports = class SpriteParser
|
|||
if movieClips.length
|
||||
# First movie clip is root, so do it last
|
||||
movieClips = movieClips[1 ... movieClips.length].concat([movieClips[0]])
|
||||
else if containers.length
|
||||
# First container is root, so do it last
|
||||
containers = containers[1 ... containers.length].concat([containers[0]])
|
||||
|
||||
# first container isn't necessarily root... actually the last one is root in blue-cart
|
||||
# else if containers.length
|
||||
# # First container is root, so do it last
|
||||
# containers = containers[1 ... containers.length].concat([containers[0]])
|
||||
mainClip = _.last(movieClips) ? _.last(containers)
|
||||
@animationName = mainClip.name
|
||||
for container in containers
|
||||
for container, index in containers
|
||||
if index is containers.length - 1 and not movieClips.length and container.bounds?.length
|
||||
container.bounds[0] -= @width / 2
|
||||
container.bounds[1] -= @height / 2
|
||||
[shapeKeys, localShapes] = @getShapesFromBlock container, source
|
||||
localContainers = @getContainersFromMovieClip container, source
|
||||
addChildArgs = @getAddChildCallArguments container, source
|
||||
|
@ -62,6 +67,7 @@ module.exports = class SpriteParser
|
|||
if c.bn is bn
|
||||
instructions.push {t: c.t, gn: c.gn}
|
||||
break
|
||||
continue unless container.bounds and instructions.length
|
||||
@addContainer {c: instructions, b: container.bounds}, container.name
|
||||
for movieClip, index in movieClips
|
||||
if index is 0
|
||||
|
|
|
@ -240,7 +240,6 @@ module.exports = class ThangType extends CocoModel
|
|||
return if _.isString spriteSheet
|
||||
return unless spriteSheet
|
||||
canvas = $("<canvas width='#{size}' height='#{size}'></canvas>")
|
||||
console.log 'made canvas', canvas, 'with size', size unless canvas[0]
|
||||
stage = new createjs.Stage(canvas[0])
|
||||
sprite = new createjs.Sprite(spriteSheet)
|
||||
pt = @actions.portrait?.positions?.registration
|
||||
|
@ -262,6 +261,29 @@ module.exports = class ThangType extends CocoModel
|
|||
@tick = null
|
||||
stage
|
||||
|
||||
getVectorPortraitStage: (size=100) ->
|
||||
return unless @actions
|
||||
canvas = $("<canvas width='#{size}' height='#{size}'></canvas>")
|
||||
stage = new createjs.Stage(canvas[0])
|
||||
portrait = @actions.portrait
|
||||
return unless portrait and (portrait.animation or portrait.container)
|
||||
scale = portrait.scale or 1
|
||||
|
||||
vectorParser = new SpriteBuilder(@, {})
|
||||
if portrait.animation
|
||||
sprite = vectorParser.buildMovieClip portrait.animation
|
||||
sprite.gotoAndStop(0)
|
||||
else if portrait.container
|
||||
sprite = vectorParser.buildContainerFromStore(portrait.container)
|
||||
|
||||
pt = portrait.positions?.registration
|
||||
sprite.regX = pt?.x or 0
|
||||
sprite.regY = pt?.y or 0
|
||||
sprite.scaleX = sprite.scaleY = scale * size / 100
|
||||
stage.addChild(sprite)
|
||||
stage.update()
|
||||
stage
|
||||
|
||||
uploadGenericPortrait: (callback, src) ->
|
||||
src ?= @getPortraitSource()
|
||||
return callback?() unless src and src.startsWith 'data:'
|
||||
|
|
|
@ -130,6 +130,7 @@ _.extend ThangTypeSchema.properties,
|
|||
positions: PositionsSchema
|
||||
raster: {type: 'string', format: 'image-file', title: 'Raster Image'}
|
||||
rasterIcon: { type: 'string', format: 'image-file', title: 'Raster Image Icon' }
|
||||
containerIcon: { type: 'string' }
|
||||
featureImage: { type: 'string', format: 'image-file', title: 'Feature Image' }
|
||||
colorGroups: c.object
|
||||
title: 'Color Groups'
|
||||
|
|
9
app/styles/editor/thang/vector-icon-setup-modal.sass
Normal file
9
app/styles/editor/thang/vector-icon-setup-modal.sass
Normal file
|
@ -0,0 +1,9 @@
|
|||
#vector-icon-setup-modal
|
||||
select
|
||||
margin-bottom: 20px
|
||||
|
||||
canvas
|
||||
background: lightblue
|
||||
border: 3px solid black
|
||||
margin: 20px auto
|
||||
display: block
|
|
@ -81,12 +81,15 @@ block outer_content
|
|||
div#settings-col.well
|
||||
img#portrait.img-thumbnail
|
||||
div.file-controls
|
||||
button(disabled=authorized === true ? undefined : "true").btn.btn-small.btn-info#upload-button
|
||||
button(disabled=authorized === true ? undefined : "true").btn.btn-sm.btn-info#upload-button
|
||||
span.glyphicon.glyphicon-upload
|
||||
span.spl Upload Animation
|
||||
button(disabled=authorized === true ? undefined : "true").btn.btn-small.btn-danger#clear-button
|
||||
button(disabled=authorized === true ? undefined : "true").btn.btn-sm.btn-danger#clear-button
|
||||
span.glyphicon.glyphicon-remove
|
||||
span.spl Clear Data
|
||||
button#set-vector-icon(disabled=authorized === true ? undefined : "true").btn.btn-sm
|
||||
span.glyphicon.glyphicon-gbp
|
||||
span.spl Vector Icon Setup
|
||||
input#real-upload-button(type="file")
|
||||
#thang-type-file-size= fileSizeString
|
||||
div#thang-type-treema
|
||||
|
|
24
app/templates/editor/thang/vector-icon-setup-modal.jade
Normal file
24
app/templates/editor/thang/vector-icon-setup-modal.jade
Normal file
|
@ -0,0 +1,24 @@
|
|||
extends /templates/modal/modal_base
|
||||
|
||||
block modal-header-content
|
||||
h3 Choose Container for Vector Icon
|
||||
|
||||
block modal-body-content
|
||||
if chosenContainer
|
||||
form.form
|
||||
.form-group
|
||||
select#container-select.form-control
|
||||
for container in containers
|
||||
option(value=container, selected=container === chosenContainer)= container
|
||||
|
||||
canvas(width=demoSize height=demoSize)#resulting-icon
|
||||
|
||||
.alert.alert-info Arrow keys to move, Shift-Plus/Minus to scale.
|
||||
else
|
||||
div forgetting something?
|
||||
|
||||
block modal-footer-content
|
||||
button.btn.pull-left.btn-info#center
|
||||
span.glyphicon.glyphicon-cutlery
|
||||
span.spl Center
|
||||
button.btn.btn-primary#done-button Done
|
|
@ -12,6 +12,7 @@ ThangTypeVersionsModal = require './ThangTypeVersionsModal'
|
|||
ThangTypeColorsTabView = require './ThangTypeColorsTabView'
|
||||
PatchesView = require 'views/editor/PatchesView'
|
||||
ForkModal = require 'views/editor/ForkModal'
|
||||
VectorIconSetupModal = require 'views/editor/thang/VectorIconSetupModal'
|
||||
SaveVersionModal = require 'views/modal/SaveVersionModal'
|
||||
template = require 'templates/editor/thang/thang-type-edit-view'
|
||||
storage = require 'lib/storage'
|
||||
|
@ -33,6 +34,7 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
events:
|
||||
'click #clear-button': 'clearRawData'
|
||||
'click #upload-button': -> @$el.find('input#real-upload-button').click()
|
||||
'click #set-vector-icon': 'onClickSetVectorIcon'
|
||||
'change #real-upload-button': 'animationFileChosen'
|
||||
'change #animations-select': 'showAnimation'
|
||||
'click #marker-button': 'toggleDots'
|
||||
|
@ -47,6 +49,12 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
'keyup .play-with-level-input': 'onPlayLevelKeyUp'
|
||||
'click #pop-level-i18n-button': 'onPopulateLevelI18N'
|
||||
|
||||
|
||||
onClickSetVectorIcon: ->
|
||||
modal = new VectorIconSetupModal({}, @thangType)
|
||||
@openModalView modal
|
||||
modal.once 'done', => @treema.set('/', @getThangData())
|
||||
|
||||
subscriptions:
|
||||
'editor:thang-type-color-groups-changed': 'onColorGroupsChanged'
|
||||
'editor:save-new-version': 'saveNewThangType'
|
||||
|
@ -234,7 +242,7 @@ module.exports = class ThangTypeEditView extends RootView
|
|||
# animation select
|
||||
|
||||
refreshAnimation: =>
|
||||
@thangType.buildActions()
|
||||
@thangType.resetSpriteSheetCache()
|
||||
return @showRasterImage() if @thangType.get('raster')
|
||||
options = @getLankOptions()
|
||||
console.log 'refresh animation....'
|
||||
|
|
115
app/views/editor/thang/VectorIconSetupModal.coffee
Normal file
115
app/views/editor/thang/VectorIconSetupModal.coffee
Normal file
|
@ -0,0 +1,115 @@
|
|||
ModalView = require 'views/kinds/ModalView'
|
||||
template = require 'templates/editor/thang/vector-icon-setup-modal'
|
||||
|
||||
module.exports = class VectorIconSetupModal extends ModalView
|
||||
id: "vector-icon-setup-modal"
|
||||
template: template
|
||||
demoSize: 400
|
||||
plain: true
|
||||
|
||||
events:
|
||||
'change #container-select': 'onChangeContainer'
|
||||
'click #center': 'onClickCenter'
|
||||
'click #zero-bounds': 'onClickZeroBounds'
|
||||
'click #done-button': 'onClickDone'
|
||||
|
||||
shortcuts:
|
||||
'shift+-': -> @incrScale(-0.02)
|
||||
'shift+=': -> @incrScale(0.02)
|
||||
'up': -> @incrRegY(1)
|
||||
'down': -> @incrRegY(-1)
|
||||
'left': -> @incrRegX(1)
|
||||
'right': -> @incrRegX(-1)
|
||||
|
||||
constructor: (options, @thangType) ->
|
||||
portrait = @thangType.get('actions')?.portrait
|
||||
@containers = _.keys(@thangType.get('raw')?.containers or {})
|
||||
@container = portrait?.container or _.last @containers
|
||||
@scale = portrait?.scale or 1
|
||||
@regX = portrait?.positions?.registration?.x or 0
|
||||
@regY = portrait?.positions?.registration?.y or 0
|
||||
@saveChanges()
|
||||
super(options)
|
||||
|
||||
saveChanges: ->
|
||||
actions = _.cloneDeep (@thangType.get('actions') ? {})
|
||||
actions.portrait ?= {}
|
||||
actions.portrait.scale = @scale
|
||||
actions.portrait.positions ?= {}
|
||||
actions.portrait.positions.registration = { x: @regX, y: @regY }
|
||||
actions.portrait.container = @container
|
||||
@thangType.set('actions', actions)
|
||||
@thangType.buildActions()
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.containers = @containers
|
||||
c.chosenContainer = @container
|
||||
c.demoSize = @demoSize
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
@initStage()
|
||||
super()
|
||||
|
||||
initStage: ->
|
||||
return unless @containers and @container
|
||||
@stage = @thangType.getVectorPortraitStage(@demoSize)
|
||||
@sprite = @stage.children[0]
|
||||
canvas = $(@stage.canvas)
|
||||
canvas.attr('id', 'resulting-icon')
|
||||
@$el.find('#resulting-icon').replaceWith(canvas)
|
||||
@updateSpriteProperties()
|
||||
|
||||
onChangeContainer: (e) ->
|
||||
@container = $(e.target).val()
|
||||
@saveChanges()
|
||||
@initStage()
|
||||
|
||||
refreshSprite: ->
|
||||
return unless @stage
|
||||
stage = @thangType.getVectorPortraitStage(@demoSize)
|
||||
@stage.removeAllChildren()
|
||||
@stage.addChild(@sprite = stage.children[0])
|
||||
@updateSpriteProperties()
|
||||
@stage.update()
|
||||
|
||||
updateSpriteProperties: ->
|
||||
@sprite.scaleX = @sprite.scaleY = @scale * @demoSize / 100
|
||||
@sprite.regX = @regX
|
||||
@sprite.regY = @regY
|
||||
console.log 'set to', @scale, @regX, @regY
|
||||
|
||||
onClickCenter: ->
|
||||
containerInfo = @thangType.get('raw').containers[@container]
|
||||
b = containerInfo.b
|
||||
@regX = b[0]
|
||||
@regY = b[1]
|
||||
maxDimension = Math.max(b[2], b[3])
|
||||
@scale = 100 / maxDimension
|
||||
if b[2] > b[3]
|
||||
@regY += (b[3] - b[2]) / 2
|
||||
else
|
||||
@regX += (b[2] - b[3]) / 2
|
||||
@updateSpriteProperties()
|
||||
@stage.update()
|
||||
|
||||
incrScale: (amount) ->
|
||||
@scale += amount
|
||||
@updateSpriteProperties()
|
||||
@stage.update()
|
||||
|
||||
incrRegX: (amount) ->
|
||||
@regX += amount
|
||||
@updateSpriteProperties()
|
||||
@stage.update()
|
||||
|
||||
incrRegY: (amount) ->
|
||||
@regY += amount
|
||||
@updateSpriteProperties()
|
||||
@stage.update()
|
||||
|
||||
onClickDone: ->
|
||||
@saveChanges()
|
||||
@trigger 'done'
|
||||
@hide()
|
Loading…
Reference in a new issue