Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f85bde5dee | |||
| 05e7472051 | |||
| 006691db7e | |||
| a663881368 | |||
| c8cc8576b0 | |||
| 31df7e77ba | |||
| 67d4862f6b | |||
| 6a16327c30 | |||
| 060b1b8f41 | |||
| da2e228293 | |||
| f9473f558a | |||
| 88078bad4c | |||
| 1a3d6ec800 | |||
| 9b5fc2cd74 | |||
| c26398a13f | |||
| fdb874b616 | |||
| dfd06544ec | |||
| 69c10ed1e7 | |||
| 00df9800ed | |||
| 6494fd6b41 | |||
| e9cb673f3a | |||
| 4e5cb64710 | |||
| aaa6ff9938 | |||
| 099cb6b13b | |||
| 75c4065d27 | |||
| f3ce5c8993 | |||
| 9760d3f0d5 | |||
| dab851f3d4 | |||
| 81b3d4d6d7 | |||
| 5b09566c49 | |||
| 70dcc23b25 | |||
| 4c90b3fb16 | |||
| 87931df9b6 | |||
| 5d03229d35 | |||
| fb31d662cc | |||
| 489ec8701f | |||
| e1afe66c7e | |||
| b920d822ef | |||
| 0908763d33 | |||
| 847ad87b23 | |||
| 90cf165dcf | |||
| 8b0307bc72 | |||
| a645e2829a | |||
| 33d8644dd6 | |||
| de713a848c | |||
| e9aa91fe7f | |||
| 9661c79bd6 | |||
| 91fab4dcd4 | |||
| 29488a2d87 | |||
| a3f1dd2459 | |||
| ab12145e4d | |||
| 442ea7e6ab | |||
| 04f0024734 | |||
| 831cc60ab2 | |||
| 7fc4c55362 | |||
| 78e8202d1c | |||
| f35e953531 | |||
| f5796bdec8 | |||
| 9f87c22424 | |||
| 88ba11a836 | |||
| 53f370d24e | |||
| 9e0998f054 | |||
| 0dce0cb88c | |||
| a61097bdcd | |||
| ec073bd544 | |||
| 1c23da6fb2 | |||
| 7e6b993b06 | |||
| 792251dfb9 | |||
| 1c4ebb5380 | |||
| 4ac76d23ca |
+1
-1
Submodule _sqlite3 updated: 800dd5e366...3cce3fb807
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
@@ -7,6 +7,7 @@ require_relative '../constants/path_constants'
|
|||||||
module SpeckleConnector
|
module SpeckleConnector
|
||||||
# Accounts to communicate with models on user's account.
|
# Accounts to communicate with models on user's account.
|
||||||
module Accounts
|
module Accounts
|
||||||
|
# Load accounts from user's app data.
|
||||||
def self.load_accounts
|
def self.load_accounts
|
||||||
db_path = SPECKLE_ACCOUNTS_DB_PATH
|
db_path = SPECKLE_ACCOUNTS_DB_PATH
|
||||||
unless File.exist?(db_path)
|
unless File.exist?(db_path)
|
||||||
@@ -23,9 +24,21 @@ module SpeckleConnector
|
|||||||
rows.map { |row| JSON.parse(row[1]) }
|
rows.map { |row| JSON.parse(row[1]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.get_account_by_id(id)
|
||||||
|
accounts = load_accounts
|
||||||
|
accounts.select { |acc| acc['id'] == id }[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Default account on the user computer.
|
||||||
def self.default_account
|
def self.default_account
|
||||||
accounts = load_accounts
|
accounts = load_accounts
|
||||||
accounts.select { |acc| acc['isDefault'] }[0] || accounts[0]
|
accounts.select { |acc| acc['isDefault'] }[0] || accounts[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Try to get local server account for debug/test purposes.
|
||||||
|
def self.try_get_local_server_account
|
||||||
|
accounts = load_accounts
|
||||||
|
accounts.select { |acc| acc['serverInfo']['url'].include?('localhost') }[0] || nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ module SpeckleConnector
|
|||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def update_state(state)
|
def update_state(state)
|
||||||
state = DeactivateDiffing.update_state(state, {})
|
state = DeactivateDiffing.update_state(state, nil, {})
|
||||||
puts "Diffing activated for #{@stream_id}"
|
puts "Diffing activated for #{@stream_id}"
|
||||||
speckle_entities = state.speckle_state.speckle_entities
|
speckle_entities = state.speckle_state.speckle_entities
|
||||||
invalid_speckle_entities = speckle_entities.select do |_id, entity|
|
invalid_speckle_entities = speckle_entities.select do |_id, entity|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../cards/send_card'
|
||||||
|
require_relative '../../cards/receive_card'
|
||||||
|
require_relative '../../filters/send/everything_filter'
|
||||||
|
require_relative '../../filters/send/selection_filter'
|
||||||
|
require_relative '../../filters/send_filters'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to add send card.
|
||||||
|
class AddModel < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, data)
|
||||||
|
if data['typeDiscriminator'] == 'ReceiverModelCard'
|
||||||
|
receive_card = Cards::ReceiveCard.new(data['id'], data['accountId'],
|
||||||
|
data['projectId'], data['projectName'],
|
||||||
|
data['modelId'], data['modelName'],
|
||||||
|
data['referencedObject'])
|
||||||
|
SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||||
|
.save_card_to_model(receive_card, state.sketchup_state.sketchup_model)
|
||||||
|
new_speckle_state = state.speckle_state.with_receive_card(receive_card)
|
||||||
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
|
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
return state.with_add_queue_js_command('addSendCard', js_script)
|
||||||
|
end
|
||||||
|
|
||||||
|
send_filter = Filters::SendFilters.get_filter_from_ui_data(data['sendFilter'])
|
||||||
|
# Init card and add to the state
|
||||||
|
send_card = Cards::SendCard.new(data['id'], data['accountId'], data['projectId'], data['modelId'],
|
||||||
|
send_filter, {})
|
||||||
|
|
||||||
|
SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||||
|
.save_card_to_model(send_card, state.sketchup_state.sketchup_model)
|
||||||
|
|
||||||
|
new_speckle_state = state.speckle_state.with_send_card(send_card)
|
||||||
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
|
# Resolve promise
|
||||||
|
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('addSendCard', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../cards/send_card'
|
||||||
|
require_relative '../../filters/send_filters'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Add model to document state.
|
||||||
|
class AddModelToDocumentState < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, model)
|
||||||
|
puts model.to_json
|
||||||
|
|
||||||
|
send_filter = Filters::SendFilters.get_filter_from_ui_data(model['sendFilter'])
|
||||||
|
|
||||||
|
send_card = Cards::SendCard.new(model['id'], model['accountId'], model['projectId'], model['modelId'], send_filter, {})
|
||||||
|
SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||||
|
.save_card_to_model(send_card, state.sketchup_state.sketchup_model)
|
||||||
|
new_speckle_state = state.speckle_state.with_send_card(send_card)
|
||||||
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
|
|
||||||
|
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('addModelToDocumentState', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../filters/send_filters'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Gets document state.
|
||||||
|
class GetDocumentState < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
send_cards_hash = SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||||
|
.get_cards_from_dict(state.sketchup_state.sketchup_model)
|
||||||
|
|
||||||
|
send_cards = send_cards_hash.collect do |id, card|
|
||||||
|
filter = Filters::SendFilters.get_filter_from_document(card['sendFilter'])
|
||||||
|
send_card = Cards::SendCard.new(id, card['account_id'], card['project_id'], card['model_id'], filter, {})
|
||||||
|
|
||||||
|
new_speckle_state = state.speckle_state.with_send_card(send_card)
|
||||||
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
|
{
|
||||||
|
id: send_card.id,
|
||||||
|
accountId: send_card.account_id,
|
||||||
|
projectId: send_card.project_id,
|
||||||
|
modelId: send_card.model_id,
|
||||||
|
sendFilter: send_card.send_filter,
|
||||||
|
typeDiscriminator: send_card.type_discriminator
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
model_state = { models: send_cards }
|
||||||
|
|
||||||
|
js_script = "baseBinding.receiveResponse('#{resolve_id}', #{model_state.to_json})"
|
||||||
|
state.with_add_queue_js_command('getDocumentState', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../filters/send_filters'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Gets model state.
|
||||||
|
class GetModelState < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
send_cards_hash = SketchupModel::Dictionary::ModelCardDictionaryHandler
|
||||||
|
.get_cards_from_dict(state.sketchup_state.sketchup_model)
|
||||||
|
|
||||||
|
send_cards = send_cards_hash.collect do |id, card|
|
||||||
|
filters = Filters::SendFilters.get_filters_from_model(card['filters'])
|
||||||
|
send_card = Cards::SendCard.new(id, card['account_id'], card['project_id'], card['model_id'], filters)
|
||||||
|
|
||||||
|
new_speckle_state = state.speckle_state.with_send_card(send_card)
|
||||||
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
|
{
|
||||||
|
accountId: send_card.account_id,
|
||||||
|
projectId: send_card.project_id,
|
||||||
|
modelId: send_card.model_id,
|
||||||
|
filters: send_card.filters
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
model_state = { sendCards: send_cards }
|
||||||
|
|
||||||
|
js_script = "baseBinding.receiveResponse('#{resolve_id}', #{model_state.to_json})"
|
||||||
|
state.with_add_queue_js_command('getModelState', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../filters/send_filters'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to get send filter.
|
||||||
|
class GetSendFilters < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
default_filters = Filters::SendFilters.get_default(state.sketchup_state.sketchup_model)
|
||||||
|
js_script = "sendBinding.receiveResponse('#{resolve_id}', #{default_filters.to_json})"
|
||||||
|
state.with_add_queue_js_command('getSendFilter', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Get source app name.
|
||||||
|
class GetSourceAppName < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
js_command = "baseBinding.receiveResponse('#{resolve_id}', 'Sketchup')"
|
||||||
|
state.with_add_queue_js_command('getSourceAppName', js_command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Get source app version.
|
||||||
|
class GetSourceAppVersion < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
js_command = "baseBinding.receiveResponse('#{resolve_id}', #{SKETCHUP_VERSION})"
|
||||||
|
state.with_add_queue_js_command('getSourceAppVersion', js_command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../sketchup_model/query/entity'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to add send card.
|
||||||
|
class HighlightModel < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, model_card_id)
|
||||||
|
# objects_to_highlight = if data['typeDiscriminator'] == 'ReceiverModelCard'
|
||||||
|
# # model_card = state.speckle_state.receive_cards[model_card_id]
|
||||||
|
# # TODO: return received objects
|
||||||
|
# []
|
||||||
|
# else
|
||||||
|
# model_card = state.speckle_state.send_cards[model_card_id]
|
||||||
|
# model_card.send_filter.selected_object_ids
|
||||||
|
# end
|
||||||
|
objects_to_highlight = state.speckle_state.send_cards[model_card_id].send_filter.selected_object_ids
|
||||||
|
|
||||||
|
state.sketchup_state.sketchup_model.selection.clear
|
||||||
|
|
||||||
|
# Flat entities to select entities on card
|
||||||
|
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
|
||||||
|
|
||||||
|
flat_entities.each do |entity|
|
||||||
|
next unless objects_to_highlight.include?(entity.persistent_id)
|
||||||
|
|
||||||
|
if entity.is_a?(Sketchup::ComponentDefinition)
|
||||||
|
state.sketchup_state.sketchup_model.selection.add(entity.instances)
|
||||||
|
end
|
||||||
|
state.sketchup_state.sketchup_model.selection.add(entity)
|
||||||
|
end
|
||||||
|
|
||||||
|
state.sketchup_state.sketchup_model.active_view.zoom(state.sketchup_state.sketchup_model.selection)
|
||||||
|
|
||||||
|
# Resolve promise
|
||||||
|
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('highlightModel', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../cards/send_card'
|
||||||
|
require_relative '../../cards/receive_card'
|
||||||
|
require_relative '../../filters/send/everything_filter'
|
||||||
|
require_relative '../../filters/send/selection_filter'
|
||||||
|
require_relative '../../filters/send_filters'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to remove send card.
|
||||||
|
class RemoveModel < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, data)
|
||||||
|
SketchupModel::Dictionary::ModelCardDictionaryHandler.remove_card_dict(state.sketchup_state.sketchup_model, data)
|
||||||
|
new_speckle_state = if data['typeDiscriminator'] == 'ReceiverModelCard'
|
||||||
|
state.speckle_state.without_receive_card(data['id'])
|
||||||
|
else
|
||||||
|
state.speckle_state.without_send_card(data['id'])
|
||||||
|
end
|
||||||
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
|
# Resolve promise
|
||||||
|
js_script = "baseBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('removeModel', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to update send filter.
|
||||||
|
class UpdateSendFilter < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, data, value)
|
||||||
|
SketchupModel::Dictionary::ModelCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value)
|
||||||
|
|
||||||
|
js_script = "sendBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('updateSendFilter', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -9,7 +9,7 @@ module SpeckleConnector
|
|||||||
class ClearMapperSource < Action
|
class ClearMapperSource < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data)
|
def self.update_state(state, _resolve_id, _data)
|
||||||
new_speckle_state = state.speckle_state.with_removed_mapper_source
|
new_speckle_state = state.speckle_state.with_removed_mapper_source
|
||||||
erase_levels(state)
|
erase_levels(state)
|
||||||
state.with_speckle_state(new_speckle_state)
|
state.with_speckle_state(new_speckle_state)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module SpeckleConnector
|
|||||||
class ClearMappingsFromTable < Action
|
class ClearMappingsFromTable < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, data)
|
def self.update_state(state, _resolve_id, data)
|
||||||
# Flat entities to clear mappings
|
# Flat entities to clear mappings
|
||||||
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
|
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module SpeckleConnector
|
|||||||
class CollectPreferences < Action
|
class CollectPreferences < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data)
|
def self.update_state(state, _resolve_id, _data)
|
||||||
state.with_add_queue('collectPreferences', state.user_state.preferences.to_json, [])
|
state.with_add_queue('collectPreferences', state.user_state.preferences.to_json, [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module SpeckleConnector
|
|||||||
class CollectVersions < Action
|
class CollectVersions < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data)
|
def self.update_state(state, _resolve_id, _data)
|
||||||
versions = {
|
versions = {
|
||||||
sketchup: Sketchup.version.to_i,
|
sketchup: Sketchup.version.to_i,
|
||||||
speckle: SpeckleConnector::CONNECTOR_VERSION
|
speckle: SpeckleConnector::CONNECTOR_VERSION
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to get config.
|
||||||
|
class GetConfig < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
# Previously it was stored in user state
|
||||||
|
# config = state.user_state.preferences.to_json
|
||||||
|
config = {
|
||||||
|
darkTheme: state.user_state.user_preferences[:dark_theme]
|
||||||
|
}
|
||||||
|
js_script = "configBinding.receiveResponse('#{resolve_id}', #{config.to_json})"
|
||||||
|
state.with_add_queue_js_command('getConfig', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../user_preferences_updated'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to update config.
|
||||||
|
class UpdateConfig < Action
|
||||||
|
KEY_VALUES = {
|
||||||
|
'darkTheme' => 'dark_theme'
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, config)
|
||||||
|
config.each do |key, value|
|
||||||
|
state = Actions::UserPreferencesUpdated.new('configSketchup', KEY_VALUES[key], value).update_state(state)
|
||||||
|
end
|
||||||
|
|
||||||
|
js_script = "configBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('updateConfig', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -8,7 +8,7 @@ module SpeckleConnector
|
|||||||
class DeactivateDiffing < Action
|
class DeactivateDiffing < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data)
|
def self.update_state(state, _resolve_id, _data)
|
||||||
puts 'Diffing deactivated!'
|
puts 'Diffing deactivated!'
|
||||||
speckle_entities = state.speckle_state.speckle_entities
|
speckle_entities = state.speckle_state.speckle_entities
|
||||||
diffing_activated_speckle_entities = speckle_entities.reject do |_id, entity|
|
diffing_activated_speckle_entities = speckle_entities.reject do |_id, entity|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative 'event_action'
|
require_relative 'event_action'
|
||||||
|
require_relative 'on_document_changed'
|
||||||
require_relative '../load_sketchup_model'
|
require_relative '../load_sketchup_model'
|
||||||
require_relative '../collect_preferences'
|
require_relative '../collect_preferences'
|
||||||
|
|
||||||
@@ -25,7 +26,8 @@ module SpeckleConnector
|
|||||||
# Action to let UI to render itself with new preferences state
|
# Action to let UI to render itself with new preferences state
|
||||||
# TODO: Later UI should be updated if any stream is invalid after
|
# TODO: Later UI should be updated if any stream is invalid after
|
||||||
# we collected speckle_entities appropriately
|
# we collected speckle_entities appropriately
|
||||||
CollectPreferences.update_state(new_state, {})
|
new_state = CollectPreferences.update_state(new_state, nil, {})
|
||||||
|
OnDocumentChanged.update_state(new_state)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative 'event_action'
|
require_relative 'event_action'
|
||||||
|
require_relative '../../actions/send_actions/send_card_expiration_check'
|
||||||
require_relative '../../sketchup_model/utils/face_utils'
|
require_relative '../../sketchup_model/utils/face_utils'
|
||||||
require_relative '../../constants/dict_constants'
|
require_relative '../../constants/dict_constants'
|
||||||
|
|
||||||
@@ -26,19 +27,23 @@ module SpeckleConnector
|
|||||||
def self.update_state(state, event_data)
|
def self.update_state(state, event_data)
|
||||||
speckle_state = state.speckle_state
|
speckle_state = state.speckle_state
|
||||||
modified_entity = event_data[0][1]
|
modified_entity = event_data[0][1]
|
||||||
if modified_entity.is_a?(Sketchup::Face)
|
modified_entities = event_data.collect { |data| data[1] }
|
||||||
path = state.sketchup_state.sketchup_model.active_path
|
new_speckle_state = state.speckle_state.with_changed_object_ids(modified_entities.collect(&:persistent_id))
|
||||||
modified_faces = SketchupModel::Utils::FaceUtils.near_faces(modified_entity.edges)
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
path_objects = path.nil? ? [] : path + path.collect(&:definition)
|
state = Actions::SendCardExpirationCheck.update_state(state)
|
||||||
parent_ids = path_objects.collect(&:persistent_id)
|
# if modified_entity.is_a?(Sketchup::Face)
|
||||||
ids_to_invalidate = modified_faces.collect(&:persistent_id) + parent_ids
|
# path = state.sketchup_state.sketchup_model.active_path
|
||||||
entities_to_invalidate = speckle_entities_to_invalidate(speckle_state, ids_to_invalidate)
|
# modified_faces = SketchupModel::Utils::FaceUtils.near_faces(modified_entity.edges)
|
||||||
new_speckle_state = invalidate_speckle_entities(speckle_state, entities_to_invalidate)
|
# path_objects = path.nil? ? [] : path + path.collect(&:definition)
|
||||||
# This is the place we can send information to UI for diffing check
|
# parent_ids = path_objects.collect(&:persistent_id)
|
||||||
diffing = state.user_state.preferences[:user][:diffing]
|
# ids_to_invalidate = modified_faces.collect(&:persistent_id) + parent_ids
|
||||||
new_speckle_state = new_speckle_state.with_invalid_streams_queue if diffing
|
# entities_to_invalidate = speckle_entities_to_invalidate(speckle_state, ids_to_invalidate)
|
||||||
return state.with_speckle_state(new_speckle_state)
|
# new_speckle_state = invalidate_speckle_entities(speckle_state, entities_to_invalidate)
|
||||||
end
|
# # This is the place we can send information to UI for diffing check
|
||||||
|
# diffing = state.user_state.preferences[:user][:diffing]
|
||||||
|
# new_speckle_state = new_speckle_state.with_invalid_streams_queue if diffing
|
||||||
|
# return state.with_speckle_state(new_speckle_state)
|
||||||
|
# end
|
||||||
|
|
||||||
state
|
state
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Triggers whenever document has changed.
|
||||||
|
class OnDocumentChanged < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state)
|
||||||
|
js_command = "baseBinding.emit('documentChanged')"
|
||||||
|
state.with_add_queue_js_command('documentChanged', js_command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
require_relative 'event_action'
|
require_relative 'event_action'
|
||||||
require_relative '../mapper_selection_changed'
|
require_relative '../mapper_selection_changed'
|
||||||
|
require_relative '../selection_actions/get_selection'
|
||||||
require_relative '../../mapper/category/revit_category'
|
require_relative '../../mapper/category/revit_category'
|
||||||
require_relative '../../sketchup_model/reader/speckle_entities_reader'
|
require_relative '../../sketchup_model/reader/speckle_entities_reader'
|
||||||
require_relative '../../sketchup_model/reader/mapper_reader'
|
require_relative '../../sketchup_model/reader/mapper_reader'
|
||||||
@@ -20,9 +21,11 @@ module SpeckleConnector
|
|||||||
# Get sketchup selection
|
# Get sketchup selection
|
||||||
sketchup_selection = state.sketchup_state.sketchup_model.selection
|
sketchup_selection = state.sketchup_state.sketchup_model.selection
|
||||||
|
|
||||||
|
Actions::GetSelection.update_state(state)
|
||||||
|
|
||||||
# Collect and return mapper selection info.
|
# Collect and return mapper selection info.
|
||||||
# Later we can add more selection info for different scopes.
|
# Later we can add more selection info for different scopes.
|
||||||
MapperSelectionChanged.new(sketchup_selection).update_state(state)
|
# MapperSelectionChanged.new(sketchup_selection).update_state(state)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'action'
|
||||||
|
require_relative '../accounts/accounts'
|
||||||
|
require_relative 'load_saved_streams'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to initialize local accounts from database.
|
||||||
|
class GetAccounts < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
puts 'Initialisation of Speckle accounts requested by plugin'
|
||||||
|
accounts_data = state.speckle_state.accounts
|
||||||
|
js_script = "accountsBinding.receiveResponse('#{resolve_id}', #{accounts_data.to_json})"
|
||||||
|
state.with_add_queue_js_command('getAccounts', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Get document info.
|
||||||
|
class GetDocumentInfo < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
document_info = {
|
||||||
|
location: state.sketchup_state.sketchup_model.path,
|
||||||
|
name: state.sketchup_state.sketchup_model.name,
|
||||||
|
id: state.sketchup_state.sketchup_model.guid
|
||||||
|
}
|
||||||
|
js_command = "baseBinding.receiveResponse('#{resolve_id}', #{document_info.to_json})"
|
||||||
|
state.with_add_queue_js_command('getDocumentInfo', js_command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to return error message to UI.
|
||||||
|
class HandleError < Action
|
||||||
|
# @param error [String] error
|
||||||
|
# @param view_name [String] name of the view (binding)
|
||||||
|
# @param action [Action] action that error happened
|
||||||
|
# @param parameters [Array<String>] arguments
|
||||||
|
def initialize(error, view_name, action, parameters)
|
||||||
|
super()
|
||||||
|
@error = error
|
||||||
|
@view_name = view_name
|
||||||
|
@action = action
|
||||||
|
@args = parameters
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def update_state(state)
|
||||||
|
error_message = "Error: #{@error}\nBinding: #{@view_name}\nAction:#{@action}\nArgs: #{@args}\n"
|
||||||
|
error = {
|
||||||
|
error: error_message
|
||||||
|
}
|
||||||
|
js_error_script = "#{@view_name}.receiveResponse('#{@args.first}', #{error.to_json})"
|
||||||
|
state.with_add_queue_js_command("error_#{@view_name}", js_error_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -10,7 +10,7 @@ module SpeckleConnector
|
|||||||
class HideMappingsFromTable < Action
|
class HideMappingsFromTable < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, data)
|
def self.update_state(state, _resolve_id, data)
|
||||||
# Flat entities to clear mappings
|
# Flat entities to clear mappings
|
||||||
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
|
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module SpeckleConnector
|
|||||||
class InitLocalAccounts < Action
|
class InitLocalAccounts < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data)
|
def self.update_state(state, _request_id, _data)
|
||||||
puts 'Initialisation of Speckle accounts requested by plugin'
|
puts 'Initialisation of Speckle accounts requested by plugin'
|
||||||
accounts_data = state.speckle_state.accounts
|
accounts_data = state.speckle_state.accounts
|
||||||
state.with_add_queue('loadAccounts', accounts_data.to_json, [])
|
state.with_add_queue('loadAccounts', accounts_data.to_json, [])
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ require_relative '../states/sketchup_state'
|
|||||||
require_relative '../accounts/accounts'
|
require_relative '../accounts/accounts'
|
||||||
require_relative '../preferences/preferences'
|
require_relative '../preferences/preferences'
|
||||||
require_relative '../constants/observer_constants'
|
require_relative '../constants/observer_constants'
|
||||||
|
require_relative '../ext/worker'
|
||||||
|
|
||||||
module SpeckleConnector
|
module SpeckleConnector
|
||||||
module Actions
|
module Actions
|
||||||
@@ -14,7 +15,8 @@ module SpeckleConnector
|
|||||||
class InitializeSpeckle < Action
|
class InitializeSpeckle < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, observers)
|
def self.update_state(state, observers, instant_message_sender)
|
||||||
|
worker = SpeckleConnector::Worker.new()
|
||||||
attach_app_observer!(observers[APP_OBSERVER])
|
attach_app_observer!(observers[APP_OBSERVER])
|
||||||
accounts = SpeckleConnector::Accounts.load_accounts
|
accounts = SpeckleConnector::Accounts.load_accounts
|
||||||
speckle_state = States::SpeckleState.new(accounts, observers, {}, {})
|
speckle_state = States::SpeckleState.new(accounts, observers, {}, {})
|
||||||
@@ -22,7 +24,8 @@ module SpeckleConnector
|
|||||||
sketchup_state = States::SketchupState.new(Sketchup.active_model)
|
sketchup_state = States::SketchupState.new(Sketchup.active_model)
|
||||||
preferences = Preferences.read_preferences(sketchup_state.sketchup_model)
|
preferences = Preferences.read_preferences(sketchup_state.sketchup_model)
|
||||||
user_state_with_preferences = state.user_state.with_preferences(preferences)
|
user_state_with_preferences = state.user_state.with_preferences(preferences)
|
||||||
state = States::State.new(user_state_with_preferences, speckle_state, sketchup_state, false)
|
state = States::State.new(user_state_with_preferences, speckle_state, sketchup_state, false,
|
||||||
|
worker, &instant_message_sender)
|
||||||
# This is where we attach observers to related model objects like selection, entities..
|
# This is where we attach observers to related model objects like selection, entities..
|
||||||
Actions::LoadSketchupModel.update_state(state, sketchup_state.sketchup_model)
|
Actions::LoadSketchupModel.update_state(state, sketchup_state.sketchup_model)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ module SpeckleConnector
|
|||||||
# rubocop:disable Metrics/MethodLength
|
# rubocop:disable Metrics/MethodLength
|
||||||
# rubocop:disable Metrics/PerceivedComplexity
|
# rubocop:disable Metrics/PerceivedComplexity
|
||||||
# rubocop:disable Metrics/CyclomaticComplexity
|
# rubocop:disable Metrics/CyclomaticComplexity
|
||||||
def self.update_state(state, data)
|
def self.update_state(state, _resolve_id, data)
|
||||||
sketchup_model = state.sketchup_state.sketchup_model
|
sketchup_model = state.sketchup_state.sketchup_model
|
||||||
|
|
||||||
# Hide all entities first
|
# Hide all entities first
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module SpeckleConnector
|
|||||||
class LoadSavedStreams < Action
|
class LoadSavedStreams < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data)
|
def self.update_state(state, _request_id, _data)
|
||||||
(saved_streams = state.sketchup_state.sketchup_model
|
(saved_streams = state.sketchup_state.sketchup_model
|
||||||
.attribute_dictionary('Speckle', true)['saved_streams']) or []
|
.attribute_dictionary('Speckle', true)['saved_streams']) or []
|
||||||
state.with_add_queue('setSavedStreams', saved_streams, [])
|
state.with_add_queue('setSavedStreams', saved_streams, [])
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module SpeckleConnector
|
|||||||
class MappedEntitiesUpdated < Action
|
class MappedEntitiesUpdated < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data = nil)
|
def self.update_state(state, _resolve_id = nil, _data = nil)
|
||||||
mapped_entities = SketchupModel::Reader::MapperReader
|
mapped_entities = SketchupModel::Reader::MapperReader
|
||||||
.mapped_entity_details(state.speckle_state.speckle_mapper_state.mapped_entities.values.to_a)
|
.mapped_entity_details(state.speckle_state.speckle_mapper_state.mapped_entities.values.to_a)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to let sketchup know receive from server is finished..
|
||||||
|
class AfterReceive < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, stream_id, root_id)
|
||||||
|
puts "receive finished for: #{root_id}"
|
||||||
|
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('afterReceive', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to let sketchup know receive will be started.
|
||||||
|
class BeforeReceive < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, stream_id, root_id)
|
||||||
|
puts "receive started for: #{root_id}"
|
||||||
|
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('beforeReceive', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../convertors/units'
|
||||||
|
require_relative '../../convertors/to_native'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Clear mappings for selected entities.
|
||||||
|
class ReceiveSingleObject < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, stream_id, root_id, speckle_objects)
|
||||||
|
puts "object receive #{speckle_objects.length}"
|
||||||
|
buffer = speckle_objects.collect { |obj| [obj['id'], obj] }.to_h
|
||||||
|
t_0 = Time.now.to_f
|
||||||
|
root_obj = traverse_and_construct(speckle_objects.first, buffer)
|
||||||
|
puts root_obj
|
||||||
|
puts "Elapsed traverse and construct #{Time.now.to_f - t_0}"
|
||||||
|
|
||||||
|
# File.open("#{ENV['HOME']}/OneDrive/Masaüstü/root.json", 'w') do |f|
|
||||||
|
# f.write(JSON.pretty_generate(root_obj))
|
||||||
|
# end
|
||||||
|
|
||||||
|
# converter = Converters::ToNative.new(state, stream_id, 'test', 'testt', 'test')
|
||||||
|
# state = converter.receive_commit_object(root_obj)
|
||||||
|
|
||||||
|
js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('receiveObject', js_script)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.traverse_and_construct(obj, buffer)
|
||||||
|
return if obj.nil?
|
||||||
|
return obj if !obj.is_a?(Hash) && !obj.is_a?(Array)
|
||||||
|
|
||||||
|
# Handle arrays
|
||||||
|
if obj.is_a?(Array) && !obj.empty?
|
||||||
|
arr = handle_array(buffer, obj)
|
||||||
|
|
||||||
|
# De-chunk, if array is a set of datachunk, flat them into single data chunk.
|
||||||
|
arr = try_dechunk(arr)
|
||||||
|
|
||||||
|
return arr
|
||||||
|
end
|
||||||
|
|
||||||
|
# Handle object
|
||||||
|
obj = handle_hash(buffer, obj)
|
||||||
|
|
||||||
|
return obj
|
||||||
|
rescue StandardError => e
|
||||||
|
puts "#{e} -> #{obj}"
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.handle_array(buffer, obj)
|
||||||
|
arr = []
|
||||||
|
obj.collect do |element|
|
||||||
|
next if element.nil?
|
||||||
|
|
||||||
|
deref = element.is_a?(Hash) && !element['referencedId'].nil? ? buffer[element['referencedId']] : element
|
||||||
|
arr.append(traverse_and_construct(deref, buffer))
|
||||||
|
end
|
||||||
|
arr
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.try_dechunk(arr)
|
||||||
|
if arr[0].is_a?(Hash) && !arr[0]['speckle_type'].nil? && arr[0]['speckle_type'].downcase.include?('datachunk')
|
||||||
|
sum_arr = []
|
||||||
|
arr.each do |chunk|
|
||||||
|
sum_arr += chunk['data']
|
||||||
|
end
|
||||||
|
sum_arr
|
||||||
|
else
|
||||||
|
arr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.handle_hash(buffer, obj)
|
||||||
|
obj.each do |prop, value|
|
||||||
|
next if value.nil? || (!value.is_a?(Hash) && !value.is_a?(Array))
|
||||||
|
|
||||||
|
obj[prop] = buffer[value['referencedId']] if value.is_a?(Hash) && value['referencedId']
|
||||||
|
obj[prop] = traverse_and_construct(obj[prop], buffer)
|
||||||
|
end
|
||||||
|
obj
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../convertors/to_native'
|
||||||
|
require_relative '../../ext/TT_Lib2/progressbar'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Receive from server.
|
||||||
|
class AfterGetObjects < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, model_card_id, source_application, root_obj)
|
||||||
|
model_card = state.speckle_state.receive_cards[model_card_id]
|
||||||
|
converter = Converters::ToNative.new(state, model_card.model_id, model_card.project_name,
|
||||||
|
model_card.model_name, source_application)
|
||||||
|
# Have side effects on the sketchup model. It effects directly on the entities by adding new objects.
|
||||||
|
state = converter.receive_commit_object(root_obj)
|
||||||
|
|
||||||
|
|
||||||
|
resolve_js_script = "receiveBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('receive', resolve_js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../accounts/accounts'
|
||||||
|
require_relative '../../convertors/units'
|
||||||
|
require_relative '../../convertors/to_speckle'
|
||||||
|
require_relative '../../operations/send'
|
||||||
|
require_relative '../../ext/TT_Lib2/progressbar'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Receive from server.
|
||||||
|
class Receive < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, model_card_id, source_application)
|
||||||
|
model_card = state.speckle_state.receive_cards[model_card_id]
|
||||||
|
account = Accounts.get_account_by_id(model_card.account_id)
|
||||||
|
|
||||||
|
resolve_js_script = "receiveBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state = state.with_add_queue_js_command('receive', resolve_js_script)
|
||||||
|
args = {
|
||||||
|
modelCardId: model_card_id,
|
||||||
|
projectId: model_card.project_id,
|
||||||
|
modelId: model_card.model_id,
|
||||||
|
token: account['token'],
|
||||||
|
serverUrl: account['serverInfo']['url'],
|
||||||
|
accountId: model_card.account_id,
|
||||||
|
objectId: model_card.object_id,
|
||||||
|
sourceApplication: source_application
|
||||||
|
}
|
||||||
|
js_script = "receiveBinding.emit('receiveViaBrowser', #{args.to_json})"
|
||||||
|
state.with_add_queue_js_command('receiveViaBrowser', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
require_relative 'action'
|
require_relative 'action'
|
||||||
require_relative '../convertors/units'
|
require_relative '../convertors/units'
|
||||||
require_relative '../convertors/to_native'
|
require_relative '../convertors/to_native'
|
||||||
|
require_relative '../operations/receive'
|
||||||
require_relative '../convertors/clean_up'
|
require_relative '../convertors/clean_up'
|
||||||
|
|
||||||
module SpeckleConnector
|
module SpeckleConnector
|
||||||
@@ -10,7 +11,7 @@ module SpeckleConnector
|
|||||||
# Action to receive objects from Speckle Server.
|
# Action to receive objects from Speckle Server.
|
||||||
class ReceiveObjects < Action
|
class ReceiveObjects < Action
|
||||||
# rubocop:disable Metrics/ParameterLists
|
# rubocop:disable Metrics/ParameterLists
|
||||||
def initialize(stream_id, base, stream_name, branch_name, branch_id, source_app)
|
def initialize(stream_id, base, stream_name, branch_name, branch_id, source_app, object_id)
|
||||||
super()
|
super()
|
||||||
@stream_id = stream_id
|
@stream_id = stream_id
|
||||||
@base = base
|
@base = base
|
||||||
@@ -18,12 +19,15 @@ module SpeckleConnector
|
|||||||
@branch_name = branch_name
|
@branch_name = branch_name
|
||||||
@branch_id = branch_id
|
@branch_id = branch_id
|
||||||
@source_app = source_app
|
@source_app = source_app
|
||||||
|
@object_id = object_id
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/ParameterLists
|
# rubocop:enable Metrics/ParameterLists
|
||||||
|
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def update_state(state)
|
def update_state(state)
|
||||||
|
# content = Operations.receive(@stream_id, @object_id)
|
||||||
|
|
||||||
converter = Converters::ToNative.new(state, @stream_id, @stream_name, @branch_name, @source_app)
|
converter = Converters::ToNative.new(state, @stream_id, @stream_name, @branch_name, @source_app)
|
||||||
# Have side effects on the sketchup model. It effects directly on the entities by adding new objects.
|
# Have side effects on the sketchup model. It effects directly on the entities by adding new objects.
|
||||||
start_time = Time.now.to_f
|
start_time = Time.now.to_f
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module SpeckleConnector
|
|||||||
class ReloadAccounts < Action
|
class ReloadAccounts < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data)
|
def self.update_state(state, _resolve_id, _data)
|
||||||
puts 'Reload of Speckle accounts requested by plugin'
|
puts 'Reload of Speckle accounts requested by plugin'
|
||||||
new_speckle_state = state.speckle_state.with_accounts(Accounts.load_accounts)
|
new_speckle_state = state.speckle_state.with_accounts(Accounts.load_accounts)
|
||||||
state = state.with_speckle_state(new_speckle_state)
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ module SpeckleConnector
|
|||||||
class SelectMappingsFromTable < Action
|
class SelectMappingsFromTable < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, data)
|
def self.update_state(state, _resolve_id, data)
|
||||||
# Clear first selection
|
# Clear first selection
|
||||||
state.sketchup_state.sketchup_model.selection.clear
|
state.sketchup_state.sketchup_model.selection.clear
|
||||||
|
|
||||||
# Flat entities to clear mappings
|
# Flat entities to select mapped elements
|
||||||
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
|
flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities)
|
||||||
|
|
||||||
# Collect entity ids to clear mappings
|
# Collect entity ids to clear mappings
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../ui_data/sketchup/selection_info'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to get selection.
|
||||||
|
class GetSelection < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state)
|
||||||
|
selected_object_ids = state.sketchup_state.sketchup_model.selection.collect(&:persistent_id)
|
||||||
|
summary = "Selected #{selected_object_ids.length} objects."
|
||||||
|
selection_info = UiData::Sketchup::SelectionInfo.new(selected_object_ids, summary)
|
||||||
|
# js_script = "selectionBinding.receiveResponse('#{resolve_id}', #{selection_info.to_json})"
|
||||||
|
js_script = "selectionBinding.emit('setSelection', #{selection_info.to_json})"
|
||||||
|
state.with_add_queue_js_command('setSelection', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to activate send filter.
|
||||||
|
class ActivateSendFilter < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, data, value)
|
||||||
|
SketchupModel::Dictionary::ModelCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value)
|
||||||
|
card_id = "#{data['accountId']}-#{data['projectId']}-#{data['modelId']}"
|
||||||
|
send_card = state.speckle_state.send_cards[card_id]
|
||||||
|
puts "Send card filter updated -> #{card_id} -> #{send_card}"
|
||||||
|
js_script = "sendBindingOld.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('activateSendFilter', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to activate send filter tag.
|
||||||
|
class ActivateSendFilterTag < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, data, value)
|
||||||
|
SketchupModel::Dictionary::ModelCardDictionaryHandler.update_tag_filter(state.sketchup_state.sketchup_model, data, value)
|
||||||
|
card_id = "#{data['accountId']}-#{data['projectId']}-#{data['modelId']}"
|
||||||
|
send_card = state.speckle_state.send_cards[card_id]
|
||||||
|
puts "Send card filter updated -> #{card_id} -> #{send_card}"
|
||||||
|
js_script = "sendBindingOld.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('activateSendFilterTag', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../accounts/accounts'
|
||||||
|
require_relative '../../convertors/units'
|
||||||
|
require_relative '../../convertors/to_speckle'
|
||||||
|
require_relative '../../operations/send'
|
||||||
|
require_relative '../../ext/TT_Lib2/progressbar'
|
||||||
|
require_relative '../../ext/worker'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Send to server.
|
||||||
|
class Send < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, model_card_id)
|
||||||
|
model_card = state.speckle_state.send_cards[model_card_id]
|
||||||
|
account = Accounts.get_account_by_id(model_card.account_id)
|
||||||
|
converter = Converters::ToSpeckle.new(state, model_card_id, model_card.send_filter)
|
||||||
|
|
||||||
|
new_speckle_state, base = converter.convert_selection_to_base(state.user_state.preferences)
|
||||||
|
id, total_children_count, batches, new_speckle_state = converter.serialize(base, new_speckle_state,
|
||||||
|
state.user_state.preferences)
|
||||||
|
|
||||||
|
# update_test(state)
|
||||||
|
|
||||||
|
puts("converted #{base.count} objects for stream #{@stream_id}")
|
||||||
|
|
||||||
|
state = state.with_speckle_state(new_speckle_state)
|
||||||
|
|
||||||
|
resolve_js_script = "sendBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state = state.with_add_queue_js_command('send', resolve_js_script)
|
||||||
|
args = {
|
||||||
|
modelCardId: model_card_id,
|
||||||
|
projectId: model_card.project_id,
|
||||||
|
modelId: model_card.model_id,
|
||||||
|
token: account['token'],
|
||||||
|
serverUrl: account['serverInfo']['url'],
|
||||||
|
accountId: model_card.account_id,
|
||||||
|
message: model_card.message,
|
||||||
|
sendObject: {
|
||||||
|
id: id,
|
||||||
|
totalChildrenCount: total_children_count,
|
||||||
|
batches: batches
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js_script = "sendBinding.emit('sendViaBrowser', #{args.to_json})"
|
||||||
|
state.with_add_queue_js_command('sendViaBrowser', js_script)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.update_test(state)
|
||||||
|
dialog = UI::HtmlDialog.new(
|
||||||
|
{
|
||||||
|
:dialog_title => 'Dialog Example',
|
||||||
|
:preferences_key => 'com.sample.plugin',
|
||||||
|
:scrollable => true,
|
||||||
|
:resizable => true,
|
||||||
|
:width => 600,
|
||||||
|
:height => 400,
|
||||||
|
:left => 10,
|
||||||
|
:top => 10,
|
||||||
|
:min_width => 50,
|
||||||
|
:min_height => 50,
|
||||||
|
:max_width =>1000,
|
||||||
|
:max_height => 1000,
|
||||||
|
:style => UI::HtmlDialog::STYLE_DIALOG
|
||||||
|
})
|
||||||
|
html = '<div id="hi"><b>Hello world!</b></div>'
|
||||||
|
dialog.set_html(html)
|
||||||
|
dialog.show
|
||||||
|
|
||||||
|
action = Proc.new do |status|
|
||||||
|
js_command = "document.getElementById('hi').innerHTML = '<b>#{status}</b>'"
|
||||||
|
log_js_command = "console.log('test')"
|
||||||
|
dialog.execute_script(js_command)
|
||||||
|
dialog.execute_script(log_js_command)
|
||||||
|
end
|
||||||
|
|
||||||
|
selected_object_ids = state.sketchup_state.sketchup_model.selection.collect(&:persistent_id)
|
||||||
|
state.worker.add_jobs(1000.times.to_a.map { |i| Job.new(i, &action) })
|
||||||
|
state.worker.do_work(Time.now.to_f, &action)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to check send card expirations.
|
||||||
|
class SendCardExpirationCheck < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state)
|
||||||
|
return state unless state.speckle_state.changed_entity_ids.any?
|
||||||
|
|
||||||
|
expired_send_cards_ids = state.speckle_state.send_cards.select do |_id, send_card|
|
||||||
|
send_card.send_filter.check_expiry(state.speckle_state.changed_entity_ids)
|
||||||
|
end.keys.to_a
|
||||||
|
js_script = "sendBinding.emit('sendersExpired', #{expired_send_cards_ids.to_json})"
|
||||||
|
state.with_add_queue_js_command('sendersExpired', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -4,6 +4,7 @@ require_relative 'action'
|
|||||||
require_relative 'deactivate_diffing'
|
require_relative 'deactivate_diffing'
|
||||||
require_relative '../convertors/units'
|
require_relative '../convertors/units'
|
||||||
require_relative '../convertors/to_speckle'
|
require_relative '../convertors/to_speckle'
|
||||||
|
require_relative '../operations/send'
|
||||||
|
|
||||||
module SpeckleConnector
|
module SpeckleConnector
|
||||||
module Actions
|
module Actions
|
||||||
@@ -17,11 +18,14 @@ module SpeckleConnector
|
|||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def update_state(state)
|
def update_state(state)
|
||||||
state = DeactivateDiffing.update_state(state, {})
|
state = DeactivateDiffing.update_state(state, nil, {})
|
||||||
converter = Converters::ToSpeckle.new(state, @stream_id)
|
converter = Converters::ToSpeckle.new(state, @stream_id, {})
|
||||||
new_speckle_state, base = converter.convert_selection_to_base(state.user_state.preferences)
|
new_speckle_state, base = converter.convert_selection_to_base(state.user_state.preferences)
|
||||||
id, total_children_count, batches, new_speckle_state = converter.serialize(base, new_speckle_state,
|
id, total_children_count, batches, new_speckle_state = converter.serialize(base, new_speckle_state,
|
||||||
state.user_state.preferences)
|
state.user_state.preferences)
|
||||||
|
# TODO: Later active send operation.
|
||||||
|
# Operations.send(@stream_id, batches)
|
||||||
|
|
||||||
puts("converted #{base.count} objects for stream #{@stream_id}")
|
puts("converted #{base.count} objects for stream #{@stream_id}")
|
||||||
|
|
||||||
# This is the place we can send information to UI for diffing check
|
# This is the place we can send information to UI for diffing check
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module SpeckleConnector
|
|||||||
class ShowAllEntities < Action
|
class ShowAllEntities < Action
|
||||||
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
# @return [States::State] the new updated state object
|
# @return [States::State] the new updated state object
|
||||||
def self.update_state(state, _data)
|
def self.update_state(state, _resolve_id, _data)
|
||||||
# Show all entities first
|
# Show all entities first
|
||||||
state.sketchup_state.sketchup_model.entities.each do |ent|
|
state.sketchup_state.sketchup_model.entities.each do |ent|
|
||||||
ent.hidden = false
|
ent.hidden = false
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to get user config.
|
||||||
|
class GetUserConfig < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
# Previously it was stored in user state
|
||||||
|
# config = state.user_state.preferences.to_json
|
||||||
|
config = [
|
||||||
|
{
|
||||||
|
key: 'darkTheme',
|
||||||
|
title: 'Theme',
|
||||||
|
type: 'toggle',
|
||||||
|
config: {
|
||||||
|
value: state.user_state.user_preferences[:dark_theme]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'diffing',
|
||||||
|
title: 'Diffing',
|
||||||
|
type: 'toggle',
|
||||||
|
config: {
|
||||||
|
value: state.user_state.user_preferences[:diffing]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'referencePoint',
|
||||||
|
title: 'Reference Point',
|
||||||
|
type: 'dropdown',
|
||||||
|
config: {
|
||||||
|
value: 'test',
|
||||||
|
items: ['test', 'test1', 'test2']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
js_script = "connectorConfigBinding.receiveResponse('#{resolve_id}', #{config.to_json})"
|
||||||
|
state.with_add_queue_js_command('getUserConfig', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Action to get user config.
|
||||||
|
class UpdateUserConfig < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, new_config)
|
||||||
|
puts new_config.values
|
||||||
|
js_script = "connectorConfigBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('updateUserConfig', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Test purpose action.
|
||||||
|
class GetComplexType < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
complex_type = {
|
||||||
|
id: 'complex_type_id',
|
||||||
|
count: 3
|
||||||
|
}
|
||||||
|
js_script = "testBinding.receiveResponse('#{resolve_id}', #{complex_type.to_json})"
|
||||||
|
state.with_add_queue_js_command('getComplexType', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Test purpose action.
|
||||||
|
class GoAway < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id)
|
||||||
|
puts 'SketchUp went away :('
|
||||||
|
js_script = "testBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state.with_add_queue_js_command('goAway', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Test purpose action.
|
||||||
|
class SayHi < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, name, count, say_hello_not_hi)
|
||||||
|
said_hi = []
|
||||||
|
count.times do
|
||||||
|
said_hi.append("#{say_hello_not_hi ? 'Hello' : 'Hi'} #{name}!")
|
||||||
|
end
|
||||||
|
js_script = "testBinding.receiveResponse('#{resolve_id}', #{said_hi})"
|
||||||
|
state.with_add_queue_js_command('sayHi', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../action'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Actions
|
||||||
|
# Test purpose action.
|
||||||
|
class TriggerEvent < Action
|
||||||
|
# @param state [States::State] the current state of the {App::SpeckleConnectorApp}
|
||||||
|
# @return [States::State] the new updated state object
|
||||||
|
def self.update_state(state, resolve_id, event_name)
|
||||||
|
if event_name == 'emptyTestEvent'
|
||||||
|
js_script = "testBinding.emit('#{event_name}')"
|
||||||
|
else
|
||||||
|
args = {
|
||||||
|
name: 'Oguzhan',
|
||||||
|
isOk: true,
|
||||||
|
count: 3
|
||||||
|
}
|
||||||
|
js_script = "testBinding.emit('#{event_name}', #{args.to_json})"
|
||||||
|
end
|
||||||
|
resolve_js_script = "testBinding.receiveResponse('#{resolve_id}')"
|
||||||
|
state = state.with_add_queue_js_command('triggerEventResolve', resolve_js_script)
|
||||||
|
state.with_add_queue_js_command('triggerEvent', js_script)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -28,10 +28,6 @@ module SpeckleConnector
|
|||||||
state.speckle_state?
|
state.speckle_state?
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_ui!
|
|
||||||
ui_controller.update_ui(state)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Attach observers to application when speckle initialized via menu commands.
|
# Attach observers to application when speckle initialized via menu commands.
|
||||||
def add_observer_handler!(observer_handler)
|
def add_observer_handler!(observer_handler)
|
||||||
@observer_handler = observer_handler
|
@observer_handler = observer_handler
|
||||||
@@ -40,17 +36,24 @@ module SpeckleConnector
|
|||||||
# Send messages to HtmlDialog if any.
|
# Send messages to HtmlDialog if any.
|
||||||
def send_messages!
|
def send_messages!
|
||||||
queue = @state.speckle_state.message_queue
|
queue = @state.speckle_state.message_queue
|
||||||
queue.each_value { |value| ui_controller.user_interfaces[Ui::SPECKLE_UI_ID].dialog.execute_script(value) }
|
queue.each_value do |value|
|
||||||
|
instant_message_sender(value)
|
||||||
|
end
|
||||||
update_state!(Actions::ClearQueue)
|
update_state!(Actions::ClearQueue)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def instant_message_sender(message)
|
||||||
|
ui_controller.user_interfaces.each_value do |dialog|
|
||||||
|
dialog.execute_script(message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This is the only function application state will be switched by calling upcoming action with it's parameters
|
# This is the only function application state will be switched by calling upcoming action with it's parameters
|
||||||
# if any.
|
# if any.
|
||||||
def update_state!(action, *parameters)
|
def update_state!(action, *parameters)
|
||||||
old_state = @state
|
old_state = @state
|
||||||
@state = action.update_state(old_state, *parameters)
|
@state = action.update_state(old_state, *parameters)
|
||||||
send_messages! if @state.speckle_state.message_queue.any?
|
send_messages! if @state.speckle_state.message_queue.any?
|
||||||
update_ui! unless @state.equal?(old_state)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../speckle_objects/other/color'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Cards
|
||||||
|
# Card for sketchup connector to communicate speckle.
|
||||||
|
class Card < Hash
|
||||||
|
# @return [String] id of the card.
|
||||||
|
attr_reader :id
|
||||||
|
|
||||||
|
# @return [String] account id of the card.
|
||||||
|
attr_reader :account_id
|
||||||
|
|
||||||
|
# @return [String] project id of the card.
|
||||||
|
attr_reader :project_id
|
||||||
|
|
||||||
|
# @return [String] model id of the card.
|
||||||
|
attr_reader :model_id
|
||||||
|
|
||||||
|
# @return [Boolean] card is valid or not.
|
||||||
|
attr_reader :valid
|
||||||
|
|
||||||
|
def initialize(card_id, account_id, project_id, model_id)
|
||||||
|
super()
|
||||||
|
@id = card_id
|
||||||
|
@account_id = account_id
|
||||||
|
@project_id = project_id
|
||||||
|
@model_id = model_id
|
||||||
|
@valid = true
|
||||||
|
self[:id] = card_id
|
||||||
|
self[:account_id] = account_id
|
||||||
|
self[:project_id] = project_id
|
||||||
|
self[:model_id] = model_id
|
||||||
|
self[:valid] = @valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'card'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Cards
|
||||||
|
# Receive card for sketchup connector to communicate speckle.
|
||||||
|
class ReceiveCard < Card
|
||||||
|
attr_reader :type_discriminator
|
||||||
|
|
||||||
|
# @return [String, NilClass] message to send
|
||||||
|
attr_reader :message
|
||||||
|
|
||||||
|
# @return [String] object id to receive
|
||||||
|
attr_reader :object_id
|
||||||
|
|
||||||
|
# @return [String] name of the project
|
||||||
|
attr_reader :project_name
|
||||||
|
|
||||||
|
# @return [String] name of the model
|
||||||
|
attr_reader :model_name
|
||||||
|
|
||||||
|
def initialize(card_id, account_id, project_id, project_name, model_id, model_name, object_id)
|
||||||
|
super(card_id, account_id, project_id, model_id)
|
||||||
|
@object_id = object_id
|
||||||
|
self[:object_id] = object_id
|
||||||
|
self[:model_name] = model_name
|
||||||
|
self[:project_name] = project_name
|
||||||
|
@model_name = model_name
|
||||||
|
@project_name = project_name
|
||||||
|
@type_discriminator = 'ReceiverModelCard'
|
||||||
|
self[:type_discriminator] = @type_discriminator
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'card'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Cards
|
||||||
|
# Send card for sketchup connector to communicate speckle.
|
||||||
|
class SendCard < Card
|
||||||
|
# @return [Filters::Send::EverythingFilter | Filters::Send::SelectionFilter | Filters::Send::LayerFilter] filter of the card.
|
||||||
|
attr_reader :send_filter
|
||||||
|
|
||||||
|
# @return [Object] send settings of the card.
|
||||||
|
attr_reader :send_settings
|
||||||
|
|
||||||
|
attr_reader :type_discriminator
|
||||||
|
|
||||||
|
# @return [String, NilClass] message to send
|
||||||
|
attr_reader :message
|
||||||
|
|
||||||
|
def initialize(card_id, account_id, project_id, model_id, send_filter, send_settings)
|
||||||
|
super(card_id, account_id, project_id, model_id)
|
||||||
|
@send_filter = send_filter
|
||||||
|
@send_settings = send_settings
|
||||||
|
@type_discriminator = 'SenderModelCard'
|
||||||
|
self[:sendFilter] = send_filter
|
||||||
|
self[:sendSettings] = send_settings
|
||||||
|
self[:type_discriminator] = @type_discriminator
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'card'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Cards
|
||||||
|
# Send card for sketchup connector to communicate speckle.
|
||||||
|
class SendCardMultipleFilters < Card
|
||||||
|
# @return [Hash{String=>Filter}] filters of the card.
|
||||||
|
attr_reader :filters
|
||||||
|
|
||||||
|
def initialize(card_id, account_id, project_id, model_id, filters)
|
||||||
|
super(card_id, account_id, project_id, model_id)
|
||||||
|
@filters = filters
|
||||||
|
self[:filters] = filters
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -7,10 +7,10 @@ module SpeckleConnector
|
|||||||
# Command to update state of the application.
|
# Command to update state of the application.
|
||||||
class ActionCommand < Command
|
class ActionCommand < Command
|
||||||
# @param app [App::SpeckleConnectorApp] the app object to run command on
|
# @param app [App::SpeckleConnectorApp] the app object to run command on
|
||||||
|
# @param binding [Ui::Binding] binding object holds commands to call
|
||||||
# @param action [#update_state] the action that knows how to change the state of the speckle app
|
# @param action [#update_state] the action that knows how to change the state of the speckle app
|
||||||
def initialize(app, action)
|
def initialize(app, binding, action)
|
||||||
super(app)
|
super(app, binding)
|
||||||
@app = app
|
|
||||||
@action = action
|
@action = action
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to activate diffing for stream.
|
# Command to activate diffing for stream.
|
||||||
class ActivateDiffing < Command
|
class ActivateDiffing < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
stream_id = data['stream_id']
|
stream_id = data['stream_id']
|
||||||
action = Actions::ActivateDiffing.new(stream_id)
|
action = Actions::ActivateDiffing.new(stream_id)
|
||||||
app.update_state!(action)
|
app.update_state!(action)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to apply mapping for selected entities.
|
# Command to apply mapping for selected entities.
|
||||||
class ApplyMappings < Command
|
class ApplyMappings < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
entities_to_map = data['entitiesToMap']
|
entities_to_map = data['entitiesToMap']
|
||||||
method = data['method']
|
method = data['method']
|
||||||
category = data['category']
|
category = data['category']
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to clear mapping for selected entities.
|
# Command to clear mapping for selected entities.
|
||||||
class ClearMappings < Command
|
class ClearMappings < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
entities_to_map = data['entitiesToClearMap']
|
entities_to_map = data['entitiesToClearMap']
|
||||||
is_definition = data['isDefinition']
|
is_definition = data['isDefinition']
|
||||||
action = Actions::ClearMappings.new(entities_to_map, is_definition)
|
action = Actions::ClearMappings.new(entities_to_map, is_definition)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../actions/handle_error'
|
||||||
|
|
||||||
module SpeckleConnector
|
module SpeckleConnector
|
||||||
module Commands
|
module Commands
|
||||||
# Base command schema to wrap common operations for all commands.
|
# Base command schema to wrap common operations for all commands.
|
||||||
@@ -7,19 +9,25 @@ module SpeckleConnector
|
|||||||
# @return [App::SpeckleConnectorApp] the main app object
|
# @return [App::SpeckleConnectorApp] the main app object
|
||||||
attr_reader :app
|
attr_reader :app
|
||||||
|
|
||||||
# @return [Ui::View] view object holds dialog and it's state
|
# @return [Ui::Binding] binding object holds dialog and it's state
|
||||||
attr_reader :view
|
attr_reader :binding
|
||||||
|
|
||||||
# @@param app [App::SpeckleConnectorApp] the main app object
|
# @param app [App::SpeckleConnectorApp] the main app object
|
||||||
def initialize(app)
|
# @param binding [Ui::Binding] binding object holds commands to call
|
||||||
|
def initialize(app, binding)
|
||||||
@app = app
|
@app = app
|
||||||
@view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
|
@binding = binding
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(*parameters)
|
def run(*parameters)
|
||||||
# Run here common operations that same for each command.
|
begin
|
||||||
with_observers_disabled do
|
# Run here common operations that same for each command.
|
||||||
_run(*parameters)
|
with_observers_disabled do
|
||||||
|
_run(*parameters)
|
||||||
|
end
|
||||||
|
rescue StandardError => e
|
||||||
|
action = Actions::HandleError.new(e, @binding.name, @action, parameters)
|
||||||
|
app.update_state!(action)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require_relative 'command'
|
|
||||||
|
|
||||||
module SpeckleConnector
|
|
||||||
module Commands
|
|
||||||
# Run this command when the UI is ready to get data
|
|
||||||
class DialogReady < Command
|
|
||||||
# Update the selected user interface
|
|
||||||
def _run(_data)
|
|
||||||
view.update_view(app.state)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'command'
|
||||||
|
require_relative '../ui/dui3_dialog'
|
||||||
|
require_relative '../states/initial_state'
|
||||||
|
require_relative '../ui/legacy_binding'
|
||||||
|
require_relative '../ui/bindings/accounts_binding'
|
||||||
|
require_relative '../ui/bindings/base_binding'
|
||||||
|
require_relative '../ui/bindings/send_binding'
|
||||||
|
require_relative '../ui/bindings/receive_binding'
|
||||||
|
require_relative '../ui/bindings/selection_binding'
|
||||||
|
require_relative '../ui/test_binding'
|
||||||
|
require_relative '../ui/bindings/config_binding'
|
||||||
|
require_relative '../ui/sketchup_config_binding'
|
||||||
|
require_relative '../actions/initialize_speckle'
|
||||||
|
require_relative '../observers/factory'
|
||||||
|
|
||||||
|
module SpeckleConnector
|
||||||
|
module Commands
|
||||||
|
# Command to initialize Speckle UI and register it to ui_controller.
|
||||||
|
# This is the command where we show UI to user.
|
||||||
|
class InitializeDUI3Speckle < Command
|
||||||
|
SPECKLE_DUI3 = 'speckle_dui3'
|
||||||
|
|
||||||
|
def dialog_title
|
||||||
|
"Speckle #{CONNECTOR_VERSION}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def _run
|
||||||
|
app = self.app
|
||||||
|
if !app.state.instance_of?(States::InitialState) && app.ui_controller.user_interfaces[SPECKLE_DUI3]
|
||||||
|
dialog = app.ui_controller.user_interfaces[SPECKLE_DUI3]
|
||||||
|
dialog.show
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
initialize_speckle_dui3(app)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Do the actual Speckle initialization.
|
||||||
|
# rubocop:disable Naming/VariableNumber
|
||||||
|
def initialize_speckle_dui3(app)
|
||||||
|
# TODO: Initialize here speckle states and observers.
|
||||||
|
observer_handler = Observers::Factory.create_handler(app)
|
||||||
|
app.add_observer_handler!(observer_handler)
|
||||||
|
observers = Observers::Factory.create_observers(observer_handler)
|
||||||
|
app.update_state!(Actions::InitializeSpeckle, observers, app.method(:instant_message_sender))
|
||||||
|
dialog_specs = {
|
||||||
|
dialog_id: SPECKLE_DUI3,
|
||||||
|
dialog_title: dialog_title,
|
||||||
|
height: 950,
|
||||||
|
width: 300
|
||||||
|
}
|
||||||
|
# Init bindings
|
||||||
|
base_binding = Ui::BaseBinding.new(app, Ui::BASE_BINDING_NAME)
|
||||||
|
accounts_binding = Ui::AccountsBinding.new(app, Ui::ACCOUNTS_BINDING_NAME)
|
||||||
|
send_binding = Ui::SendBinding.new(app, Ui::SEND_BINDING_NAME)
|
||||||
|
receive_binding = Ui::ReceiveBinding.new(app, Ui::RECEIVE_BINDING_NAME)
|
||||||
|
selection_binding = Ui::SelectionBinding.new(app, Ui::SELECTION_BINDING_NAME)
|
||||||
|
test_bindings = Ui::TestBinding.new(app, Ui::TEST_BINDINGS_NAME)
|
||||||
|
config_bindings = Ui::ConfigBinding.new(app, Ui::CONFIG_BINDING_NAME)
|
||||||
|
connector_config_bindings = Ui::SketchupConfigBinding.new(app, Ui::CONNECTOR_CONFIG_BINDING_NAME)
|
||||||
|
|
||||||
|
# Init dialog
|
||||||
|
dui3_dialog = SpeckleConnector::Ui::DUI3Dialog.new(**dialog_specs)
|
||||||
|
|
||||||
|
# Register bindings to dialog
|
||||||
|
dui3_dialog.bindings[Ui::BASE_BINDING_NAME] = base_binding
|
||||||
|
dui3_dialog.bindings[Ui::ACCOUNTS_BINDING_NAME] = accounts_binding
|
||||||
|
dui3_dialog.bindings[Ui::SEND_BINDING_NAME] = send_binding
|
||||||
|
dui3_dialog.bindings[Ui::RECEIVE_BINDING_NAME] = receive_binding
|
||||||
|
dui3_dialog.bindings[Ui::TEST_BINDINGS_NAME] = test_bindings
|
||||||
|
dui3_dialog.bindings[Ui::CONFIG_BINDING_NAME] = config_bindings
|
||||||
|
dui3_dialog.bindings[Ui::CONNECTOR_CONFIG_BINDING_NAME] = connector_config_bindings
|
||||||
|
dui3_dialog.bindings[Ui::SELECTION_BINDING_NAME] = selection_binding
|
||||||
|
|
||||||
|
app.ui_controller.register_ui(SPECKLE_DUI3, dui3_dialog)
|
||||||
|
dui3_dialog.show
|
||||||
|
end
|
||||||
|
# rubocop:enable Naming/VariableNumber
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
require_relative 'command'
|
require_relative 'command'
|
||||||
require_relative '../states/initial_state'
|
require_relative '../states/initial_state'
|
||||||
require_relative '../ui/vue_view'
|
require_relative '../ui/legacy_binding'
|
||||||
require_relative '../actions/initialize_speckle'
|
require_relative '../actions/initialize_speckle'
|
||||||
require_relative '../observers/factory'
|
require_relative '../observers/factory'
|
||||||
|
|
||||||
module SpeckleConnector
|
module SpeckleConnector
|
||||||
module Commands
|
module Commands
|
||||||
# Command to initialize Speckle UI and register it to ui_controller.
|
# Command to initialize old Speckle UI and register it to ui_controller.
|
||||||
# This is the command where we show UI to user.
|
# This is the command where we show UI to user.
|
||||||
class InitializeSpeckle < Command
|
class InitializeSpeckle < Command
|
||||||
|
SPECKLE_LEGACY_UI = 'speckle_legacy_ui'
|
||||||
|
|
||||||
def dialog_title
|
def dialog_title
|
||||||
"Speckle #{CONNECTOR_VERSION}"
|
"Speckle #{CONNECTOR_VERSION}"
|
||||||
end
|
end
|
||||||
@@ -19,32 +21,34 @@ module SpeckleConnector
|
|||||||
|
|
||||||
def _run
|
def _run
|
||||||
app = self.app
|
app = self.app
|
||||||
unless app.state.instance_of?(States::InitialState)
|
if !app.state.instance_of?(States::InitialState) && app.ui_controller.user_interfaces[SPECKLE_LEGACY_UI]
|
||||||
vue_view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
|
vue_view = app.ui_controller.user_interfaces[SPECKLE_LEGACY_UI]
|
||||||
vue_view.show
|
vue_view.show
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
initialize_speckle(app)
|
initialize_speckle_legacy_view(app)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Do the actual Speckle initialization.
|
# Do the actual Speckle initialization.
|
||||||
def initialize_speckle(app)
|
def initialize_speckle_legacy_view(app)
|
||||||
# TODO: Initialize here speckle states and observers.
|
# TODO: Initialize here speckle states and observers.
|
||||||
observer_handler = Observers::Factory.create_handler(app)
|
observer_handler = Observers::Factory.create_handler(app)
|
||||||
app.add_observer_handler!(observer_handler)
|
app.add_observer_handler!(observer_handler)
|
||||||
observers = Observers::Factory.create_observers(observer_handler)
|
observers = Observers::Factory.create_observers(observer_handler)
|
||||||
app.update_state!(Actions::InitializeSpeckle, observers)
|
app.update_state!(Actions::InitializeSpeckle, observers)
|
||||||
dialog_specs = {
|
dialog_specs = {
|
||||||
dialog_id: Ui::SPECKLE_UI_ID,
|
dialog_id: SPECKLE_LEGACY_UI,
|
||||||
htm_file: Ui::VUE_UI_HTML,
|
htm_file: Ui::VUE_UI_HTML,
|
||||||
dialog_title: dialog_title,
|
dialog_title: dialog_title,
|
||||||
height: 950,
|
height: 950,
|
||||||
width: 300
|
width: 300
|
||||||
}
|
}
|
||||||
vue_view = Ui::VueView.new(dialog_specs, app)
|
legacy_ui_dialog = SpeckleConnector::Ui::Dialog.new(**dialog_specs)
|
||||||
app.ui_controller.register_ui(Ui::SPECKLE_UI_ID, vue_view)
|
legacy_binding = Ui::LegacyBinding.new(app, 'legacy_ui')
|
||||||
vue_view.show
|
legacy_ui_dialog.bindings[Ui::SPECKLE_LEGACY_BINDING_NAME] = legacy_binding
|
||||||
|
app.ui_controller.register_ui(SPECKLE_LEGACY_UI, legacy_ui_dialog)
|
||||||
|
legacy_ui_dialog.show
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to update mapper source.
|
# Command to update mapper source.
|
||||||
class MapperSourceUpdated < Command
|
class MapperSourceUpdated < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
base = data['base']
|
base = data['base']
|
||||||
stream_id = data['stream_id']
|
stream_id = data['stream_id']
|
||||||
commit_id = data['commit_id']
|
commit_id = data['commit_id']
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to update theme.
|
# Command to update theme.
|
||||||
class ModelPreferencesUpdated < Command
|
class ModelPreferencesUpdated < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
preference = data['preference']
|
preference = data['preference']
|
||||||
new_value = data['value']
|
new_value = data['value']
|
||||||
app.update_state!(Actions::ModelPreferencesUpdated.new(preference, new_value))
|
app.update_state!(Actions::ModelPreferencesUpdated.new(preference, new_value))
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to notify connected.
|
# Command to notify connected.
|
||||||
class NotifyConnected < Command
|
class NotifyConnected < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
stream_id = data['stream_id']
|
stream_id = data['stream_id']
|
||||||
app.update_state!(Actions::Connected)
|
app.update_state!(Actions::Connected)
|
||||||
app.update_state!(Actions::SendFromQueue.new(stream_id))
|
app.update_state!(Actions::SendFromQueue.new(stream_id))
|
||||||
|
|||||||
@@ -7,14 +7,15 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to receive objects from Speckle Server.
|
# Command to receive objects from Speckle Server.
|
||||||
class ReceiveObjects < Command
|
class ReceiveObjects < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
stream_id = data['stream_id']
|
stream_id = data['stream_id']
|
||||||
base = data['base']
|
base = data['base']
|
||||||
branch_name = data['branch_name']
|
branch_name = data['branch_name']
|
||||||
branch_id = data['branch_id']
|
branch_id = data['branch_id']
|
||||||
stream_name = data['stream_name']
|
stream_name = data['stream_name']
|
||||||
source_app = data['source_app']
|
source_app = data['source_app']
|
||||||
action = Actions::ReceiveObjects.new(stream_id, base, stream_name, branch_name, branch_id, source_app)
|
object_id = data['object_id']
|
||||||
|
action = Actions::ReceiveObjects.new(stream_id, base, stream_name, branch_name, branch_id, source_app, object_id)
|
||||||
app.update_state!(action)
|
app.update_state!(action)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to remove stream.
|
# Command to remove stream.
|
||||||
class RemoveStream < Command
|
class RemoveStream < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
stream_id = data['stream_id']
|
stream_id = data['stream_id']
|
||||||
action = Actions::RemoveStream.new(stream_id)
|
action = Actions::RemoveStream.new(stream_id)
|
||||||
app.update_state!(action)
|
app.update_state!(action)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
require_relative 'command'
|
require_relative 'command'
|
||||||
require_relative '../states/initial_state'
|
require_relative '../states/initial_state'
|
||||||
require_relative '../ui/vue_view'
|
|
||||||
require_relative '../actions/initialize_speckle'
|
require_relative '../actions/initialize_speckle'
|
||||||
require_relative '../observers/factory'
|
require_relative '../observers/factory'
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@ module SpeckleConnector
|
|||||||
|
|
||||||
def _run
|
def _run
|
||||||
app = self.app
|
app = self.app
|
||||||
vue_view = app.ui_controller.user_interfaces[Ui::SPECKLE_UI_ID]
|
vue_view = app.ui_controller.user_interfaces[Ui::SPECKLE_LEGACY_UI]
|
||||||
if vue_view
|
if vue_view
|
||||||
vue_view.dialog.reset_dialog_location
|
vue_view.dialog.reset_dialog_location
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to saved stream.
|
# Command to saved stream.
|
||||||
class SaveStream < Command
|
class SaveStream < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
stream_id = data['stream_id']
|
stream_id = data['stream_id']
|
||||||
app.update_state!(Actions::SaveStream.new(stream_id))
|
app.update_state!(Actions::SaveStream.new(stream_id))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to send selection to Speckle Server.
|
# Command to send selection to Speckle Server.
|
||||||
class SendSelection < Command
|
class SendSelection < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
stream_id = data['stream_id']
|
stream_id = data['stream_id']
|
||||||
action = Actions::SendSelection.new(stream_id)
|
action = Actions::SendSelection.new(stream_id)
|
||||||
app.update_state!(action)
|
app.update_state!(action)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
require_relative 'menu_command_handler'
|
require_relative 'menu_command_handler'
|
||||||
require_relative 'action_command'
|
require_relative 'action_command'
|
||||||
require_relative 'initialize_speckle'
|
require_relative 'initialize_speckle'
|
||||||
|
require_relative 'initialize_dui3_speckle'
|
||||||
require_relative 'reset_window_location'
|
require_relative 'reset_window_location'
|
||||||
require_relative '../actions/one_click_send'
|
require_relative '../actions/one_click_send'
|
||||||
|
|
||||||
@@ -11,6 +12,7 @@ module SpeckleConnector
|
|||||||
# Speckle menu commands that adds them to Sketchup menu and toolbar.
|
# Speckle menu commands that adds them to Sketchup menu and toolbar.
|
||||||
class SpeckleMenuCommands
|
class SpeckleMenuCommands
|
||||||
CMD_INITIALIZE_SPECKLE = :initialize_speckle
|
CMD_INITIALIZE_SPECKLE = :initialize_speckle
|
||||||
|
CMD_INITIALIZE_DUI3_SPECKLE = :initialize_dui3_speckle
|
||||||
CMD_RESET_WINDOW_LOCATION_SPECKLE = :reset_window_location_speckle
|
CMD_RESET_WINDOW_LOCATION_SPECKLE = :reset_window_location_speckle
|
||||||
CMD_SEND_TO_SPECKLE = :send_to_speckle
|
CMD_SEND_TO_SPECKLE = :send_to_speckle
|
||||||
CMD_RECEIVE_FROM_SPECKLE = :receive_from_speckle
|
CMD_RECEIVE_FROM_SPECKLE = :receive_from_speckle
|
||||||
@@ -28,6 +30,10 @@ module SpeckleConnector
|
|||||||
commands.add_to_menu!(CMD_INITIALIZE_SPECKLE, speckle_menu)
|
commands.add_to_menu!(CMD_INITIALIZE_SPECKLE, speckle_menu)
|
||||||
commands.add_to_toolbar!(CMD_INITIALIZE_SPECKLE, speckle_toolbar)
|
commands.add_to_toolbar!(CMD_INITIALIZE_SPECKLE, speckle_toolbar)
|
||||||
|
|
||||||
|
commands[CMD_INITIALIZE_DUI3_SPECKLE] = initialize_dui3_speckle_command(app)
|
||||||
|
commands.add_to_menu!(CMD_INITIALIZE_DUI3_SPECKLE, speckle_menu)
|
||||||
|
commands.add_to_toolbar!(CMD_INITIALIZE_DUI3_SPECKLE, speckle_toolbar)
|
||||||
|
|
||||||
commands[CMD_RESET_WINDOW_LOCATION_SPECKLE] = reset_window_location_command(app)
|
commands[CMD_RESET_WINDOW_LOCATION_SPECKLE] = reset_window_location_command(app)
|
||||||
commands.add_to_menu!(CMD_RESET_WINDOW_LOCATION_SPECKLE, speckle_menu)
|
commands.add_to_menu!(CMD_RESET_WINDOW_LOCATION_SPECKLE, speckle_menu)
|
||||||
|
|
||||||
@@ -38,7 +44,7 @@ module SpeckleConnector
|
|||||||
|
|
||||||
def self.initialize_speckle_command(app)
|
def self.initialize_speckle_command(app)
|
||||||
cmd = MenuCommandHandler.sketchup_command(
|
cmd = MenuCommandHandler.sketchup_command(
|
||||||
InitializeSpeckle.new(app), 'Initialize Speckle'
|
InitializeSpeckle.new(app, nil), 'Initialize Speckle'
|
||||||
)
|
)
|
||||||
cmd.tooltip = 'Launch Connector'
|
cmd.tooltip = 'Launch Connector'
|
||||||
cmd.status_bar_text = 'Opens the Speckle Connector window'
|
cmd.status_bar_text = 'Opens the Speckle Connector window'
|
||||||
@@ -47,9 +53,20 @@ module SpeckleConnector
|
|||||||
cmd
|
cmd
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.initialize_dui3_speckle_command(app)
|
||||||
|
cmd = MenuCommandHandler.sketchup_command(
|
||||||
|
InitializeDUI3Speckle.new(app, nil), 'Initialize DUI3 Speckle'
|
||||||
|
)
|
||||||
|
cmd.tooltip = 'Launch Connector with DUI3'
|
||||||
|
cmd.status_bar_text = 'Opens the Speckle Connector DUI3 Window'
|
||||||
|
cmd.small_icon = '../../img/s2logo_dui3.png'
|
||||||
|
cmd.large_icon = '../../img/s2logo_dui3.png'
|
||||||
|
cmd
|
||||||
|
end
|
||||||
|
|
||||||
def self.reset_window_location_command(app)
|
def self.reset_window_location_command(app)
|
||||||
cmd = MenuCommandHandler.sketchup_command(
|
cmd = MenuCommandHandler.sketchup_command(
|
||||||
ResetWindowLocation.new(app), 'Reset Window Location'
|
ResetWindowLocation.new(app, nil), 'Reset Window Location'
|
||||||
)
|
)
|
||||||
cmd.tooltip = 'Bring Speckle window onto center of SketchUp window'
|
cmd.tooltip = 'Bring Speckle window onto center of SketchUp window'
|
||||||
cmd.status_bar_text = 'Bring Speckle window onto center of SketchUp window'
|
cmd.status_bar_text = 'Bring Speckle window onto center of SketchUp window'
|
||||||
@@ -60,7 +77,7 @@ module SpeckleConnector
|
|||||||
|
|
||||||
def self.send_command(app)
|
def self.send_command(app)
|
||||||
cmd = MenuCommandHandler.sketchup_command(
|
cmd = MenuCommandHandler.sketchup_command(
|
||||||
ActionCommand.new(app, Actions::OneClickSend), 'Send to Speckle'
|
ActionCommand.new(app, nil, Actions::OneClickSend), 'Send to Speckle'
|
||||||
)
|
)
|
||||||
cmd.tooltip = 'Send to Speckle'
|
cmd.tooltip = 'Send to Speckle'
|
||||||
cmd.status_bar_text = 'Send to Speckle'
|
cmd.status_bar_text = 'Send to Speckle'
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module SpeckleConnector
|
|||||||
module Commands
|
module Commands
|
||||||
# Command to update preferences.
|
# Command to update preferences.
|
||||||
class UserPreferencesUpdated < Command
|
class UserPreferencesUpdated < Command
|
||||||
def _run(data)
|
def _run(_resolve_id, data)
|
||||||
preference_hash = data['preference_hash']
|
preference_hash = data['preference_hash']
|
||||||
preference = data['preference']
|
preference = data['preference']
|
||||||
new_value = data['value']
|
new_value = data['value']
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ module SpeckleConnector
|
|||||||
SPECKLE_MAPPING_TOOL_SCHEMA = 'Speckle_Mapping_Tool_Schema'
|
SPECKLE_MAPPING_TOOL_SCHEMA = 'Speckle_Mapping_Tool_Schema'
|
||||||
SPECKLE_SCHEMA = 'Speckle_Schema'
|
SPECKLE_SCHEMA = 'Speckle_Schema'
|
||||||
|
|
||||||
|
SPECKLE_SEND_CARDS = 'Speckle_Send_Cards'
|
||||||
|
SPECKLE_RECEIVE_CARDS = 'Speckle_Receive_Cards'
|
||||||
|
|
||||||
SPECKLE_ID = 'speckle_id'
|
SPECKLE_ID = 'speckle_id'
|
||||||
SPECKLE_TYPE = 'speckle_type'
|
SPECKLE_TYPE = 'speckle_type'
|
||||||
APPLICATION_ID = 'application_id'
|
APPLICATION_ID = 'application_id'
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ module SpeckleConnector
|
|||||||
Sketchup::ComponentInstance => INCLUDE_COMPONENT_ENTITY_ATTRIBUTES,
|
Sketchup::ComponentInstance => INCLUDE_COMPONENT_ENTITY_ATTRIBUTES,
|
||||||
Sketchup::Group => INCLUDE_GROUP_ENTITY_ATTRIBUTES,
|
Sketchup::Group => INCLUDE_GROUP_ENTITY_ATTRIBUTES,
|
||||||
Sketchup::Face => INCLUDE_FACE_ENTITY_ATTRIBUTES,
|
Sketchup::Face => INCLUDE_FACE_ENTITY_ATTRIBUTES,
|
||||||
Sketchup::Face => INCLUDE_EDGE_ENTITY_ATTRIBUTES
|
Sketchup::Edge => INCLUDE_EDGE_ENTITY_ATTRIBUTES
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
LEVEL_SHIFT_VALUE = SpeckleObjects::Geometry.length_to_native(1.5, 'm')
|
LEVEL_SHIFT_VALUE = SpeckleObjects::Geometry.length_to_native(1.5, 'm')
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ module SpeckleConnector
|
|||||||
OBJECTS_BUILTELEMENTS_REVIT_FLOOR = 'Objects.BuiltElements.Floor:Objects.BuiltElements.Revit.RevitFloor'
|
OBJECTS_BUILTELEMENTS_REVIT_FLOOR = 'Objects.BuiltElements.Floor:Objects.BuiltElements.Revit.RevitFloor'
|
||||||
OBJECTS_BUILTELEMENTS_DEFAULT_WALL = 'Objects.BuiltElements.Wall'
|
OBJECTS_BUILTELEMENTS_DEFAULT_WALL = 'Objects.BuiltElements.Wall'
|
||||||
OBJECTS_BUILTELEMENTS_REVIT_WALL = 'Objects.BuiltElements.Wall:Objects.BuiltElements.Revit.RevitWall'
|
OBJECTS_BUILTELEMENTS_REVIT_WALL = 'Objects.BuiltElements.Wall:Objects.BuiltElements.Revit.RevitWall'
|
||||||
|
OBJECTS_BUILTELEMENTS_DEFAULT_COLUMN = 'Objects.BuiltElements.Column'
|
||||||
|
OBJECTS_BUILTELEMENTS_REVIT_COLUMN = 'Objects.BuiltElements.Column:Objects.BuiltElements.Revit.RevitColumn'
|
||||||
|
OBJECTS_BUILTELEMENTS_DEFAULT_BEAM = 'Objects.BuiltElements.Beam'
|
||||||
|
OBJECTS_BUILTELEMENTS_REVIT_BEAM = 'Objects.BuiltElements.Beam:Objects.BuiltElements.Revit.RevitBeam'
|
||||||
|
OBJECTS_BUILTELEMENTS_DEFAULT_PIPE = 'Objects.BuiltElements.Pipe'
|
||||||
|
OBJECTS_BUILTELEMENTS_REVIT_PIPE = 'Objects.BuiltElements.Pipe:Objects.BuiltElements.Revit.RevitPipe'
|
||||||
|
OBJECTS_BUILTELEMENTS_DEFAULT_DUCT = 'Objects.BuiltElements.Duct'
|
||||||
|
OBJECTS_BUILTELEMENTS_REVIT_DUCT = 'Objects.BuiltElements.Duct:Objects.BuiltElements.Revit.RevitDuct'
|
||||||
OBJECTS_BUILTELEMENTS_REVIT_DIRECTSHAPE = 'Objects.BuiltElements.Revit.DirectShape'
|
OBJECTS_BUILTELEMENTS_REVIT_DIRECTSHAPE = 'Objects.BuiltElements.Revit.DirectShape'
|
||||||
OBJECTS_BUILTELEMENTS_REVIT_FAMILY_INSTANCE = 'Objects.BuiltElements.Revit.FamilyInstance'
|
OBJECTS_BUILTELEMENTS_REVIT_FAMILY_INSTANCE = 'Objects.BuiltElements.Revit.FamilyInstance'
|
||||||
OBJECTS_BUILTELEMENTS_REVIT_PARAMETER = 'Objects.BuiltElements.Revit.Parameter'
|
OBJECTS_BUILTELEMENTS_REVIT_PARAMETER = 'Objects.BuiltElements.Revit.Parameter'
|
||||||
|
|||||||
@@ -310,8 +310,12 @@ module SpeckleConnector
|
|||||||
Digest::MD5.hexdigest(traversed_base.to_json)
|
Digest::MD5.hexdigest(traversed_base.to_json)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def batch_objects
|
||||||
|
@objects
|
||||||
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics/MethodLength
|
# rubocop:disable Metrics/MethodLength
|
||||||
def batch_objects(max_batch_size_mb = 1)
|
def batch_json_objects(max_batch_size_mb = 1)
|
||||||
max_size = 1000 * 1000 * max_batch_size_mb
|
max_size = 1000 * 1000 * max_batch_size_mb
|
||||||
batches = []
|
batches = []
|
||||||
batch = '['
|
batch = '['
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ module SpeckleConnector
|
|||||||
|
|
||||||
attr_accessor :definitions
|
attr_accessor :definitions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# @param state [States::State] the current state of the {SpeckleConnector::App}
|
# @param state [States::State] the current state of the {SpeckleConnector::App}
|
||||||
def initialize(state, stream_id)
|
def initialize(state, stream_id)
|
||||||
@state = state
|
@state = state
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ require_relative '../constants/path_constants'
|
|||||||
require_relative '../sketchup_model/reader/speckle_entities_reader'
|
require_relative '../sketchup_model/reader/speckle_entities_reader'
|
||||||
require_relative '../sketchup_model/reader/mapper_reader'
|
require_relative '../sketchup_model/reader/mapper_reader'
|
||||||
require_relative '../sketchup_model/query/entity'
|
require_relative '../sketchup_model/query/entity'
|
||||||
|
require_relative '../ext/TT_Lib2/progressbar'
|
||||||
|
require_relative '../ext/TT_Lib2/model'
|
||||||
|
require_relative '../ext/TT_Lib2/entities'
|
||||||
|
|
||||||
module SpeckleConnector
|
module SpeckleConnector
|
||||||
module Converters
|
module Converters
|
||||||
@@ -27,12 +30,37 @@ module SpeckleConnector
|
|||||||
SPECKLE_ENTITIES_READER = SketchupModel::Reader::SpeckleEntitiesReader
|
SPECKLE_ENTITIES_READER = SketchupModel::Reader::SpeckleEntitiesReader
|
||||||
VIEW3D = SpeckleObjects::BuiltElements::View3d
|
VIEW3D = SpeckleObjects::BuiltElements::View3d
|
||||||
|
|
||||||
|
# @return [TT::ProgressBar]
|
||||||
|
attr_reader :progress_bar
|
||||||
|
|
||||||
|
attr_reader :entity_count
|
||||||
|
|
||||||
|
attr_reader :send_filter
|
||||||
|
|
||||||
|
attr_reader :worker
|
||||||
|
|
||||||
|
attr_writer :count
|
||||||
|
|
||||||
|
def initialize(state, stream_id, send_filter)
|
||||||
|
super(state, stream_id)
|
||||||
|
@count = 0
|
||||||
|
@send_filter = send_filter
|
||||||
|
model = state.sketchup_state.sketchup_model
|
||||||
|
@entity_count = if send_filter.name == 'Selection'
|
||||||
|
TT::Model.count_unique_entity(model)
|
||||||
|
else
|
||||||
|
TT::Entities.count_unique_entity(model.selection)
|
||||||
|
end
|
||||||
|
@progress_bar = TT::Progressbar.new(@entity_count, 'Converting to Speckle')
|
||||||
|
end
|
||||||
|
|
||||||
# Convert selected objects by putting them into related array that grouped by layer.
|
# Convert selected objects by putting them into related array that grouped by layer.
|
||||||
# @return [Hash{Symbol=>Array}] layers -which only have objects- to hold it's objects under the base object.
|
# @return [Hash{Symbol=>Array}] layers -which only have objects- to hold it's objects under the base object.
|
||||||
def convert_selection_to_base(preferences)
|
def convert_selection_to_base(preferences)
|
||||||
convert = method(:convert)
|
convert = method(:convert)
|
||||||
|
|
||||||
new_speckle_state, model_collection = MODEL_COLLECTION.from_sketchup_model(sketchup_model, speckle_state,
|
new_speckle_state, model_collection = MODEL_COLLECTION.from_sketchup_model(sketchup_model, speckle_state,
|
||||||
@units, preferences, &convert)
|
@units, preferences, state, @stream_id, &convert)
|
||||||
|
|
||||||
return new_speckle_state, model_collection
|
return new_speckle_state, model_collection
|
||||||
end
|
end
|
||||||
@@ -44,7 +72,7 @@ module SpeckleConnector
|
|||||||
serializer = SpeckleConnector::Converters::BaseObjectSerializer.new(speckle_state, stream_id, preferences)
|
serializer = SpeckleConnector::Converters::BaseObjectSerializer.new(speckle_state, stream_id, preferences)
|
||||||
t = Time.now.to_f
|
t = Time.now.to_f
|
||||||
id = serializer.serialize(base_and_entity)
|
id = serializer.serialize(base_and_entity)
|
||||||
batches = serializer.batch_objects
|
batches = serializer.batch_json_objects
|
||||||
# write_to_speckle_folder(id, batches)
|
# write_to_speckle_folder(id, batches)
|
||||||
puts "Generating traversed object elapsed #{Time.now.to_f - t} s"
|
puts "Generating traversed object elapsed #{Time.now.to_f - t} s"
|
||||||
base_total_children_count = serializer.total_children_count(id)
|
base_total_children_count = serializer.total_children_count(id)
|
||||||
@@ -62,6 +90,7 @@ module SpeckleConnector
|
|||||||
# @param speckle_state [States::SpeckleState] the current speckle state of the {States::State}
|
# @param speckle_state [States::SpeckleState] the current speckle state of the {States::State}
|
||||||
# @param parent [Symbol, String] parent of the Sketchup Entity to be converted.
|
# @param parent [Symbol, String] parent of the Sketchup Entity to be converted.
|
||||||
def convert(entity, preferences, speckle_state, parent = :base)
|
def convert(entity, preferences, speckle_state, parent = :base)
|
||||||
|
progress_bar.next
|
||||||
convert = method(:convert)
|
convert = method(:convert)
|
||||||
|
|
||||||
unless SketchupModel::Reader::MapperReader.mapped_with_schema?(entity) &&
|
unless SketchupModel::Reader::MapperReader.mapped_with_schema?(entity) &&
|
||||||
@@ -75,7 +104,8 @@ module SpeckleConnector
|
|||||||
# rubocop:disable Metrics/MethodLength
|
# rubocop:disable Metrics/MethodLength
|
||||||
def from_native_to_speckle(entity, preferences, speckle_state, parent, &convert)
|
def from_native_to_speckle(entity, preferences, speckle_state, parent, &convert)
|
||||||
if entity.is_a?(Sketchup::Edge)
|
if entity.is_a?(Sketchup::Edge)
|
||||||
line = SpeckleObjects::Geometry::Line.from_edge(entity, @units, preferences[:model]).to_h
|
line = SpeckleObjects::Geometry::Line.from_edge(speckle_state: speckle_state, edge: entity,
|
||||||
|
units: @units, model_preferences: preferences[:model]).to_h
|
||||||
return speckle_state, [line, [entity]]
|
return speckle_state, [line, [entity]]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT
|
||||||
|
module Lib
|
||||||
|
|
||||||
|
### CONSTANTS ### ------------------------------------------------------------
|
||||||
|
|
||||||
|
# Plugin information
|
||||||
|
PLUGIN_ID = 'TT_Lib2'.freeze
|
||||||
|
PLUGIN_NAME = 'TT_Lib²'.freeze
|
||||||
|
PLUGIN_VERSION = '2.13.1'.freeze
|
||||||
|
|
||||||
|
end # module Lib
|
||||||
|
end # module TT
|
||||||
|
end
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# CHANGELOG
|
||||||
|
# 2.5.0 - 18.10.2010
|
||||||
|
# * Upgraded JQuery to 1.4.4
|
||||||
|
# * Now bundles JQuery minimized
|
||||||
|
# * Added Win32Utils' Win32::API under TT::Win32::API
|
||||||
|
# * Added module: TT::Bezier
|
||||||
|
# * Added module: TT::Edge
|
||||||
|
# * Added module: TT::Edges
|
||||||
|
# * Added module: TT::Faces
|
||||||
|
# * Added module: TT::Materials
|
||||||
|
# * Added module: TT::Gizmo::Axis
|
||||||
|
# * Added module: TT::Win32
|
||||||
|
# * Added class: TT::Babelfish
|
||||||
|
# * Added class: TT::Dimension
|
||||||
|
# * Added class: TT::GUI::ToolWindow
|
||||||
|
# * Added method: TT::debug
|
||||||
|
# * Added method: TT::Point3d.douglas_peucker
|
||||||
|
# * Added method: TT::Point3d.simplify_curve
|
||||||
|
# * Added method: TT::Geom3d.interpolate_linear
|
||||||
|
# * Added method: TT::Geom3d.average_point
|
||||||
|
# * Added method: TT::GUI::Button.custom_properties
|
||||||
|
# * Added method: TT::GUI::Control.add_event
|
||||||
|
# * Added method: TT::GUI::Control.call_event
|
||||||
|
# * Added method: TT::GUI::Control.positioned?
|
||||||
|
# * Added method: TT::GUI::Control.properties
|
||||||
|
# * Added method: TT::GUI::ContainerElement.add_controls_to_webdialog
|
||||||
|
# * Added method: TT::GUI::ContainerElement.get_control_by_ui_id
|
||||||
|
# * Added methods: TT::GUI::Listbox
|
||||||
|
# * Added method: TT::GUI::Window.add_action_callback
|
||||||
|
# * Added method: TT::GUI::Window.add_control_to_webdialog
|
||||||
|
# * Added method: TT::GUI::Window.set_client_size
|
||||||
|
# * Added method: TT::System.is_windows?
|
||||||
|
# * Changed: TT::Gizmo::Manipulator
|
||||||
|
# * Changed: TT::GUI::Inputbox now inherits from TT::GUI::ToolWindow
|
||||||
|
# * Changed: TT::GUI::Inputbox.add_control accepts a +key+ argument a control id.
|
||||||
|
# * Changed: TT::GUI::Inputbox.prompt returns a Hash instead of Array.
|
||||||
|
# * Changed: TT::UV_Plane
|
||||||
|
# * Fixed: TT::JSON.to_s - Now handles Symbols as values.
|
||||||
|
# * Plus lots lots more - lots track of it all.
|
||||||
|
#
|
||||||
|
# 2.4.0 - 22.09.2010
|
||||||
|
# * Added module: TT::Binary
|
||||||
|
# * Added module: TT::GUI
|
||||||
|
# * Added class: TT::GUI::Window
|
||||||
|
# * Added class: TT::GUI::Inputbox
|
||||||
|
# * Added class: TT::JSON
|
||||||
|
# * Added module: TT::System
|
||||||
|
# * Added module: TT::Locale
|
||||||
|
# * Added module: TT::Cursor
|
||||||
|
#
|
||||||
|
# 2.3.0 - 08.09.2010
|
||||||
|
# * Added method: TT::Geom3d.spiral_sphere
|
||||||
|
# * Fixed: TT::Ray.test
|
||||||
|
#
|
||||||
|
# 2.2.0 - 06.09.2010
|
||||||
|
# * Added module: TT::Bounds
|
||||||
|
#
|
||||||
|
# 2.1.1 - 04.09.2010
|
||||||
|
# * Fixed bug: Ray.test (Workaround for SU8.0 bug)
|
||||||
|
#
|
||||||
|
# 2.1.0 - 03.09.2010
|
||||||
|
# * Added module: TT::Selection
|
||||||
|
# * Added module: TT::UVQ
|
||||||
|
# * Added class: TT::UV_Plane
|
||||||
|
# * Added class: TT::Gizmo::Manipulator
|
||||||
|
# * Added method: TT::Entities.bounds
|
||||||
|
# * Fixed: TT::Ray.test
|
||||||
|
#
|
||||||
|
# 2.0.0 - 01.09.2010
|
||||||
|
# * Initial Release
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
= TT_Lib2
|
||||||
|
|
||||||
|
* {SCF Thread}[http://forums.sketchucation.com/viewtopic.php?f=323&t=23307]
|
||||||
|
|
||||||
|
== Description
|
||||||
|
|
||||||
|
Library of common methods and classes for Google SketchUp Ruby plugins.
|
||||||
|
|
||||||
|
== Author
|
||||||
|
|
||||||
|
* Thomas Thomassen
|
||||||
|
* thomas[at]thomthom[dot]net
|
||||||
Binary file not shown.
@@ -0,0 +1,70 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
|
||||||
|
# Collection of Arc methods.
|
||||||
|
#
|
||||||
|
# @since 2.0.0
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT::Arc
|
||||||
|
|
||||||
|
# Checks if a given +Curve+ is an +ArcCurve+ and not a polygon.
|
||||||
|
#
|
||||||
|
# Check for polygon requires SketchUp 7.1M1 or newer. Older SketchUp
|
||||||
|
# versions will not check for this property.
|
||||||
|
#
|
||||||
|
# @param [Sketchup::Curve] curve
|
||||||
|
# @since 2.0.0
|
||||||
|
def self.is?( curve )
|
||||||
|
return false if curve.respond_to?( :is_polygon? ) && curve.is_polygon?
|
||||||
|
curve.is_a?(Sketchup::ArcCurve)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Checks if a given +Curve+ makes an circle and is not a polygon.
|
||||||
|
#
|
||||||
|
# Check for polygon requires SketchUp 7.1M1 or newer. Older SketchUp
|
||||||
|
# versions will not check for this property.
|
||||||
|
#
|
||||||
|
# SketchUp has a bug where an ArcCurve some times has 720 degrees angle
|
||||||
|
# instead of 360. This method handles this.
|
||||||
|
#
|
||||||
|
# @param [Sketchup::Curve] curve
|
||||||
|
# @since 2.0.0
|
||||||
|
def self.circle?( curve )
|
||||||
|
return false unless self.is?( curve )
|
||||||
|
return ((curve.end_angle - curve.start_angle).radians >= 360) ? true : false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Based on Chris Fullmers "Exploded Arc Centerpoint Finder".
|
||||||
|
# Calculates the centre points of an arc given two edges.
|
||||||
|
#
|
||||||
|
# @param [Sketchup::Edge] e1
|
||||||
|
# @param [Sketchup::Edge] e2
|
||||||
|
#
|
||||||
|
# @return [Geom::Point3d, nil]
|
||||||
|
# @since 2.0.0
|
||||||
|
def self.exploded_center(e1, e2)
|
||||||
|
# Two edges representing an arc must have the same length and can not
|
||||||
|
# be parallel.
|
||||||
|
return nil if e1.length != e2.length
|
||||||
|
v1 = e1.line[1]
|
||||||
|
v2 = e2.line[1]
|
||||||
|
return nil if v1.parallel?( v2 )
|
||||||
|
# Get mid-point of edges from where intersecting lines will origin.
|
||||||
|
m1 = Geom.linear_combination( 0.5, e1.start.position, 0.5, e1.end.position )
|
||||||
|
m2 = Geom.linear_combination( 0.5, e2.start.position, 0.5, e2.end.position )
|
||||||
|
# Get the vectors for the intersecting lines
|
||||||
|
z_axis = v1 * v2
|
||||||
|
line1 = [m1, v1 * z_axis]
|
||||||
|
line2 = [m2, v2 * z_axis]
|
||||||
|
# Return the center
|
||||||
|
Geom.intersect_line_line(line1, line2)
|
||||||
|
end
|
||||||
|
|
||||||
|
end # module TT::Arc
|
||||||
|
end
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
|
||||||
|
# Collection of AttributeDictionary methods.
|
||||||
|
#
|
||||||
|
# @since 2.5.0
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT::Attributes
|
||||||
|
|
||||||
|
# Compare two +AttributeDictionaries+ objects.
|
||||||
|
#
|
||||||
|
# @param [Sketchup::AttributeDictionaries] dictionaries1
|
||||||
|
# @param [Sketchup::AttributeDictionaries] dictionaries2
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.dictionaries_equal?( dictionaries1, dictionaries2 )
|
||||||
|
if dictionaries1.nil? || dictionaries2.nil?
|
||||||
|
if dictionaries1.nil? && dictionaries2.nil?
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for dictionary in dictionaries1
|
||||||
|
return false unless d = dictionaries2[ dictionary.name ]
|
||||||
|
return false unless self.dictionary_equal?( dictionary, d, false )
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Compare two +AttributeDictionary+ objects. By defaults their names must
|
||||||
|
# match, but one can set +compare_name+ to +false+ to only compare their
|
||||||
|
# content.
|
||||||
|
#
|
||||||
|
# @param [Sketchup::AttributeDictionary] dictionary1
|
||||||
|
# @param [Sketchup::AttributeDictionary] dictionary2
|
||||||
|
# @param [Boolean] compare_name
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.dictionary_equal?( dictionary1, dictionary2, compare_name = true )
|
||||||
|
if compare_name
|
||||||
|
return false unless dictionary1.name == dictionary2.name
|
||||||
|
end
|
||||||
|
return false unless dictionary1.length == dictionary2.length
|
||||||
|
return false unless dictionary1.keys == dictionary2.keys
|
||||||
|
for key in dictionary1.keys
|
||||||
|
return false unless dictionary1[key] == dictionary2[key]
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end # module TT::Attributes
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
|
||||||
|
# Translation dictionary. Pass strings through the +translate+ or +tr+ method
|
||||||
|
# to translate strings to the language given in to the last +load+ call.
|
||||||
|
#
|
||||||
|
# Silently eats errors and pass through the original string if a translation
|
||||||
|
# cannot be made.
|
||||||
|
#
|
||||||
|
# module MyPlugin
|
||||||
|
#
|
||||||
|
# # Assigning the instance to a constant makes it into
|
||||||
|
# # a easy to use shorthand that works in any sub-modules/classes.
|
||||||
|
# S = TT::Babelfish.new( l10n_path )
|
||||||
|
#
|
||||||
|
# def self.init
|
||||||
|
# S.load( 'fr' )
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.foo
|
||||||
|
# puts S.tr( 'Hello World' )
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# end # module
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# @since 2.5.0
|
||||||
|
module SpeckleConnector
|
||||||
|
class TT::Babelfish
|
||||||
|
|
||||||
|
# @since 2.5.0
|
||||||
|
attr_reader( :l10n, :default_l10n, :path, :file_ex )
|
||||||
|
|
||||||
|
# @param [String] l10n_path The path where the translation files are located.
|
||||||
|
# @param [String] default_l10n The source translation code.
|
||||||
|
# @param [String] file_ex The file extension of the translation files.
|
||||||
|
#
|
||||||
|
# @since 2.5.0
|
||||||
|
def initialize(l10n_path, default_l10n = 'en', file_ex = 'l10n')
|
||||||
|
@file_ex = file_ex.dup
|
||||||
|
@l10n = default_l10n.dup
|
||||||
|
@default_l10n = default_l10n.dup
|
||||||
|
@dictionary = {}
|
||||||
|
@metadata = {} # (!) Default data
|
||||||
|
|
||||||
|
path = File.expand_path( l10n_path )
|
||||||
|
unless File.exist?( path )
|
||||||
|
raise( ArgumentError, 'Path does not exist.' )
|
||||||
|
end
|
||||||
|
@path = path
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.5.0
|
||||||
|
def inspect
|
||||||
|
if @metadata
|
||||||
|
name = @metadata['name']
|
||||||
|
size = @dictionary.size
|
||||||
|
"<#{self.class}:#{@l10n} - Speaks #{size} phrases in #{name}>"
|
||||||
|
else
|
||||||
|
"<#{self.class}:#{@l10n}>"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# @return [Hash] A copy of the current translation dictionary.
|
||||||
|
# @since 2.5.0
|
||||||
|
def dictionary
|
||||||
|
@dictionary.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# @return [Hash] A copy of the current translation dictionary.
|
||||||
|
# @since 2.5.0
|
||||||
|
def metadata
|
||||||
|
@metadata.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Loads a translation dictionary.
|
||||||
|
#
|
||||||
|
# @param [String] l10n must represent the base name of a .l10n file in the
|
||||||
|
# language folder.
|
||||||
|
#
|
||||||
|
# @return [Boolean] +true+ on success, +false+ on failure.
|
||||||
|
# @since 2.5.0
|
||||||
|
def load(l10n)
|
||||||
|
# Special case for default language.
|
||||||
|
if l10n == @default_l10n
|
||||||
|
@l10n = @default_l10n
|
||||||
|
@metadata.clear # (!) Default data
|
||||||
|
@dictionary.clear
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
# Work out the filename and ensure it exists.
|
||||||
|
filename = File.join(@path, "#{l10n}.#{@file_ex}")
|
||||||
|
unless File.exists?(filename)
|
||||||
|
puts "Babelfish - Failed to load l10n: #{l10n} (#{filename}). No such file."
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
# Open the language file and parse the content. Unicode Regex ensures that
|
||||||
|
# UTF-8 files are parsed properly.
|
||||||
|
#
|
||||||
|
# Using a proxy hash prevents a failed appempt of loading a translation
|
||||||
|
# file from ruining the existing translation hash.
|
||||||
|
#
|
||||||
|
# Garbage data - data that doesn't match the expected format is ignored.
|
||||||
|
dictionary = {}
|
||||||
|
metadata = {}
|
||||||
|
File.open(filename, 'r') { |file|
|
||||||
|
metadata = read_metadata(file)
|
||||||
|
unless metadata
|
||||||
|
puts "Babelfish - Failed to load l10n: #{l10n} (#{filename}). Invalid data."
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
file.each { |line|
|
||||||
|
next if line.match(/^\s*#/u) # Ignore comments
|
||||||
|
next if line.match(/^\s*$/u) # Ignore empty lines
|
||||||
|
if match = line.match(/^\s*"(.*)"\s*=\s*"(.*)"\s*$/u)
|
||||||
|
dictionary[ match[1] ] = match[2]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@l10n = l10n.dup
|
||||||
|
@metadata = metadata
|
||||||
|
@dictionary = dictionary
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Looks up the string and returns a translated string.
|
||||||
|
# If no translated string exists, the original is returned.
|
||||||
|
#
|
||||||
|
# Silently outputs any errors to the console and returns the original
|
||||||
|
# string.
|
||||||
|
#
|
||||||
|
# @param [String] string
|
||||||
|
# @param [Array] args
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.5.0
|
||||||
|
def translate(string, *args)
|
||||||
|
translated = @dictionary[string] || string
|
||||||
|
sprintf(translated, *args)
|
||||||
|
rescue => e
|
||||||
|
p e.message
|
||||||
|
puts e.backtrace.join("\n")
|
||||||
|
sprintf(string, *args)
|
||||||
|
end
|
||||||
|
alias :tr :translate
|
||||||
|
|
||||||
|
|
||||||
|
# Used to handle singluar vs plural form.
|
||||||
|
#
|
||||||
|
# When +expression+ is a boolean, +true+ represent singular.
|
||||||
|
#
|
||||||
|
# @param [Numeric, Enumerable, Boolean] expression
|
||||||
|
# @param [String] singular
|
||||||
|
# @param [String] multiple
|
||||||
|
# @param [Array] args
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.12.0
|
||||||
|
def plural(expression, singular, multiple, *args)
|
||||||
|
single = false
|
||||||
|
case expression
|
||||||
|
when Numeric
|
||||||
|
single = expression.to_i == 1
|
||||||
|
when Enumerable
|
||||||
|
[:size, :length, :count].each { |symbol|
|
||||||
|
single = expression.send(symbol) == 1 if expression.respond_to?(symbol)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
single = !!expression
|
||||||
|
end
|
||||||
|
string = single ? singular : multiple
|
||||||
|
translate(string, *args)
|
||||||
|
end
|
||||||
|
alias :pl :plural
|
||||||
|
|
||||||
|
|
||||||
|
# Utility accessor to return a string without arguments.
|
||||||
|
#
|
||||||
|
# @param [String] string
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.12.0
|
||||||
|
def [](string)
|
||||||
|
translate(string)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Iterates the language folder for .l10n files and extracts the required
|
||||||
|
# display name in the first line of the file.
|
||||||
|
#
|
||||||
|
# Returns a hash of all the languages availible. The key is the translation
|
||||||
|
# code and the value is a hash with meta data.
|
||||||
|
#
|
||||||
|
# The meta data contains one required key: 'name' and optionally 'author'
|
||||||
|
# and/or 'contact'.
|
||||||
|
#
|
||||||
|
# {
|
||||||
|
# 'no' => {
|
||||||
|
# 'name' => '...'
|
||||||
|
# },
|
||||||
|
# 'fr' => {
|
||||||
|
# 'name' => '...',
|
||||||
|
# 'author' => '...',
|
||||||
|
# 'contact' => '...'
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# How to get an array of availible language codes:
|
||||||
|
# codes = babelfish.translations.keys
|
||||||
|
#
|
||||||
|
# Silently eats errors and output any errors or warnings to the console.
|
||||||
|
#
|
||||||
|
# @return [Hash]
|
||||||
|
# @since 2.5.0
|
||||||
|
def translations
|
||||||
|
lang = {}
|
||||||
|
file_filter = File.join(@path, "*.#{@file_ex}")
|
||||||
|
Dir.glob( file_filter ) { |filename|
|
||||||
|
lang_code = File.basename(filename, ".#{@file_ex}")
|
||||||
|
File.open(filename, 'r') { |file|
|
||||||
|
# UTF-8 files might have a BOM mark, account for this.
|
||||||
|
metadata = read_metadata(file)
|
||||||
|
if metadata
|
||||||
|
lang[lang_code] = metadata
|
||||||
|
else
|
||||||
|
puts "WARNING: No @title in #{filename}"
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lang # (?) This method appears to return false unless this is here...
|
||||||
|
rescue => e
|
||||||
|
p e.message
|
||||||
|
puts e.backtrace.join("\n")
|
||||||
|
ensure
|
||||||
|
lang
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Try to pick a language based on the Sketchup locale.
|
||||||
|
#
|
||||||
|
# 1. Tries exact matches.
|
||||||
|
# 2. Tries to find by language code, (if SU locale is en-GB) it tries to find
|
||||||
|
# "en.l10n".
|
||||||
|
# 3. Tries to find a similar dialect. (if SU locale is en-GB) it will consider
|
||||||
|
# "en-US.l10n" a match.
|
||||||
|
#
|
||||||
|
# (!)
|
||||||
|
# Norwegian is nn-NO and nb-NO, no
|
||||||
|
# This appear to be different from how English system works.
|
||||||
|
#
|
||||||
|
# http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo%28VS.80%29.aspx
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.5.0
|
||||||
|
def guess_l10n
|
||||||
|
su_locale = Sketchup.get_locale.downcase
|
||||||
|
# Extract list of languages availible
|
||||||
|
file_filter = File.join( @path, "*.#{@file_ex}" )
|
||||||
|
languages = Dir.glob( file_filter ).map { |filename|
|
||||||
|
File.basename(filename, ".#{@file_ex}").downcase
|
||||||
|
}
|
||||||
|
# First search for exact match
|
||||||
|
for lang_code in languages
|
||||||
|
return lang_code if lang_code == su_locale
|
||||||
|
end
|
||||||
|
# Search for partial match - language code
|
||||||
|
su_country = su_locale.split('-').first
|
||||||
|
for lang_code in languages
|
||||||
|
return lang_code if lang_code == su_country
|
||||||
|
end
|
||||||
|
# Search for partial match - language code and dialect
|
||||||
|
for lang_code in languages
|
||||||
|
country = lang_code.split('-').first
|
||||||
|
return lang_code if country == su_country
|
||||||
|
end
|
||||||
|
# Default
|
||||||
|
return @default_l10n
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Debug method that compares the availible translations against a spesified
|
||||||
|
# prototype. Outputs the result to the Console.
|
||||||
|
#
|
||||||
|
# @param [String] prototype_l10n The translation to compare against.
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.5.0
|
||||||
|
def check(prototype_l10n)
|
||||||
|
puts "\nChecking language files for missing strings against #{prototype_l10n}..."
|
||||||
|
|
||||||
|
prototype = self.new( @path, @default_l10n )
|
||||||
|
prototype.load( prototype_l10n )
|
||||||
|
|
||||||
|
temp = self.new( @path, @default_l10n )
|
||||||
|
|
||||||
|
keys = prototype.dictionary.keys
|
||||||
|
|
||||||
|
prototype.translations.each { |code, data|
|
||||||
|
next if code == prototype_l10n
|
||||||
|
temp.load(code)
|
||||||
|
puts "\n=== #{data['name']} (#{code}) ==="
|
||||||
|
missing = keys - temp.dictionary.keys
|
||||||
|
puts "> Missing #{missing.length} keys:"
|
||||||
|
missing.each { |str| p str }
|
||||||
|
}
|
||||||
|
|
||||||
|
self.load(org)
|
||||||
|
"\nDone\n\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def read_metadata(file)
|
||||||
|
match = file.readline.match(/^(?:\xEF\xBB\xBF)?@title:\s*"(.+)"/u)
|
||||||
|
return nil if match.nil?
|
||||||
|
# Language data is read into a hash
|
||||||
|
lang_data = {
|
||||||
|
'author' => 'unknown',
|
||||||
|
'contact' => ''
|
||||||
|
}
|
||||||
|
# The Name is required and MUST be the first line in the file.
|
||||||
|
lang_data['name'] = match[1]
|
||||||
|
# The next following lines are optional and can be in any order,
|
||||||
|
# but with comments or skipped lines.
|
||||||
|
2.times {
|
||||||
|
match = file.readline.match(/@(\w+):\s*"(.+)"/u)
|
||||||
|
if match && ['author','contact'].include?(match[1])
|
||||||
|
lang_data[ match[1] ] = match[2]
|
||||||
|
end
|
||||||
|
}
|
||||||
|
lang_data
|
||||||
|
end
|
||||||
|
|
||||||
|
end # class TT::Babelfish
|
||||||
|
end
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# This file exist only as a compatibility with older version of TT_Lib when
|
||||||
|
# the implementation was in pure Ruby. It also ensures the correct version for
|
||||||
|
# the platform is loaded.
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
require File.join( SpeckleConnector::TT::Lib::PATH_LIBS_CEXT, 'tt_lib2' )
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
|
||||||
|
# ...
|
||||||
|
#
|
||||||
|
# @since 2.4.0
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT::Binary
|
||||||
|
|
||||||
|
# Base64 encodes binary data.
|
||||||
|
#
|
||||||
|
# @param [Mixed] data
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.4.0
|
||||||
|
def self.encode64(data)
|
||||||
|
return [data].pack('m')
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Decodes Base64 strings.
|
||||||
|
#
|
||||||
|
# @param [String] string
|
||||||
|
#
|
||||||
|
# @return [Mixed]
|
||||||
|
# @since 2.4.0
|
||||||
|
def self.decode64(string)
|
||||||
|
return string.unpack('m')[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
end # module TT::Binary
|
||||||
|
end
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
|
||||||
|
# @example
|
||||||
|
# class Foo
|
||||||
|
# extend TT::BooleanAttributes
|
||||||
|
# battr_accessor :bar
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# @since 2.7.0
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT::BooleanAttributes
|
||||||
|
|
||||||
|
# @since 2.7.0
|
||||||
|
def battr( symbol, writable = false )
|
||||||
|
self.class_eval {
|
||||||
|
attr( symbol, writable )
|
||||||
|
question = "#{symbol}?".to_sym
|
||||||
|
alias_method( question, symbol )
|
||||||
|
remove_method( symbol )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# @since 2.7.0
|
||||||
|
def battr_accessor( *args )
|
||||||
|
self.class_eval {
|
||||||
|
attr_accessor( *args )
|
||||||
|
for attribute in args
|
||||||
|
question = "#{attribute}?".to_sym
|
||||||
|
alias_method( question, attribute )
|
||||||
|
remove_method( attribute )
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# @since 2.7.0
|
||||||
|
def battr_reader( *args )
|
||||||
|
self.class_eval {
|
||||||
|
attr_reader( *args )
|
||||||
|
for attribute in args
|
||||||
|
question = "#{attribute}?".to_sym
|
||||||
|
alias_method( question, attribute )
|
||||||
|
remove_method( attribute )
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
end # class TT::BooleanAttributes
|
||||||
|
end
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
|
||||||
|
# Collection of BoundingBox methods.
|
||||||
|
#
|
||||||
|
# @since 2.2.0
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT::Bounds
|
||||||
|
|
||||||
|
# Returns a +Point3d+ from a standard position of the boundingbox.
|
||||||
|
#
|
||||||
|
# @param [Geom::BoundingBox] bounds
|
||||||
|
# @param [Integer] index
|
||||||
|
#
|
||||||
|
# @return [Geom::Point3d]
|
||||||
|
# @since 2.2.0
|
||||||
|
def self.point(bounds, index)
|
||||||
|
case index
|
||||||
|
when 0..7
|
||||||
|
pt = bounds.corner(index)
|
||||||
|
|
||||||
|
when TT::BB_CENTER_FRONT_BOTTOM
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_FRONT_BOTTOM )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_CENTER_BACK_BOTTOM
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_BACK_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_BOTTOM )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_CENTER_FRONT_TOP
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_TOP )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_FRONT_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_CENTER_BACK_TOP
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_BACK_TOP )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
|
||||||
|
when TT::BB_LEFT_CENTER_BOTTOM
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_LEFT_BACK_BOTTOM )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_LEFT_CENTER_TOP
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_TOP )
|
||||||
|
p2 = bounds.corner( TT::BB_LEFT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_RIGHT_CENTER_BOTTOM
|
||||||
|
p1 = bounds.corner( TT::BB_RIGHT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_BOTTOM )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_RIGHT_CENTER_TOP
|
||||||
|
p1 = bounds.corner( TT::BB_RIGHT_FRONT_TOP )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
|
||||||
|
when TT::BB_LEFT_FRONT_CENTER
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_LEFT_FRONT_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_RIGHT_FRONT_CENTER
|
||||||
|
p1 = bounds.corner( TT::BB_RIGHT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_FRONT_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_LEFT_BACK_CENTER
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_BACK_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_LEFT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_RIGHT_BACK_CENTER
|
||||||
|
p1 = bounds.corner( TT::BB_RIGHT_BACK_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
|
||||||
|
when TT::BB_LEFT_CENTER_CENTER
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_LEFT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_RIGHT_CENTER_CENTER
|
||||||
|
p1 = bounds.corner( TT::BB_RIGHT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_CENTER_FRONT_CENTER
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_FRONT_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_CENTER_BACK_CENTER
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_BACK_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_CENTER_CENTER_TOP
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_TOP )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_TOP )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
when TT::BB_CENTER_CENTER_BOTTOM
|
||||||
|
p1 = bounds.corner( TT::BB_LEFT_FRONT_BOTTOM )
|
||||||
|
p2 = bounds.corner( TT::BB_RIGHT_BACK_BOTTOM )
|
||||||
|
pt = Geom.linear_combination( 0.5, p1, 0.5, p2 )
|
||||||
|
|
||||||
|
when TT::BB_CENTER_CENTER_CENTER
|
||||||
|
pt = bounds.center
|
||||||
|
end
|
||||||
|
|
||||||
|
pt
|
||||||
|
end
|
||||||
|
|
||||||
|
end # module TT::Bounds
|
||||||
|
end
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT
|
||||||
|
|
||||||
|
# Loads the appropriate C Extension loader after ensuring the appropriate
|
||||||
|
# version has been copied from the staging area.
|
||||||
|
#
|
||||||
|
# @since 2.9.0
|
||||||
|
class CExtensionManager
|
||||||
|
|
||||||
|
class IncompatibleVersion < RuntimeError; end
|
||||||
|
|
||||||
|
VERSION_PATTERN = /\d+\.\d+\.\d+$/
|
||||||
|
|
||||||
|
# The `path` argument should point to the path where a 'stage' folder is
|
||||||
|
# located with the following folder structure:
|
||||||
|
#
|
||||||
|
# + `path`
|
||||||
|
# +-+ stage
|
||||||
|
# +-+ 1.8
|
||||||
|
# | +-+ HelloWorld.so
|
||||||
|
# | + HelloWorld.bundle
|
||||||
|
# +-+ 2.0
|
||||||
|
# +-+ HelloWorld.so
|
||||||
|
# + HelloWorld.bundle
|
||||||
|
#
|
||||||
|
# The appropriate file will be copied on demand to a folder structure like:
|
||||||
|
# `path`/<EXTENSION_VERSION>/<RUBY_VERSION>/HelloWorld.so
|
||||||
|
#
|
||||||
|
# When a new version is deployed the files will be copied again from the
|
||||||
|
# staging area to a new folder named with the new extension version.
|
||||||
|
#
|
||||||
|
# The old versions are cleaned up if possible. This attempt is done upon
|
||||||
|
# each time #prepare_path is called.
|
||||||
|
#
|
||||||
|
# This way the C extensions can be updated because they are never loaded
|
||||||
|
# from the staging folder directly.
|
||||||
|
#
|
||||||
|
# @param [String] path The location where the C Extensions are located.
|
||||||
|
# @since 2.9.0
|
||||||
|
def initialize( path, version )
|
||||||
|
# ENV, __FILE__, $LOAD_PATH, $LOADED_FEATURE and more might return an
|
||||||
|
# encoding different from UTF-8. It's often ASCII-US or ASCII-8BIT.
|
||||||
|
# If the developer has derived from these strings the encoding sticks with
|
||||||
|
# it and will often lead to errors further down the road when trying to
|
||||||
|
# load the files. To work around this the path is attempted to be
|
||||||
|
# relabeled as UTF-8 if we can produce a valid UTF-8 string.
|
||||||
|
# I'm forcing an encoding instead of converting because the encoding label
|
||||||
|
# of the strings seem to be consistently mislabeled - the data is in
|
||||||
|
# fact UTF-8.
|
||||||
|
if path.respond_to?(:encoding)
|
||||||
|
test_path = path.dup.force_encoding("UTF-8")
|
||||||
|
path = test_path if test_path.valid_encoding?
|
||||||
|
end
|
||||||
|
|
||||||
|
unless version =~ VERSION_PATTERN
|
||||||
|
raise ArgumentError, 'Version must be in "X.Y.Z" format'
|
||||||
|
end
|
||||||
|
unless File.directory?( path )
|
||||||
|
raise IOError, "Stage path not found: #{path}"
|
||||||
|
end
|
||||||
|
|
||||||
|
@version = version
|
||||||
|
@path = path
|
||||||
|
@stage = File.join( path, 'stage' )
|
||||||
|
@target = File.join( path, version )
|
||||||
|
|
||||||
|
@log = []
|
||||||
|
|
||||||
|
# See method comments for more info.
|
||||||
|
#require_file_utils()
|
||||||
|
end
|
||||||
|
|
||||||
|
# Copies the necessary C Extension libraries to a version dependent folder
|
||||||
|
# from where they can be loaded. This will allow the SketchUp RBZ installer
|
||||||
|
# to update the extension without running into errors when trying to
|
||||||
|
# overwrite files from previous installation.
|
||||||
|
#
|
||||||
|
# @return [String] The path where the extensions are located.
|
||||||
|
# @since 2.9.0
|
||||||
|
def prepare_path
|
||||||
|
log("prepare_path")
|
||||||
|
|
||||||
|
pointer_size = ['a'].pack('P').size * 8 # 32 or 64
|
||||||
|
ruby = RUBY_VERSION.split('.')[0..1].join('.') # Get Major.Minor string.
|
||||||
|
platform = ( TT::System::PLATFORM_IS_OSX ) ? 'osx' : 'win'
|
||||||
|
platform = "#{platform}#{pointer_size}"
|
||||||
|
stage_path = File.join( @stage, ruby, platform )
|
||||||
|
target_path = File.join( @target, ruby, platform )
|
||||||
|
fallback = false
|
||||||
|
|
||||||
|
log("> stage_path: #{stage_path}")
|
||||||
|
log("> target_path: #{target_path}")
|
||||||
|
|
||||||
|
begin
|
||||||
|
# Copy files if target doesn't exist.
|
||||||
|
unless File.directory?(stage_path)
|
||||||
|
raise IncompatibleVersion, "Staging directory not found: #{stage_path}"
|
||||||
|
end
|
||||||
|
unless File.directory?( target_path )
|
||||||
|
log("MKDIR: #{target_path}")
|
||||||
|
require_file_utils() # See method comments for more info.
|
||||||
|
log(FileUtils.mkdir_p( target_path ))
|
||||||
|
end
|
||||||
|
stage_content = Dir.entries( stage_path )
|
||||||
|
target_content = Dir.entries( target_path )
|
||||||
|
log("> stage_content: #{stage_content}")
|
||||||
|
log("> target_content: #{target_content}")
|
||||||
|
unless (stage_content - target_content).empty?
|
||||||
|
log("COPY: #{stage_path} => #{target_path}")
|
||||||
|
require_file_utils() # See method comments for more info.
|
||||||
|
log(FileUtils.copy_entry( stage_path, target_path ))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Clean up old versions.
|
||||||
|
version_pattern = /\d+\.\d+\.\d+$/
|
||||||
|
filter = File.join( @path, '*' )
|
||||||
|
log("> cleanup: #{filter}")
|
||||||
|
Dir.glob( filter ).each { |entry|
|
||||||
|
log(">>> entry: #{entry}")
|
||||||
|
next unless File.directory?( entry )
|
||||||
|
log(">>> @target: #{@target} (#{entry.downcase == @target.downcase})")
|
||||||
|
log(">>> @stage: #{@stage} (#{entry.downcase == @stage.downcase})")
|
||||||
|
log(">>>>> @target vs entry")
|
||||||
|
log(">>>>> #{entry.class.name}: #{entry.bytes}") if entry.respond_to?(:bytes)
|
||||||
|
log(">>>>> #{@target.class.name}: #{@target.bytes}") if @target.respond_to?(:bytes)
|
||||||
|
next if entry.downcase == @stage.downcase || entry.downcase == @target.downcase
|
||||||
|
log(">>> match: #{entry =~ version_pattern}")
|
||||||
|
next unless entry =~ version_pattern
|
||||||
|
begin
|
||||||
|
log("REMOVE: #{entry}")
|
||||||
|
require_file_utils # See method comments for more info.
|
||||||
|
log(FileUtils.rm_r( entry ))
|
||||||
|
rescue
|
||||||
|
log_warn("#{TT::Lib::PLUGIN_NAME} - Unable to clean up: #{entry}")
|
||||||
|
end
|
||||||
|
}
|
||||||
|
rescue Errno::EACCES
|
||||||
|
if fallback
|
||||||
|
UI.messagebox(
|
||||||
|
"Failed to load #{TT::Lib::PLUGIN_NAME}. Missing permissions to " <<
|
||||||
|
"Plugins and temp folder."
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
else
|
||||||
|
# Even though the temp folder contains the username, it appear to be
|
||||||
|
# returned in DOS 8.3 format which Ruby 1.8 can open. Fall back to
|
||||||
|
# using the temp folder for these kind of systems.
|
||||||
|
log_warn("#{TT::Lib::PLUGIN_NAME} - Unable to access: #{target_path}")
|
||||||
|
temp_tt_lib_path = File.join( temp_path, TT::Lib::PLUGIN_ID )
|
||||||
|
target_path = File.join( temp_tt_lib_path, @version, ruby, platform )
|
||||||
|
log_warn("#{TT::Lib::PLUGIN_NAME} - Falling back to: #{target_path}")
|
||||||
|
fallback = true
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
target_path
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.9.0
|
||||||
|
def to_s
|
||||||
|
object_hex_id = "0x%x" % (self.object_id << 1)
|
||||||
|
"<##{self.class}::#{object_hex_id}>"
|
||||||
|
end
|
||||||
|
alias :inspect :to_s
|
||||||
|
|
||||||
|
# @since 2.10.7
|
||||||
|
def print_log
|
||||||
|
puts @log.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# @since 2.10.7
|
||||||
|
def log(value)
|
||||||
|
string = value.is_a?(String) ? value : value.inspect
|
||||||
|
@log << string
|
||||||
|
string
|
||||||
|
end
|
||||||
|
|
||||||
|
# @since 2.10.7
|
||||||
|
def log_warn(value)
|
||||||
|
puts log(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return the system temp path from the environment variables.
|
||||||
|
#
|
||||||
|
# @since 2.10.7
|
||||||
|
def temp_path
|
||||||
|
File.expand_path( ENV['TMPDIR'] || ENV['TMP'] || ENV['TEMP'] )
|
||||||
|
end
|
||||||
|
|
||||||
|
# Attempt to load the Standard Library FileUtils module. Fall back to
|
||||||
|
# bundled 1.8 copy.
|
||||||
|
#
|
||||||
|
# @since 2.9.0
|
||||||
|
def require_file_utils
|
||||||
|
if RUBY_VERSION.to_i == 1
|
||||||
|
path = File.dirname( __FILE__ ) # rubocop:disable SketchupSuggestions/FileEncoding
|
||||||
|
require File.join( path, 'thirdparty', 'fileutils.rb' )
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
require 'fileutils'
|
||||||
|
rescue LoadError
|
||||||
|
# A bug in SketchUp 2014 M0 caused the drive letter for the Ruby
|
||||||
|
# Standard Library to be incorrect if SketchUp was started by
|
||||||
|
# clicking a SKP file on a drive (network drive?) different from
|
||||||
|
# where SketchUp was installed.
|
||||||
|
#
|
||||||
|
# This cause the fileutils to fail to load. To work around this the
|
||||||
|
# file is required right before it is needed. That should make the
|
||||||
|
# file needed only the first time after installing a new version.
|
||||||
|
# Makes the code awkward and ugly, but alas. :(
|
||||||
|
std_lib_path = Sketchup.find_support_file( 'Tools/RubyStdLib' ) # rubocop:disable SketchupSuggestions/SketchupFindSupportFile
|
||||||
|
unless $LOAD_PATH.include?( std_lib_path )
|
||||||
|
UI.messagebox(
|
||||||
|
'Due to a bug in SketchUp 2014 M0 the standard library was ' <<
|
||||||
|
'not loaded. Please start SketchUp from a link on the drive ' <<
|
||||||
|
'it was installed to instead of from clicking an SKP on a ' <<
|
||||||
|
'different drive.'
|
||||||
|
) unless @load_error_displayed
|
||||||
|
@load_error_displayed = true
|
||||||
|
end
|
||||||
|
puts $LOAD_PATH.join("\n")
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
end # if RUBY_VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
end # class
|
||||||
|
|
||||||
|
end # module
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
|
||||||
|
# Collection of Color methods.
|
||||||
|
#
|
||||||
|
# @since 2.5.0
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT::Color
|
||||||
|
|
||||||
|
# Safely clones a Sketchup::Color object. Sketchup::Color.clone appear to
|
||||||
|
# be bugged and prone to crash SU.
|
||||||
|
#
|
||||||
|
# @param [Sketchup::Color] color
|
||||||
|
#
|
||||||
|
# @return [Sketchup::Color]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.clone(color)
|
||||||
|
Sketchup::Color.new( *color.to_a )
|
||||||
|
end
|
||||||
|
|
||||||
|
end # module TT::Instance
|
||||||
|
end
|
||||||
@@ -0,0 +1,537 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Sketchup::require 'sketchup.rb'
|
||||||
|
# Sketchup::require '../TT_Lib2.rb'
|
||||||
|
require_relative 'system.rb'
|
||||||
|
require_relative 'c_extension_manager.rb'
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Root namespace for Thomas Thomassen (ThomThom, TT)
|
||||||
|
#
|
||||||
|
# Do not modify or extend!
|
||||||
|
#
|
||||||
|
# @since 2.0.0
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT
|
||||||
|
|
||||||
|
### CONSTANTS ### ------------------------------------------------------------
|
||||||
|
|
||||||
|
# BoundingBox Constants
|
||||||
|
# @since 2.0.0
|
||||||
|
|
||||||
|
BB_LEFT_FRONT_BOTTOM = 0
|
||||||
|
BB_RIGHT_FRONT_BOTTOM = 1
|
||||||
|
BB_LEFT_BACK_BOTTOM = 2
|
||||||
|
BB_RIGHT_BACK_BOTTOM = 3
|
||||||
|
BB_LEFT_FRONT_TOP = 4
|
||||||
|
BB_RIGHT_FRONT_TOP = 5
|
||||||
|
BB_LEFT_BACK_TOP = 6
|
||||||
|
BB_RIGHT_BACK_TOP = 7
|
||||||
|
|
||||||
|
BB_CENTER_FRONT_BOTTOM = 8
|
||||||
|
BB_CENTER_BACK_BOTTOM = 9
|
||||||
|
BB_CENTER_FRONT_TOP = 10
|
||||||
|
BB_CENTER_BACK_TOP = 11
|
||||||
|
|
||||||
|
BB_LEFT_CENTER_BOTTOM = 12
|
||||||
|
BB_LEFT_CENTER_TOP = 13
|
||||||
|
BB_RIGHT_CENTER_BOTTOM = 14
|
||||||
|
BB_RIGHT_CENTER_TOP = 15
|
||||||
|
|
||||||
|
BB_LEFT_FRONT_CENTER = 16
|
||||||
|
BB_RIGHT_FRONT_CENTER = 17
|
||||||
|
BB_LEFT_BACK_CENTER = 18
|
||||||
|
BB_RIGHT_BACK_CENTER = 19
|
||||||
|
|
||||||
|
BB_LEFT_CENTER_CENTER = 20
|
||||||
|
BB_RIGHT_CENTER_CENTER = 21
|
||||||
|
BB_CENTER_FRONT_CENTER = 22
|
||||||
|
BB_CENTER_BACK_CENTER = 23
|
||||||
|
BB_CENTER_CENTER_TOP = 24
|
||||||
|
BB_CENTER_CENTER_BOTTOM = 25
|
||||||
|
|
||||||
|
BB_CENTER_CENTER_CENTER = 26
|
||||||
|
BB_CENTER = 26
|
||||||
|
|
||||||
|
# UI.messagebox Constants
|
||||||
|
# @since 2.4.0
|
||||||
|
|
||||||
|
MB_ICONHAND = 0x00000010
|
||||||
|
MB_ICONSTOP = 0x00000010
|
||||||
|
MB_ICONERROR = 0x00000010
|
||||||
|
MB_ICONQUESTION = 0x00000020
|
||||||
|
MB_ICONEXCLAMATION = 0x00000030
|
||||||
|
MB_ICONWARNING = 0x00000030
|
||||||
|
MB_ICONASTERISK = 0x00000040
|
||||||
|
MB_ICONINFORMATION = 0x00000040
|
||||||
|
MB_ICON_NONE = 80
|
||||||
|
|
||||||
|
MB_DEFBUTTON1 = 0x00000000
|
||||||
|
MB_DEFBUTTON2 = 0x00000100
|
||||||
|
MB_DEFBUTTON3 = 0x00000200
|
||||||
|
MB_DEFBUTTON4 = 0x00000300
|
||||||
|
|
||||||
|
# PolygonMesh
|
||||||
|
# @since 2.5.0
|
||||||
|
|
||||||
|
MESH_SHARP = 0
|
||||||
|
MESH_SOFT = 4
|
||||||
|
MESH_SMOOTH = 8
|
||||||
|
MESH_SOFT_SMOOTH = 12
|
||||||
|
|
||||||
|
# view.draw_points
|
||||||
|
# @since 2.5.0
|
||||||
|
|
||||||
|
POINT_OPEN_SQUARE = 1
|
||||||
|
POINT_FILLED_SQUARE = 2
|
||||||
|
POINT_CROSS = 3
|
||||||
|
POINT_X = 4
|
||||||
|
POINT_STAR = 5
|
||||||
|
POINT_OPEN_TRIANGLE = 6
|
||||||
|
POINT_FILLED_TRIANGLE = 7
|
||||||
|
|
||||||
|
# Handle to error message window.
|
||||||
|
# @since 2.7.0
|
||||||
|
@lib2_update = nil
|
||||||
|
def self.lib2_update; @lib2_update; end
|
||||||
|
def self.lib2_update=(window); @lib2_update = window; end
|
||||||
|
|
||||||
|
|
||||||
|
# Defers execution of the given block.
|
||||||
|
#
|
||||||
|
# @param [Numeric] time
|
||||||
|
#
|
||||||
|
# @return [Nil]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.defer( time = 0 )
|
||||||
|
done = false
|
||||||
|
timer = UI.start_timer( time, false ) {
|
||||||
|
# (i) Unless the timer is stopped before the messagebox it will
|
||||||
|
# continue to trigger until the frist messagebox is closed.
|
||||||
|
unless done
|
||||||
|
done = true
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
}
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
### LIBRARY ### --------------------------------------------------------------
|
||||||
|
|
||||||
|
# TT_Lib related methods.
|
||||||
|
#
|
||||||
|
# @since 2.0.0
|
||||||
|
module Lib
|
||||||
|
|
||||||
|
# Library version number.
|
||||||
|
# @since 2.0.0
|
||||||
|
VERSION = PLUGIN_VERSION
|
||||||
|
|
||||||
|
# Library preference key.
|
||||||
|
# @since 2.5.0
|
||||||
|
PREF_KEY = 'TT_Lib2'.freeze
|
||||||
|
|
||||||
|
# @since 2.8.0
|
||||||
|
file = File.expand_path( __FILE__ ) # rubocop:disable SketchupSuggestions/FileEncoding
|
||||||
|
file.force_encoding( "UTF-8" ) if file.respond_to?( :force_encoding )
|
||||||
|
PATH = File.dirname( file ).freeze
|
||||||
|
PATH_LIBS = File.join( PATH, 'libraries' ).freeze
|
||||||
|
|
||||||
|
# TT::Lib.cext_manager
|
||||||
|
def self.cext_manager; @cext_manager; end
|
||||||
|
begin
|
||||||
|
@cext_manager = CExtensionManager.new( PATH_LIBS, PLUGIN_VERSION )
|
||||||
|
PATH_LIBS_CEXT = @cext_manager.prepare_path.freeze
|
||||||
|
rescue CExtensionManager::IncompatibleVersion => error
|
||||||
|
unless @compatibility_alert
|
||||||
|
# Avoid this message being called for every extension that rely on TT_Lib.
|
||||||
|
@compatibility_alert = true
|
||||||
|
message = "%{extension_name} version %{version} is not "\
|
||||||
|
"compatible with this version of SketchUp and could not be loaded. "\
|
||||||
|
"Please check for updates to the extension."
|
||||||
|
message %= { extension_name: PLUGIN_NAME, version: PLUGIN_VERSION }
|
||||||
|
TT.defer(1.0) {
|
||||||
|
UI.messagebox(message)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Call this method to check if the installed +TT_Lib+ version is the same
|
||||||
|
# or newer than +version+. If it's not then a messagebox will appear
|
||||||
|
# informing the user that a newer +TT_Lib+ is required.
|
||||||
|
#
|
||||||
|
# @param [String] version a string with the minimun version required in
|
||||||
|
# the format 'x.x.x'.
|
||||||
|
# @param [String] plugin_name a string describing to the user which plugin
|
||||||
|
# require a newer TT_Lib version.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
# @since 2.0.0
|
||||||
|
def self.compatible?(version, plugin_name = 'A plugin installed')
|
||||||
|
major, minor, revision = TT::Lib::VERSION.split('.').map { |s| s.to_i }
|
||||||
|
min_major, min_minor, min_revision = version.split('.').map { |s| s.to_i }
|
||||||
|
return true if major > min_major
|
||||||
|
return true if major == min_major && minor > min_minor
|
||||||
|
return true if major == min_major && minor == min_minor && revision >= min_revision
|
||||||
|
#UI.messagebox("#{plugin_name} requires a newer version, #{version}, of TT_Lib.")
|
||||||
|
if TT.lib2_update.nil?
|
||||||
|
url = 'http://www.thomthom.net/software/sketchup/tt_lib2/errors/outdated'
|
||||||
|
options = {
|
||||||
|
:dialog_title => 'TT_Lib² Outdated',
|
||||||
|
:scrollable => false, :resizable => false, :left => 200, :top => 200
|
||||||
|
}
|
||||||
|
w = UI::WebDialog.new( options )
|
||||||
|
w.set_size( 500, 300 )
|
||||||
|
arguments = "plugin=#{plugin_name}"
|
||||||
|
arguments << "&version=#{TT::Lib::VERSION}"
|
||||||
|
arguments << "&minimum=#{version}"
|
||||||
|
w.set_url( "#{url}?#{arguments}" )
|
||||||
|
w.show
|
||||||
|
TT.lib2_update = w
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Compiles a list of the current .rb and .rbs files in the library. This is
|
||||||
|
# used to verify the integirty of the installation upon first run.
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @return [Nil]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.compile_integrity_list
|
||||||
|
result = UI.messagebox( <<MSG, MB_OKCANCEL )
|
||||||
|
This method is only intended for development purposes. Don't mess about with it!
|
||||||
|
Press Cancel.
|
||||||
|
MSG
|
||||||
|
#'# Silly Sublime Text doesn't handle HereDoc arguments properly.
|
||||||
|
return if result == 2 # CANCEL
|
||||||
|
|
||||||
|
files = Dir.glob( File.join(self.path, '*.{rb,rbs}') ).map! { |file|
|
||||||
|
File.basename( file )
|
||||||
|
}
|
||||||
|
|
||||||
|
File.open( self.integrity_check_file, 'w' ) { |output|
|
||||||
|
output.puts( files )
|
||||||
|
}
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# @private
|
||||||
|
# @since 2.9.5
|
||||||
|
class IntegrityCheck
|
||||||
|
|
||||||
|
attr_reader :unexpected_files, :missing_files
|
||||||
|
|
||||||
|
def initialize( file_with_list_of_expected_files )
|
||||||
|
integrity_file = file_with_list_of_expected_files
|
||||||
|
@expected_files = IO.readlines( integrity_file ).map! { |file|
|
||||||
|
file.strip
|
||||||
|
}
|
||||||
|
|
||||||
|
@missing_files = @expected_files.select { |file|
|
||||||
|
filename = File.join( PATH, file )
|
||||||
|
!File.exist?( filename )
|
||||||
|
}
|
||||||
|
|
||||||
|
filter = File.join(PATH, '*.{rb,rbs}' )
|
||||||
|
@existing_files = Dir.glob( filter ).map! { |file|
|
||||||
|
File.basename( file )
|
||||||
|
}
|
||||||
|
@unexpected_files = @existing_files - @expected_files
|
||||||
|
end
|
||||||
|
|
||||||
|
def ok?
|
||||||
|
@missing_files.empty? && @unexpected_files.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def missing_files?
|
||||||
|
!@missing_files.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def unexpected_files?
|
||||||
|
!@unexpected_files.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
end # class IntegrityCheck
|
||||||
|
|
||||||
|
|
||||||
|
# Called upon startup. If it's the first time this library is loaded a file
|
||||||
|
# integrity check is run to ensure all requires files are present, and that
|
||||||
|
# there are no old remains in case of an update.
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @return [Boolean]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.integrity_check
|
||||||
|
version = "VerifiedIntegrity-#{self::VERSION}"
|
||||||
|
verified = ::Sketchup.read_default( PREF_KEY, version )
|
||||||
|
return true if verified
|
||||||
|
|
||||||
|
integrity = IntegrityCheck.new( self.integrity_check_file )
|
||||||
|
|
||||||
|
if integrity.ok?
|
||||||
|
::Sketchup.write_default( PREF_KEY, version, true )
|
||||||
|
true
|
||||||
|
else
|
||||||
|
message = <<MSG
|
||||||
|
TT_Lib² appear to be incorrectly installed. Please remove TT_Lib² and then
|
||||||
|
install it again. If this error message persist, contant the author for
|
||||||
|
assistance.
|
||||||
|
MSG
|
||||||
|
message.gsub!( /\s+/, ' ' ) # Collapse whitespace.
|
||||||
|
|
||||||
|
if integrity.missing_files?
|
||||||
|
missing_files = integrity.missing_files.join("\n")
|
||||||
|
message << "\n\nMissing files:\n" << missing_files
|
||||||
|
end
|
||||||
|
|
||||||
|
if integrity.unexpected_files?
|
||||||
|
unexpected_files = integrity.unexpected_files.join("\n")
|
||||||
|
message << "\n\nUnexpected files found:\n" << unexpected_files
|
||||||
|
end
|
||||||
|
|
||||||
|
# Defer execution to allow remaining plugins to load.
|
||||||
|
TT.defer { UI.messagebox( message, MB_OK ) }
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Checks for VirtualStore conflict.
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @return [Nil]
|
||||||
|
# @since 2.9.0
|
||||||
|
def self.virtualstore_check
|
||||||
|
return nil unless TT::System.is_windows?
|
||||||
|
require 'TT_Lib2/win32.rb'
|
||||||
|
plugins_folder = Sketchup.find_support_file( 'Plugins' ) # rubocop:disable SketchupSuggestions/SketchupFindSupportFile
|
||||||
|
virtual_folder = TT::System.get_virtual_file( plugins_folder )
|
||||||
|
return nil if virtual_folder.nil?
|
||||||
|
return nil if plugins_folder == virtual_folder
|
||||||
|
return nil unless File.exist?( virtual_folder )
|
||||||
|
if Dir.entries( virtual_folder ).to_a.size > 2
|
||||||
|
message = <<MSG
|
||||||
|
TT_Lib² detected that some of the files in SketchUp's plugin folder has ended up
|
||||||
|
in Window's Virtual Store. It happens because of insufficint permissions for the
|
||||||
|
plugin folder. Please move the files into the real Plugins folder.
|
||||||
|
MSG
|
||||||
|
message.gsub!( /\s+/, ' ' ) # Collapse whitespace.
|
||||||
|
# Defer execution to allow remaining plugins to load.
|
||||||
|
TT.defer {
|
||||||
|
result = UI.messagebox( message, MB_OKCANCEL )
|
||||||
|
if result == IDOK
|
||||||
|
UI.openURL( virtual_folder )
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the full path to the integrity file.
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @return [Nil]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.integrity_check_file
|
||||||
|
File.join( self.path, 'integrity_list.dat' )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# @return [String] The file path where the library is installed.
|
||||||
|
# @since 2.0.0
|
||||||
|
def self.path
|
||||||
|
PATH.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Debug method to reload the library modules.
|
||||||
|
#
|
||||||
|
# @param [Boolean] return_files Determines if the method should return
|
||||||
|
# the number of files reloaded or an array of the files reloaded.
|
||||||
|
#
|
||||||
|
# @return [Integer, Array]
|
||||||
|
# @since 2.0.0
|
||||||
|
def self.reload( return_files=false )
|
||||||
|
original_verbose = $VERBOSE
|
||||||
|
$VERBOSE = nil # Mute warnings caused by constant redefining.
|
||||||
|
x = Dir.glob( File.join(self.path, '*.{rb,rbs}') ).each { |file|
|
||||||
|
load file
|
||||||
|
}
|
||||||
|
(return_files) ? x : x.length
|
||||||
|
ensure
|
||||||
|
$VERBOSE = original_verbose
|
||||||
|
end
|
||||||
|
|
||||||
|
end # module TT::Lib
|
||||||
|
|
||||||
|
|
||||||
|
### MENUS ### ----------------------------------------------------------------
|
||||||
|
|
||||||
|
# If TT's Menu is installed this method will return a custom Menu item
|
||||||
|
# instead of the requested root menu.
|
||||||
|
#
|
||||||
|
# @param [String] name The prefered root menu in Sketchup.
|
||||||
|
#
|
||||||
|
# @return [Sketchup::Menu]
|
||||||
|
# @since 2.0.0
|
||||||
|
def self.menu( name )
|
||||||
|
if global_variables.include?( :$tt_menu ) && $tt_menu
|
||||||
|
$tt_menu
|
||||||
|
else
|
||||||
|
UI.menu( name )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
### NAMESPACE ### ------------------------------------------------------------
|
||||||
|
|
||||||
|
# Namespace for plugins to be wrapped into.
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# require 'TT_Lib2/core.rb'
|
||||||
|
# module TT::Plugins::FooBar
|
||||||
|
# ...
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Reserved for Thomas Thomassen.
|
||||||
|
#
|
||||||
|
# @since 2.0.0
|
||||||
|
module Plugins; end
|
||||||
|
|
||||||
|
|
||||||
|
### MACROS ### ---------------------------------------------------------------
|
||||||
|
|
||||||
|
# @param [Integer] number
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.even?(number)
|
||||||
|
number % 2 == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# @param [Integer] number
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.odd?(number)
|
||||||
|
number % 2 > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Format the given +time+ into a human readable string.
|
||||||
|
#
|
||||||
|
# @param [Numeric] time
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.format_time( time )
|
||||||
|
time = (time.finite?) ? time : 0.0
|
||||||
|
hours = (time / 3600).to_i
|
||||||
|
minutes = (time/60 - hours * 60).to_i
|
||||||
|
seconds = (time - (minutes * 60 + hours * 3600)).to_i
|
||||||
|
if hours > 0 && minutes > 0
|
||||||
|
"#{hours}h #{minutes}m #{seconds}s"
|
||||||
|
elsif minutes > 0
|
||||||
|
"#{minutes}m #{seconds}s"
|
||||||
|
else
|
||||||
|
"#{seconds}s"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the given square meters +area_meters+ in square inches.
|
||||||
|
#
|
||||||
|
# @param [Numeric] area_meters
|
||||||
|
#
|
||||||
|
# @return [Numeric]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.m2( area_meters )
|
||||||
|
ratio = 1.m ** 2
|
||||||
|
area_meters * ratio
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the given square inches +area_inches+ in square meters.
|
||||||
|
#
|
||||||
|
# @param [Numeric] area_inches
|
||||||
|
#
|
||||||
|
# @return [Numeric]
|
||||||
|
# @since 2.5.0
|
||||||
|
def self.to_m2( area_inches )
|
||||||
|
ratio = 1.0 / self.m2(1)
|
||||||
|
area_inches * ratio
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# @param [Object] object
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
# @since 2.6.0
|
||||||
|
def self.object_id_hex( object )
|
||||||
|
"0x%x" % (object.object_id << 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param [Array] array
|
||||||
|
#
|
||||||
|
# @return [Hash]
|
||||||
|
# @since 2.6.0
|
||||||
|
def self.array_to_hash( array )
|
||||||
|
h = {}
|
||||||
|
for key, value in array
|
||||||
|
h[ key ] = value
|
||||||
|
end
|
||||||
|
h
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
### ENVIRONMENT ###-----------------------------------------------------------
|
||||||
|
|
||||||
|
# Set up load paths.
|
||||||
|
#path = File.join( TT::Lib.path, 'libraries' )
|
||||||
|
#$LOAD_PATH << path unless $LOAD_PATH.include?( path )
|
||||||
|
|
||||||
|
end # module TT
|
||||||
|
end
|
||||||
|
|
||||||
|
if SpeckleConnector::TT::System.platform_supported?
|
||||||
|
|
||||||
|
# Check the integrity of the library.
|
||||||
|
SpeckleConnector::TT::Lib.integrity_check
|
||||||
|
#TT::Lib.virtualstore_check() # Disabled until a better guide can be made.
|
||||||
|
|
||||||
|
# Require remaining modules.
|
||||||
|
Dir.glob( File.join(SpeckleConnector::TT::Lib.path, '*.{rb}') ).each { |filename|
|
||||||
|
file = __FILE__.dup
|
||||||
|
file.force_encoding( "UTF-8" ) if file.respond_to?(:force_encoding)
|
||||||
|
unless File.basename( filename ) == File.basename( file )
|
||||||
|
relative_file = File.join( SpeckleConnector::TT::Lib.path, File.basename( filename ) )
|
||||||
|
require( relative_file )
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
# Disable the extension if it's not supported by the platform. This is done to
|
||||||
|
# avoid potential crashes when loading the binaries.
|
||||||
|
#if Sketchup.respond_to?(:extensions)
|
||||||
|
# extension = Sketchup.extensions[TT::Lib::PLUGIN_NAME]
|
||||||
|
# extension.uncheck
|
||||||
|
#end
|
||||||
|
# Alert the user that the extension is not compatible with the running system.
|
||||||
|
message = "#{SpeckleConnector::TT::Lib::PLUGIN_NAME} is not supported for this platform."
|
||||||
|
UI.messagebox(message)
|
||||||
|
|
||||||
|
end # if TT::System.platform_supported?
|
||||||
@@ -0,0 +1,269 @@
|
|||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Thomas Thomassen
|
||||||
|
# thomas[at]thomthom[dot]net
|
||||||
|
#
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require_relative 'core.rb'
|
||||||
|
|
||||||
|
# @since 2.4.0
|
||||||
|
module SpeckleConnector
|
||||||
|
module TT::Cursor
|
||||||
|
|
||||||
|
# Path to the cursor resources.
|
||||||
|
PATH = File.join( TT::Lib.path, 'cursors')
|
||||||
|
|
||||||
|
# Definitions of cursor resources.
|
||||||
|
# :symbol_id => ['filename.png', x, y]
|
||||||
|
@cursors = {
|
||||||
|
:default => 0,
|
||||||
|
:invalid => 663,
|
||||||
|
:hand => 671,
|
||||||
|
:hand_invalid => 918,
|
||||||
|
:link => 670,
|
||||||
|
:erase => 645,
|
||||||
|
:pencil => 632,
|
||||||
|
:freehand => 655,
|
||||||
|
:arc_1 => 629,
|
||||||
|
:arc_2 => 631,
|
||||||
|
:arc_3 => 630,
|
||||||
|
:man => 612,
|
||||||
|
:position_camera => 653,
|
||||||
|
:position_camera_3d => 902,
|
||||||
|
:walk => 420,
|
||||||
|
:walk_3d => 904,
|
||||||
|
:look_around => 418,
|
||||||
|
:look_around_3d => 903,
|
||||||
|
:orbit => 419,
|
||||||
|
:orbit_3d => 900,
|
||||||
|
:pan => 1003,
|
||||||
|
:pan_2d => 901,
|
||||||
|
:zoom => 421,
|
||||||
|
:zoom_region => 422,
|
||||||
|
:zoom_3d => 905,
|
||||||
|
:zoom_2d => 907,
|
||||||
|
:zoom_2d_region => 906,
|
||||||
|
:offset => 646,
|
||||||
|
:offset_invalid => 679,
|
||||||
|
:dropper => 651,
|
||||||
|
:dropper_texture => 652,
|
||||||
|
:dropper_invalid => ['dropper_invalid.png', 2, 29],
|
||||||
|
:paint => 681, # 647
|
||||||
|
:paint_same => 650,
|
||||||
|
:paint_object => 649,
|
||||||
|
:paint_connected => 648,
|
||||||
|
:paint_invalid => 680,
|
||||||
|
:text => 678,
|
||||||
|
:follow_me => 640,
|
||||||
|
:follow_me_invalid => 678,
|
||||||
|
:pushpull => 639,
|
||||||
|
:pushpull_add => 755,
|
||||||
|
:pushpull_invalid => 707,
|
||||||
|
:tape => 638,
|
||||||
|
:tape_add => 731,
|
||||||
|
:select => 633,
|
||||||
|
:select_add => 634,
|
||||||
|
:select_remove => 636,
|
||||||
|
:select_toggle => 635,
|
||||||
|
:select_step_1 => 924,
|
||||||
|
:select_step_2 => 925,
|
||||||
|
:select_invalid => 926,
|
||||||
|
:vertex => ['Vertex.png', 12, 19],
|
||||||
|
:vertex_add => ['Vertex_Add.png', 12, 19],
|
||||||
|
:vertex_remove => ['Vertex_Remove.png', 12, 19],
|
||||||
|
:vertex_toggle => ['Vertex_Toggle.png', 12, 19],
|
||||||
|
:rectangle => 637,
|
||||||
|
:move => 641,
|
||||||
|
:move_copy => 642,
|
||||||
|
:move_fold => 672,
|
||||||
|
:move_invalid => 673,
|
||||||
|
:position => 658,
|
||||||
|
:position_invalid => 673,
|
||||||
|
:scale => 736,
|
||||||
|
:scale_invalid => 730,
|
||||||
|
:scale_n_s => 659,
|
||||||
|
:scale_n_ne => 666,
|
||||||
|
:scale_ne => 661,
|
||||||
|
:scale_ne_e => 667,
|
||||||
|
:scale_w_e => 660,
|
||||||
|
:scale_n_nw => 665,
|
||||||
|
:scale_nw => 662,
|
||||||
|
:scale_nw_w => 664,
|
||||||
|
:rotate => 643,
|
||||||
|
:rotate_copy => 644,
|
||||||
|
:rotate_invalid => 713
|
||||||
|
}
|
||||||
|
|
||||||
|
# Creates cursor ids for the requested cursor +id+. Cursors are created on demand and
|
||||||
|
# reused to save resources.
|
||||||
|
#
|
||||||
|
# Valid +id+ arguments
|
||||||
|
# * +:default+
|
||||||
|
# * +:invalid+ (2.7.0)
|
||||||
|
# * +:hand+ (2.7.0)
|
||||||
|
# * +:hand_invalid+ (2.7.0)
|
||||||
|
# * +:link+ (2.7.0)
|
||||||
|
# * +:erase+ (2.7.0)
|
||||||
|
# * +:pencil+ (2.7.0)
|
||||||
|
# * +:freehand+ (2.7.0)
|
||||||
|
# * +:arc_1+ (2.7.0)
|
||||||
|
# * +:arc_2+ (2.7.0)
|
||||||
|
# * +:arc_3+ (2.7.0)
|
||||||
|
# * +:man+ (2.7.0)
|
||||||
|
# * +:position_camera_3d+ (2.7.0)
|
||||||
|
# * +:orbit+ (2.7.0)
|
||||||
|
# * +:orbit_3d+ (2.7.0)
|
||||||
|
# * +:pan_2d+ (2.7.0)
|
||||||
|
# * +:pan+ (2.7.0)
|
||||||
|
# * +:walk+ (2.7.0)
|
||||||
|
# * +:walk_3d+ (2.7.0)
|
||||||
|
# * +:look_around+ (2.7.0)
|
||||||
|
# * +:look_around_903+ (2.7.0)
|
||||||
|
# * +:zoom+ (2.7.0)
|
||||||
|
# * +:zoom_region+ (2.7.0)
|
||||||
|
# * +:zoom_3d+ (2.7.0)
|
||||||
|
# * +:zoom_2d+ (2.7.0)
|
||||||
|
# * +:zoom_2d_region+ (2.7.0)
|
||||||
|
# * +:offset+
|
||||||
|
# * +:offset_invalid+
|
||||||
|
# * +:dropper+
|
||||||
|
# * +:dropper_texture+ (2.7.0)
|
||||||
|
# * +:dropper_invalid+
|
||||||
|
# * +:paint+ (2.7.0)
|
||||||
|
# * +:paint_same+ (2.7.0)
|
||||||
|
# * +:paint_object+ (2.7.0)
|
||||||
|
# * +:paint_connected+ (2.7.0)
|
||||||
|
# * +:paint_invalid+ (2.7.0)
|
||||||
|
# * +:text+ (2.7.0)
|
||||||
|
# * +:follow+ (2.7.0)
|
||||||
|
# * +:follow_me+ (2.7.0)
|
||||||
|
# * +:pushpull+ (2.7.0)
|
||||||
|
# * +:pushpull_add+ (2.7.0)
|
||||||
|
# * +:pushpull_invalid+ (2.7.0)
|
||||||
|
# * +:tape+ (2.7.0)
|
||||||
|
# * +:tape_add+ (2.7.0)
|
||||||
|
# * +:select+
|
||||||
|
# * +:select_add+
|
||||||
|
# * +:select_remove+
|
||||||
|
# * +:select_toggle+
|
||||||
|
# * +:select_step_1+ (2.7.0)
|
||||||
|
# * +:select_step_2+ (2.7.0)
|
||||||
|
# * +:select_invalid+ (2.7.0)
|
||||||
|
# * +:vertex+ (2.5.0)
|
||||||
|
# * +:vertex_add+ (2.5.0)
|
||||||
|
# * +:vertex_remove+ (2.5.0)
|
||||||
|
# * +:vertex_toggle+ (2.5.0)
|
||||||
|
# * +:rectangle+ (2.6.0)
|
||||||
|
# * +:move+ (2.6.0)
|
||||||
|
# * +:move_copy+ (2.7.0)
|
||||||
|
# * +:move_fold+ (2.7.0)
|
||||||
|
# * +:move_invalid+ (2.7.0)
|
||||||
|
# * +:position+ (2.7.0)
|
||||||
|
# * +:position_invalid+ (2.7.0)
|
||||||
|
# * +:rotate+ (2.6.0)
|
||||||
|
# * +:rotate_copy+ (2.6.0)
|
||||||
|
# * +:rotate_invalid+ (2.7.0)
|
||||||
|
# * +:scale+ (2.6.0)
|
||||||
|
# * +:scale_invalid+ (2.7.0)
|
||||||
|
# * +:scale_n_s+ (2.7.0)
|
||||||
|
# * +:scale_n_ne+ (2.7.0)
|
||||||
|
# * +:scale_ne+ (2.7.0)
|
||||||
|
# * +:scale_ne_e+ (2.7.0)
|
||||||
|
# * +:scale_w_e+ (2.7.0)
|
||||||
|
# * +:scale_n_nw+ (2.7.0)
|
||||||
|
# * +:scale_nw+ (2.7.0)
|
||||||
|
# * +:scale_nw_w+ (2.7.0)
|
||||||
|
#
|
||||||
|
# @param [Symbol] id
|
||||||
|
#
|
||||||
|
# @return [Integer, nil] +Integer+ of a cursor resource uon success, +nil+ upon failure.
|
||||||
|
# @since 2.4.0
|
||||||
|
def self.get_id(id)
|
||||||
|
return nil unless @cursors.key?(id)
|
||||||
|
# Load cursors on demand
|
||||||
|
if @cursors[id].is_a?(Array)
|
||||||
|
cursor_file, x, y = @cursors[id]
|
||||||
|
filename = File.join( TT::Cursor::PATH, cursor_file )
|
||||||
|
@cursors[id] = UI.create_cursor( filename, x, y )
|
||||||
|
end
|
||||||
|
return @cursors[id]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a cursor ID to a scaling direction cursor based on a 2D vector in
|
||||||
|
# screen space.
|
||||||
|
#
|
||||||
|
# @param [Geom::Vector3d] screen_vector
|
||||||
|
# @param [Sketchup::View] view
|
||||||
|
#
|
||||||
|
# @return [Integer, nil] +Integer+ of a cursor resource uon success, +nil+ upon failure.
|
||||||
|
# @since 2.7.0
|
||||||
|
def self.get_vector2d_cursor( screen_vector, view )
|
||||||
|
cursors = self.scale_handles
|
||||||
|
cursor_id = nil
|
||||||
|
nearest_angle = nil
|
||||||
|
for vector, cursor in cursors
|
||||||
|
a1 = vector.angle_between( screen_vector ).abs
|
||||||
|
a2 = vector.angle_between( screen_vector.reverse ).abs
|
||||||
|
angle = [ a1, a2 ].min
|
||||||
|
if nearest_angle.nil? || angle < nearest_angle
|
||||||
|
nearest_angle = angle
|
||||||
|
cursor_id = cursor
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cursor_id
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a cursor ID to a scaling direction cursor based on a 3D vector in
|
||||||
|
# model space.
|
||||||
|
#
|
||||||
|
# @param [Geom::Vector3d] vector
|
||||||
|
# @param [Sketchup::View] view
|
||||||
|
#
|
||||||
|
# @return [Integer, nil] +Integer+ of a cursor resource uon success, +nil+ upon failure.
|
||||||
|
# @since 2.7.0
|
||||||
|
def self.get_vector3d_cursor( vector, view )
|
||||||
|
pt1 = ORIGIN
|
||||||
|
pt2 = ORIGIN.offset( vector )
|
||||||
|
spt1 = view.screen_coords( pt1 )
|
||||||
|
spt2 = view.screen_coords( pt2 )
|
||||||
|
spt1.z = 0
|
||||||
|
spt2.z = 0
|
||||||
|
screen_vector = spt1.vector_to( spt2 )
|
||||||
|
self.get_vector2d_cursor( screen_vector, view )
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [Hash]
|
||||||
|
# @since 2.7.0
|
||||||
|
def self.scale_handles
|
||||||
|
@scale_handles ||= self.compute_scale_handles
|
||||||
|
@scale_handles
|
||||||
|
end
|
||||||
|
|
||||||
|
# @private
|
||||||
|
#
|
||||||
|
# @return [Hash]
|
||||||
|
# @since 2.7.0
|
||||||
|
def self.compute_scale_handles
|
||||||
|
cursor_ids = [
|
||||||
|
TT::Cursor.get_id( :scale_nw_w ),
|
||||||
|
TT::Cursor.get_id( :scale_nw ),
|
||||||
|
TT::Cursor.get_id( :scale_n_nw ),
|
||||||
|
TT::Cursor.get_id( :scale_n_s ),
|
||||||
|
TT::Cursor.get_id( :scale_n_ne ),
|
||||||
|
TT::Cursor.get_id( :scale_ne ),
|
||||||
|
TT::Cursor.get_id( :scale_ne_e ),
|
||||||
|
TT::Cursor.get_id( :scale_w_e )
|
||||||
|
].reverse
|
||||||
|
cursors = {}
|
||||||
|
angle = ( 180.0 / cursor_ids.size ).degrees
|
||||||
|
cursor_ids.each_with_index { |id, index|
|
||||||
|
tr = Geom::Transformation.rotation( ORIGIN, Z_AXIS, -angle * index )
|
||||||
|
vector = X_AXIS.transform( tr )
|
||||||
|
cursors[ vector ] = id
|
||||||
|
}
|
||||||
|
cursors
|
||||||
|
end
|
||||||
|
|
||||||
|
end # module TT::Cursor
|
||||||
|
end
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user